package org.simantics.scl.compiler.elaboration.expressions; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.contexts.TypingContext; import org.simantics.scl.compiler.elaboration.query.QExists; import org.simantics.scl.compiler.elaboration.query.Query; import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext; import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationMode; import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.exceptions.MatchException; import org.simantics.scl.compiler.types.exceptions.UnificationException; import org.simantics.scl.compiler.types.kinds.Kinds; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.TIntHashSet; public class EWhen extends SimplifiableExpression { public Query query; public Expression action; Variable[] variables; public EWhen(Query query, Expression action) { this.query = query; this.action = action; } public EWhen(long location, Query query, Expression action, Variable[] variables) { if(variables == null) throw new NullPointerException(); if(location == Locations.NO_LOCATION) new Exception().printStackTrace(); this.location = location; this.query = query; this.action = action; this.variables = variables; } @Override public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { query.collectRefs(allRefs, refs); action.collectRefs(allRefs, refs); } @Override public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { query.collectVars(allVars, vars); action.collectVars(allVars, vars); } @Override public void collectEffects(THashSet effects) { throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support collectEffects."); } @Override protected void updateType() throws MatchException { setType(Types.UNIT); } @Override public Expression checkBasicType(TypingContext context, Type requiredType) { try { Types.unify(requiredType, Types.UNIT); } catch (UnificationException e) { context.typeError(location, requiredType, Types.UNIT); return this; } for(Variable variable : variables) variable.setType(Types.metaVar(Kinds.STAR)); query.checkType(context); action.checkIgnoredType(context); // Compile query return compile(context); } public Expression compile(TypingContext context) { try { QueryCompilationContext queryCompilationContext = new QueryCompilationContext(context, QueryCompilationMode.ITERATE, null, action); new QExists(variables, query).generate(queryCompilationContext); return queryCompilationContext.getContinuation(); } catch(UnsolvableQueryException e) { context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage()); return new EError(getLocation()); } } @Override public void collectFreeVariables(THashSet vars) { action.collectFreeVariables(vars); query.collectFreeVariables(vars); for(Variable var : variables) vars.remove(var); } @Override public Expression resolve(TranslationContext context) { context.pushExistentialFrame(); query = query.resolve(context); action = action.resolve(context); variables = context.popExistentialFrame(); return this; } @Override public Expression decorate(ExpressionDecorator decorator) { return decorator.decorate(this); } @Override public Expression replace(ReplaceContext context) { Variable[] newVariables = new Variable[variables.length]; for(int i=0;i