X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Felaboration%2Fquery%2Fcompilation%2FQueryCompilationContext.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Felaboration%2Fquery%2Fcompilation%2FQueryCompilationContext.java;h=f0f5b12271678932bf10908aee2ea1ca94870927;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/compilation/QueryCompilationContext.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/compilation/QueryCompilationContext.java new file mode 100644 index 000000000..f0f5b1227 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/compilation/QueryCompilationContext.java @@ -0,0 +1,323 @@ +package org.simantics.scl.compiler.elaboration.query.compilation; + +import static org.simantics.scl.compiler.elaboration.expressions.Expressions.Just; +import static org.simantics.scl.compiler.elaboration.expressions.Expressions.Nothing; +import static org.simantics.scl.compiler.elaboration.expressions.Expressions.apply; +import static org.simantics.scl.compiler.elaboration.expressions.Expressions.lambda; +import static org.simantics.scl.compiler.elaboration.expressions.Expressions.var; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.common.names.Name; +import org.simantics.scl.compiler.constants.BooleanConstant; +import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.elaboration.expressions.Case; +import org.simantics.scl.compiler.elaboration.expressions.EApply; +import org.simantics.scl.compiler.elaboration.expressions.EConstant; +import org.simantics.scl.compiler.elaboration.expressions.EIf; +import org.simantics.scl.compiler.elaboration.expressions.ELiteral; +import org.simantics.scl.compiler.elaboration.expressions.EMatch; +import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda; +import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet; +import org.simantics.scl.compiler.elaboration.expressions.EVariable; +import org.simantics.scl.compiler.elaboration.expressions.Expression; +import org.simantics.scl.compiler.elaboration.expressions.Variable; +import org.simantics.scl.compiler.elaboration.java.Builtins; +import org.simantics.scl.compiler.elaboration.modules.SCLValue; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.types.TPred; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; + +public class QueryCompilationContext implements EnvironmentalContext { + private static final Name EQUALS = Name.create("Prelude", "=="); + + TypingContext context; + QueryCompilationMode mode; + Type resultType; + Expression continuation; + double branching = 1.0; + double cost = 0.0; + + public QueryCompilationContext( + TypingContext context, + QueryCompilationMode mode, + Type resultType, + Expression continuation) { + this.context = context; + this.mode = mode; + this.resultType = resultType; + this.continuation = continuation; + } + + public Expression failure() { + switch(mode) { + case ITERATE: return new EConstant(Builtins.TUPLE_CONSTRUCTORS[0]); + case GET_FIRST: return new EConstant(Builtins.Nothing, resultType); + case GET_ALL: return new EConstant(Builtins.LIST_CONSTRUCTORS[0], resultType); + case CHECK: return new ELiteral(new BooleanConstant(false)); + default: throw new InternalCompilerError(); + } + } + + public Expression disjunction(Expression a, Expression b) { + switch(mode) { + case ITERATE: return new ESimpleLet(new Variable("_", Types.UNIT), a, b); + case GET_FIRST: { + Variable var = new Variable("temp", a.getType()); + return new EMatch(a, + new Case(new EConstant(Builtins.Nothing), b), + new Case(new EVariable(var), new EVariable(var))); + } + case GET_ALL: { + try { + return new EApply(context.getConstant(Name.create("Prelude", "appendList"), + Types.matchApply(Types.LIST, a.getType())), a, b); + } catch (MatchException e) { + throw new InternalCompilerError(); + } + } + case CHECK: return new EIf(a, new ELiteral(new BooleanConstant(true)), b); + default: throw new InternalCompilerError(); + } + } + + public Expression condition(Expression condition, Expression continuation) { + return new EIf(condition, continuation, failure()); + } + + public void condition(Expression condition) { + continuation = condition(condition, continuation); + } + + public void equalityCondition(long location, Expression a, Expression b) { + Type type = a.getType(); + condition(new EApply( + location, + Types.PROC, + context.getConstant(EQUALS, type), + new Expression[] { + getEvidence(location, Types.pred(Types.EQ, type)), + a, + b + } + )); + } + + public void let(Variable variable, Expression value) { + continuation = new ESimpleLet(variable, value, continuation); + } + + public void iterateMaybe(Variable variable, Expression value) { + continuation = new EMatch(value, + new Case(Nothing(variable.getType()), failure()), + new Case(Just(var(variable)), continuation)); + } + + public void match(Expression pattern, Expression value, boolean mayFail) { + if(mayFail) + continuation = new EMatch(value, + new Case(pattern, continuation), + new Case(new EVariable(new Variable("_", pattern.getType())), failure())); + else + continuation = new EMatch(value, + new Case(pattern, continuation)); + } + + public void iterateList(Variable variable, Expression list) { + try { + switch(mode) { + case ITERATE: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Prelude", "iterList"), variable.getType(), Types.PROC, Types.tupleConstructor(0)), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + list + } + ); + break; + case CHECK: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Prelude", "any"), variable.getType(), Types.PROC), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + list + } + ); + break; + case GET_ALL: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Prelude", "concatMap"), variable.getType(), Types.PROC, + Types.matchApply(Types.LIST, continuation.getType())), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + list + } + ); + break; + case GET_FIRST: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Prelude", "mapFirst"), variable.getType(), Types.PROC, + Types.matchApply(Types.MAYBE, continuation.getType())), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + list + } + ); + break; + default: throw new InternalCompilerError("iterateList could not handle mode " + mode); + } + } catch(MatchException e) { + throw new InternalCompilerError(e); + } + } + + public void iterateVector(Variable variable, Expression vector) { + try { + switch(mode) { + case ITERATE: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Vector", "iterVector"), variable.getType(), Types.PROC, continuation.getType()), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + vector + } + ); + break; + case CHECK: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Vector", "anyVector"), variable.getType(), Types.PROC), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + vector + } + ); + break; + case GET_ALL: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Vector", "concatMapVector"), variable.getType(), Types.PROC, + Types.matchApply(Types.LIST, continuation.getType())), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + vector + } + ); + break; + case GET_FIRST: + continuation = new EApply( + Locations.NO_LOCATION, + Types.PROC, + context.getConstant(Name.create("Vector", "mapFirstVector"), variable.getType(), Types.PROC, + Types.matchApply(Types.MAYBE, continuation.getType())), + new Expression[] { + new ESimpleLambda(Types.PROC, variable, continuation), + vector + } + ); + break; + default: throw new InternalCompilerError("iterateVector could not handle mode " + mode); + } + } catch(MatchException e) { + throw new InternalCompilerError(e); + } + } + + private static final Name MSet_iter = Name.create("MSet", "iter"); + private static final Name MSet_mapFirst = Name.create("MSet", "mapFirst"); + + public void iterateMSet(Variable variable, Expression set) { + try { + switch(mode) { + case ITERATE: + continuation = apply(context, Types.PROC, MSet_iter, variable.getType(), Types.PROC, continuation.getType(), + lambda(Types.PROC, variable, continuation), + set + ); + break; + case GET_FIRST: + continuation = apply(context, Types.PROC, MSet_mapFirst, variable.getType(), Types.PROC, + Types.matchApply(Types.MAYBE, continuation.getType()), + lambda(Types.PROC, variable, continuation), + set + ); + break; + default: throw new InternalCompilerError("iterateMSet could not handle mode " + mode); + } + } catch(MatchException e) { + throw new InternalCompilerError(e); + } + } + + public void updateCost(double localBranching, double localCost) { + branching *= localBranching; + cost *= localBranching; + cost += localCost; + } + + public Expression getConstant(Name name, Type[] typeParameters) { + return context.getConstant(name, typeParameters); + } + + public QueryCompilationContext createCheckContext() { + return new QueryCompilationContext(context, QueryCompilationMode.CHECK, + null, new ELiteral(new BooleanConstant(true))); + } + + public double getBranching() { + return branching; + } + + public double getCost() { + return cost; + } + + public QueryCompilationContext createSubcontext(Expression innerExpression) { + return new QueryCompilationContext(context, mode, resultType, innerExpression); + } + + public void setContinuation(Expression continuation) { + this.continuation = continuation; + } + + public Expression getContinuation() { + return continuation; + } + + public Expression disjunction(Expression[] disjuncts) { + Expression result = failure(); + for(int i=disjuncts.length-1;i>=0;--i) + result = disjunction(disjuncts[i], result); + return result; + } + + public TypingContext getTypingContext() { + return context; + } + + public EVariable getEvidence(long location, TPred pred) { + EVariable evidence = new EVariable(location, null); + evidence.setType(pred); + context.addConstraintDemand(evidence); + return evidence; + } + + @Override + public SCLValue getValue(Name name) { + return context.getValue(name); + } +}