]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QAtom.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / query / QAtom.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QAtom.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QAtom.java
new file mode 100644 (file)
index 0000000..9576051
--- /dev/null
@@ -0,0 +1,275 @@
+package org.simantics.scl.compiler.elaboration.query;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TIntObjectHashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+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.QueryTransformer;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
+import org.simantics.scl.compiler.elaboration.java.EqRelation;
+import org.simantics.scl.compiler.elaboration.query.compilation.ConstraintCollectionContext;
+import org.simantics.scl.compiler.elaboration.query.compilation.DerivateException;
+import org.simantics.scl.compiler.elaboration.query.compilation.EnforcingContext;
+import org.simantics.scl.compiler.elaboration.query.compilation.ExpressionConstraint;
+import org.simantics.scl.compiler.elaboration.query.compilation.RelationConstraint;
+import org.simantics.scl.compiler.elaboration.relations.CompositeRelation;
+import org.simantics.scl.compiler.elaboration.relations.LocalRelation;
+import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public class QAtom extends Query {
+    public SCLRelation relation;
+    public Type[] typeParameters;
+    public Expression[] parameters;
+    
+    public QAtom(SCLRelation relation, Expression ... parameters) {
+        this.relation = relation;
+        this.parameters = parameters;
+    }
+    
+    public QAtom(SCLRelation relation, Type[] typeParameters, Expression ... parameters) {
+        this.relation = relation;
+        this.typeParameters = typeParameters;
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void collectFreeVariables(THashSet<Variable> vars) {
+        for(Expression parameter : parameters)
+            parameter.collectFreeVariables(vars);
+    }
+    
+    @Override
+    public void checkType(TypingContext context) {
+        // Type parameters
+        TVar[] typeVariables = relation.getTypeVariables();
+        typeParameters = new Type[typeVariables.length];
+        for(int i=0;i<typeVariables.length;++i)
+            typeParameters[i] = Types.metaVar(typeVariables[i].getKind());
+        
+        // Check parameter types
+        Type[] parameterTypes = relation.getParameterTypes();
+        if(parameterTypes.length != parameters.length)
+            context.getErrorLog().log(location, "Relation is applied with wrong number of parameters.");
+        else
+            for(int i=0;i<parameters.length;++i)
+                parameters[i] = parameters[i]
+                        .checkType(context, parameterTypes[i].replace(typeVariables, typeParameters));
+    }
+    
+    public Expression generateEnforce(EnforcingContext context) {
+        Variable[] variables = new Variable[parameters.length];
+        for(int i=0;i<variables.length;++i)
+            if(parameters[i] instanceof EVariable)
+                variables[i] = ((EVariable)parameters[i]).getVariable();
+            else
+                variables[i] = new Variable("p" + i, parameters[i].getType());
+        Expression result = relation.generateEnforce(location, context, typeParameters, variables);
+        for(int i=variables.length-1;i>=0;--i)
+            if(!(parameters[i] instanceof EVariable))
+                result = new ESimpleLet(
+                        variables[i],
+                        parameters[i],
+                        result
+                        );
+        return result;
+    }
+
+    private static class VariableMaskProcedure implements VariableProcedure {
+        ConstraintCollectionContext context;
+        long requiredVariablesMask = 0L;
+        
+        public VariableMaskProcedure(ConstraintCollectionContext context) {
+            this.context = context;
+        }
+
+        @Override
+        public void execute(long location, Variable variable) {
+            int id = context.getVariableMap().get(variable);
+            if(id >= 0)
+                requiredVariablesMask |= 1L << id;
+        }
+    }
+    
+    @Override
+    public void collectConstraints(ConstraintCollectionContext context) {
+        try {
+            // Analyze parameters and find required and optional variables
+            VariableMaskProcedure procedure = new VariableMaskProcedure(context);
+            int[] optionalVariableByParameter = new int[parameters.length];
+            Variable[] varParameters = new Variable[parameters.length];
+            for(int i=0;i<parameters.length;++i) {
+                Expression parameter = parameters[i];
+                if(parameter instanceof EVariable) {
+                    Variable variable = ((EVariable)parameter).getVariable();
+                    optionalVariableByParameter[i] = context.getVariableMap().get(variable);
+                    varParameters[i] = variable;
+                }
+                else {
+                    Variable temp = new Variable("temp", parameter.getType());
+                    varParameters[i] = temp;
+                    if(parameter.isPattern(0)) {
+                        int tempId = context.addVariable(temp);
+                        context.addConstraint(new ExpressionConstraint(context, temp, parameter, true));
+                        optionalVariableByParameter[i] = tempId;
+                    }
+                    else {
+                        optionalVariableByParameter[i] = -1;
+                        parameter.forVariables(procedure);
+                    }
+                }
+            }
+                   
+            // Combine required and optional variables
+            TIntHashSet allVariablesSet = new TIntHashSet();
+            for(int v : optionalVariableByParameter)
+                if(v >= 0)
+                    allVariablesSet.add(v);
+            
+            context.addConstraint(new RelationConstraint(allVariablesSet.toArray(), varParameters, this,
+                    optionalVariableByParameter, procedure.requiredVariablesMask));
+        } catch(Exception e) {
+            context.getQueryCompilationContext().getTypingContext().getErrorLog().log(location, e);
+        }
+    }
+    
+    private static void collectRefs(SCLRelation relation, TObjectIntHashMap<Object> allRefs,
+            TIntHashSet refs) {
+        if(relation instanceof CompositeRelation) {
+            for(SCLRelation subrelation : ((CompositeRelation) relation).getSubrelations())
+                collectRefs(subrelation, allRefs, refs);
+        }
+        else {
+            int id = allRefs.get(relation);
+            if(id >= 0)
+                refs.add(id);
+        }
+    }
+
+    @Override
+    public void collectRefs(TObjectIntHashMap<Object> allRefs,
+            TIntHashSet refs) {
+        collectRefs(relation, allRefs, refs);
+        for(Expression parameter : parameters)
+            parameter.collectRefs(allRefs, refs);
+    }
+    
+    @Override
+    public void collectVars(TObjectIntHashMap<Variable> allVars,
+            TIntHashSet vars) {
+        for(Expression parameter : parameters)
+            parameter.collectVars(allVars, vars);
+    }
+
+    @Override
+    public Query replace(ReplaceContext context) {
+        Type[] newTypeParameters;
+        if(typeParameters == null)
+            newTypeParameters = null;
+        else {
+            newTypeParameters = new Type[typeParameters.length];
+            for(int i=0;i<typeParameters.length;++i)
+                newTypeParameters[i] = typeParameters[i].replace(context.tvarMap);
+        }
+        return new QAtom(relation,
+                newTypeParameters,
+                Expression.replace(context, parameters));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Diff[] derivate(THashMap<LocalRelation, Diffable> diffables) throws DerivateException {
+        Diffable diffable = diffables.get(relation);
+        if(diffable == null) {
+            if(relation instanceof CompositeRelation && 
+                    containsReferenceTo((CompositeRelation)relation,
+                            (THashMap<SCLRelation, Diffable>)(THashMap)diffables))
+                throw new DerivateException(location);
+            return NO_DIFF;
+        }
+        else {
+            Query[] eqs = new Query[parameters.length];
+            for(int i=0;i<parameters.length;++i) {
+                QAtom eq = new QAtom(EqRelation.INSTANCE, new Expression[] {
+                        new EVariable(diffable.parameters[i]),
+                        parameters[i]
+                });
+                eq.setLocationDeep(location);
+                eq.typeParameters = new Type[] {parameters[i].getType()};
+                eqs[i] = eq;
+            }
+            return new Diff[] { new Diff(diffable.id, new QConjunction(eqs)) };
+        }
+    }
+    
+    private static boolean containsReferenceTo(
+            CompositeRelation relation,
+            THashMap<SCLRelation, Diffable> diffables) {
+        for(SCLRelation r : relation.getSubrelations())
+            if(diffables.containsKey(r))
+                return true;
+            else if(r instanceof CompositeRelation &&
+                    containsReferenceTo((CompositeRelation)r, diffables))
+                return true;
+        return false;
+    }
+
+    @Override
+    public Query removeRelations(Set<SCLRelation> relations) {
+        if(relations.contains(relation))
+            return EMPTY_QUERY;
+        else
+            return this;
+    }
+    
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            location = loc;
+            for(Expression parameter : parameters)
+                parameter.setLocationDeep(loc);
+        }
+    }
+    
+    @Override
+    public void accept(QueryVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public void forVariables(VariableProcedure procedure) {
+        for(Expression parameter : parameters)
+            parameter.forVariables(procedure);
+    }
+
+    @Override
+    public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
+        int phase = relation.getPhase();
+        ArrayList<Query> list = result.get(phase);
+        if(list == null) {
+            list = new ArrayList<Query>();
+            result.put(phase, list);
+        }
+        list.add(this);
+    }
+    
+    @Override
+    public Query accept(QueryTransformer transformer) {
+        return transformer.transform(this);
+    }
+
+}