X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Felaboration%2Fexpressions%2FExpression.java;h=427acbd19b9dbbdd082df33f7c8ca97b0792d3ed;hp=e01098c12df762eb3e32c43caaff6baaee3f36c6;hb=666ee533a3cfa9f59e79215a269f8342227cdbda;hpb=c125a1755cc7c4a6241c3c5bf841c3db0ff2d658 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java old mode 100755 new mode 100644 index e01098c12..427acbd19 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java @@ -1,379 +1,401 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; - -import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; -import org.simantics.scl.compiler.common.precedence.Precedence; -import org.simantics.scl.compiler.constants.NoRepConstant; -import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext; -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.errors.NotPatternException; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; -import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; -import org.simantics.scl.compiler.elaboration.query.QAtom; -import org.simantics.scl.compiler.elaboration.relations.SCLRelation; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.interpreted.IExpression; -import org.simantics.scl.compiler.internal.parsing.Symbol; -import org.simantics.scl.compiler.top.ExpressionInterpretationContext; -import org.simantics.scl.compiler.types.TForAll; -import org.simantics.scl.compiler.types.TFun; -import org.simantics.scl.compiler.types.TPred; -import org.simantics.scl.compiler.types.TVar; -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.kinds.Kinds; -import org.simantics.scl.compiler.types.util.Typed; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public abstract class Expression extends Symbol implements Typed { - public static final Expression[] EMPTY_ARRAY = new Expression[0]; - - transient - private Type type; - - public Expression() { - } - - public Expression(long loc) { - this.location = loc; - } - - @Override - public Type getType() { - if(type == null) { - try { - updateType(); - } catch (MatchException e) { - throw new InternalCompilerError(e); - } - if(type == null) - throw new InternalCompilerError(getClass().getSimpleName() + - ".updateType couldn't compute its type."); - } - return type; - } - - public void setType(Type type) { - if(type == null) - throw new NullPointerException(); - this.type = type; - } - - /** - * Infers the type of the expression without any context. Adds type - * applications and lambdas if needed. - */ - public Expression inferType(TypingContext context) { - return checkBasicType(context, Types.metaVar(Kinds.STAR)); - } - - public Expression checkBasicType(TypingContext context, Type requiredType) { - return context.subsume(inferType(context), requiredType); - } - - protected Expression applyPUnit(EnvironmentalContext context) { - Type type = Types.canonical(getType()); - if(type instanceof TFun) { - TFun fun = (TFun)type; - if(fun.getCanonicalDomain() == Types.PUNIT) { - EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT)); - result.effect = fun.getCanonicalEffect(); - return result; - } - } - return this; - } - - public Expression checkIgnoredType(TypingContext context) { - Expression expression = inferType(context); - if(Types.canonical(expression.getType()) != Types.UNIT) - expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT)); - return expression; - } - - /** - * Checks the type of the expression against the given type. Adds type - * applications and lambdas if needed. - */ - public final Expression checkType(TypingContext context, Type requiredType) { - //System.out.println("checkType: " + this + " :: " + requiredType); - if(!context.isInPattern()) { - requiredType = Types.canonical(requiredType); - if(requiredType instanceof TForAll) { - TForAll forAll = (TForAll)requiredType; - TVar var = forAll.var; - TVar newVar = Types.var(var.getKind()); - requiredType = Types.canonical(forAll.type).replace(var, newVar); - return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType)); - } - while(requiredType instanceof TFun) { - TFun fun = (TFun)requiredType; - if(fun.domain instanceof TPred) { // No need to canonicalize - ArrayList constraints = new ArrayList(2); - while(true) { - constraints.add(new Variable("constraint", fun.domain)); - requiredType = Types.canonical(fun.range); - if(!(requiredType instanceof TFun)) - break; - fun = (TFun)requiredType; - if(!(fun.domain instanceof TPred)) - break; - } - context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()])); - Expression expression = checkType(context, requiredType); - context.popConstraintFrame(); - for(int i=constraints.size()-1;i>=0;--i) - expression = new ESimpleLambda(constraints.get(i), expression); - return expression; - } - else if(fun.domain == Types.PUNIT) { - context.pushEffectUpperBound(location, fun.effect); - Expression expr = checkType(context, fun.range); - context.popEffectUpperBound(); - - // Wrap - Variable var = new Variable("punit", Types.PUNIT); - return new ESimpleLambda(location, var, fun.effect, expr); - } - else - break; - } - } - return checkBasicType(context, requiredType); - } - - public abstract void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs); - public abstract void collectVars(TObjectIntHashMap allVars, TIntHashSet vars); - public abstract void forVariables(VariableProcedure procedure); - - public Expression decomposeMatching() { - return this; - } - - public String toString() { - StringBuilder b = new StringBuilder(); - ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); - accept(visitor); - return b.toString(); - } - - protected abstract void updateType() throws MatchException; - - public static class TypeValidationException extends Exception { - private static final long serialVersionUID = 3181298127162041248L; - - long loc; - - public TypeValidationException(long loc) { - this.loc = loc; - } - - public long getLoc() { - return loc; - } - - public TypeValidationException(long loc, Throwable cause) { - super(cause); - this.loc = loc; - } - } - - public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException { - if(!Types.equals(a, b)) - throw new TypeValidationException(loc); - } - - public abstract IVal toVal(Environment env, CodeWriter w); - - public Expression closure(TVar ... vars) { - if(vars.length == 0) - return this; - return new ELambdaType(vars, this); - } - - public abstract void collectFreeVariables(THashSet vars); - - public Expression simplify(SimplificationContext context) { - throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method."); - } - - public abstract Expression resolve(TranslationContext context); - - /** - * Returns head of the pattern. - */ - public EVar getPatternHead() throws NotPatternException { - throw new NotPatternException(this); - } - - public LhsType getLhsType() throws NotPatternException { - throw new NotPatternException(this); - } - - protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException { - throw new NotPatternException(this); - } - - public void getParameters(TranslationContext translationContext, - ArrayList parameters) { - throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters."); - } - - public Expression resolveAsPattern(TranslationContext context) { - context.getErrorLog().log(location, "Pattern was expected here."); - return new EError(); - } - - public void removeFreeVariables(THashSet vars) { - throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern."); - } - - public Expression checkTypeAsPattern(TypingContext context, Type requiredType) { - if(context.isInPattern()) - throw new InternalCompilerError("Already in a pattern."); - context.setInPattern(true); - Expression expression = checkType(context, requiredType); - context.setInPattern(false); - return expression; - } - - public THashSet getFreeVariables() { - THashSet result = new THashSet(); - collectFreeVariables(result); - return result; - } - - public static Expression[] concat(Expression[] a, Expression[] b) { - if(a.length == 0) - return b; - if(b.length == 0) - return a; - Expression[] result = new Expression[a.length + b.length]; - for(int i=0;i effects); - - public Type getEffect() { - THashSet effects = new THashSet(); - collectEffects(effects); - return Types.union(effects.toArray(new Type[effects.size()])); - } - - public abstract void accept(ExpressionVisitor visitor); - - public void collectRelationRefs( - final TObjectIntHashMap allRefs, final TIntHashSet refs) { - accept(new StandardExpressionVisitor() { - @Override - public void visit(QAtom query) { - int id = allRefs.get(query.relation); - if(id >= 0) - refs.add(id); - } - }); - } - - public boolean isFunctionDefinitionLhs() { - return false; - } - - public Precedence getPrecedence() { - return Precedence.DEFAULT; - } - - public boolean isPattern(int arity) { - return false; - } - - public abstract Expression accept(ExpressionTransformer transformer); -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; +import java.util.Set; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.common.precedence.Precedence; +import org.simantics.scl.compiler.compilation.CompilationContext; +import org.simantics.scl.compiler.constants.NoRepConstant; +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.errors.NotPatternException; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; +import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectEffectsVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectFreeVariablesVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectRefsVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectVarsVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.ForVariablesUsesVisitor; +import org.simantics.scl.compiler.elaboration.expressions.visitors.StandardExpressionVisitor; +import org.simantics.scl.compiler.elaboration.query.QAtom; +import org.simantics.scl.compiler.elaboration.relations.SCLRelation; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.internal.parsing.Symbol; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.types.TForAll; +import org.simantics.scl.compiler.types.TFun; +import org.simantics.scl.compiler.types.TPred; +import org.simantics.scl.compiler.types.TVar; +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.kinds.Kinds; +import org.simantics.scl.compiler.types.util.Typed; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.TIntHashSet; + +public abstract class Expression extends Symbol implements Typed { + public static final Expression[] EMPTY_ARRAY = new Expression[0]; + + transient + private Type type; + + public Expression() { + } + + public Expression(long loc) { + this.location = loc; + } + + @Override + public Type getType() { + if(type == null) { + try { + updateType(); + } catch (MatchException e) { + throw new InternalCompilerError(e); + } + if(type == null) + throw new InternalCompilerError(getClass().getSimpleName() + + ".updateType couldn't compute its type."); + } + return type; + } + + public void setType(Type type) { + if(type == null) + throw new NullPointerException(); + this.type = type; + } + + /** + * Infers the type of the expression without any context. Adds type + * applications and lambdas if needed. + */ + public Expression inferType(TypingContext context) { + return checkBasicType(context, Types.metaVar(Kinds.STAR)); + } + + public Expression checkBasicType(TypingContext context, Type requiredType) { + return context.subsume(inferType(context), requiredType); + } + + protected Expression applyPUnit(TypingContext context) { + Type type = Types.canonical(getType()); + if(type instanceof TFun) { + TFun fun = (TFun)type; + if(fun.getCanonicalDomain() == Types.PUNIT) { + EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT)); + result.effect = fun.getCanonicalEffect(); + context.declareEffect(this.location, result.effect); + return result; + } + } + return this; + } + + public Expression checkIgnoredType(TypingContext context) { + Expression expression = inferType(context); + if(Types.canonical(expression.getType()) != Types.UNIT) + expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT)); + return expression; + } + + /** + * Checks the type of the expression against the given type. Adds type + * applications and lambdas if needed. + */ + public final Expression checkType(TypingContext context, Type requiredType) { + //System.out.println("checkType: " + this + " :: " + requiredType); + if(!context.isInPattern()) { + requiredType = Types.canonical(requiredType); + if(requiredType instanceof TForAll) { + TForAll forAll = (TForAll)requiredType; + TVar var = forAll.var; + TVar newVar = Types.var(var.getKind()); + requiredType = Types.canonical(forAll.type).replace(var, newVar); + return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType)); + } + while(requiredType instanceof TFun) { + TFun fun = (TFun)requiredType; + if(fun.domain instanceof TPred) { // No need to canonicalize + ArrayList constraints = new ArrayList(2); + while(true) { + constraints.add(new Variable("constraint", fun.domain)); + requiredType = Types.canonical(fun.range); + if(!(requiredType instanceof TFun)) + break; + fun = (TFun)requiredType; + if(!(fun.domain instanceof TPred)) + break; + } + context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()])); + Expression expression = checkType(context, requiredType); + context.popConstraintFrame(); + for(int i=constraints.size()-1;i>=0;--i) + expression = new ESimpleLambda(constraints.get(i), expression); + return expression; + } + else if(fun.domain == Types.PUNIT) { + context.pushEffectUpperBound(location, fun.effect); + Expression expr = checkType(context, fun.range); + context.popEffectUpperBound(); + + // Wrap + Variable var = new Variable("punit", Types.PUNIT); + return new ESimpleLambda(location, var, fun.effect, expr); + } + else + break; + } + } + return checkBasicType(context, requiredType); + } + + public final void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + accept(new CollectRefsVisitor(allRefs, refs)); + } + + public final void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { + accept(new CollectVarsVisitor(allVars, vars)); + } + + public final void forVariableUses(VariableProcedure procedure) { + accept(new ForVariablesUsesVisitor(procedure)); + } + + public Expression decomposeMatching() { + return this; + } + + public String toString() { + StringBuilder b = new StringBuilder(); + ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); + accept(visitor); + return b.toString(); + } + + protected abstract void updateType() throws MatchException; + + public static class TypeValidationException extends Exception { + private static final long serialVersionUID = 3181298127162041248L; + + long loc; + + public TypeValidationException(long loc) { + this.loc = loc; + } + + public long getLoc() { + return loc; + } + + public TypeValidationException(long loc, Throwable cause) { + super(cause); + this.loc = loc; + } + } + + public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException { + if(!Types.equals(a, b)) + throw new TypeValidationException(loc); + } + + public abstract IVal toVal(CompilationContext context, CodeWriter w); + + public Expression closure(TVar ... vars) { + if(vars.length == 0) + return this; + return new ELambdaType(vars, this); + } + + public Expression simplify(SimplificationContext context) { + System.out.println("#############################"); + System.out.println(this); + throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method."); + } + + public abstract Expression resolve(TranslationContext context); + + /** + * Returns head of the pattern. + */ + public EVar getPatternHead() throws NotPatternException { + throw new NotPatternException(this); + } + + public LhsType getLhsType() throws NotPatternException { + throw new NotPatternException(this); + } + + protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException { + throw new NotPatternException(this); + } + + public void getParameters(TranslationContext translationContext, + ArrayList parameters) { + throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters."); + } + + public Expression resolveAsPattern(TranslationContext context) { + context.getErrorLog().log(location, "Pattern was expected here."); + return new EError(); + } + + public Expression checkTypeAsPattern(TypingContext context, Type requiredType) { + if(context.isInPattern()) + throw new InternalCompilerError("Already in a pattern."); + context.setInPattern(true); + Expression expression = checkType(context, requiredType); + context.setInPattern(false); + return expression; + } + + /** + * Used during simplification and in toIExpression + */ + public Set getFreeVariables() { + CollectFreeVariablesVisitor visitor = new CollectFreeVariablesVisitor(); + accept(visitor); + return visitor.getFreeVariables(); + } + + public static Expression[] concat(Expression[] a, Expression[] b) { + if(a.length == 0) + return b; + if(b.length == 0) + return a; + Expression[] result = new Expression[a.length + b.length]; + for(int i=0;i allRefs, final TIntHashSet refs) { + accept(new StandardExpressionVisitor() { + @Override + public void visit(QAtom query) { + int id = allRefs.get(query.relation); + if(id >= 0) + refs.add(id); + } + }); + } + + public boolean isFunctionDefinitionLhs() { + return false; + } + + public Precedence getPrecedence() { + return Precedence.DEFAULT; + } + + public boolean isPattern(int arity) { + return false; + } + + public abstract Expression accept(ExpressionTransformer transformer); + + // TODO implement for all expressions + public boolean equalsExpression(Expression expression) { + return false; + } + + /** + * This method returns a lower bound for the function arity of the value this expression defines. + * The lower bound is calculated purely looking the syntax of the expression, not the + * types of the constants and variables the expression refers to. + */ + public int getSyntacticFunctionArity() { + return 0; + } +}