]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/pre/QPreGuard.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / query / pre / QPreGuard.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/pre/QPreGuard.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/pre/QPreGuard.java
new file mode 100644 (file)
index 0000000..287f899
--- /dev/null
@@ -0,0 +1,115 @@
+package org.simantics.scl.compiler.elaboration.query.pre;
+
+import java.util.Arrays;
+
+import org.simantics.scl.compiler.constants.BooleanConstant;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EEntityTypeAnnotation;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+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.java.CheckRelation;
+import org.simantics.scl.compiler.elaboration.query.QAtom;
+import org.simantics.scl.compiler.elaboration.query.QMapping;
+import org.simantics.scl.compiler.elaboration.query.Query;
+import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
+import org.simantics.scl.compiler.elaboration.relations.TransitiveClosureRelation;
+import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.errors.Locations;
+
+public class QPreGuard extends PreQuery {
+    public Expression guard;
+    
+    public QPreGuard(Expression guard) {
+        super();
+        this.guard = guard;
+    }
+
+    private static Query resolveAsQuery(TranslationContext context, Expression function,
+            Expression[] parameters) {
+        if(function instanceof EVar) {
+            String relationName = ((EVar)function).name;
+            if(relationName.equals("tc") && parameters.length > 0) {
+                Query query_ = resolveAsQuery(context, parameters[0],
+                        Arrays.copyOfRange(parameters, 1, parameters.length));
+                if(query_ == null)
+                    return null;
+                if(!(query_ instanceof QAtom)) {
+                    context.getErrorLog().log(query_.location, "Cannot form a transitive relation.");
+                    return null;
+                }
+                QAtom query = (QAtom)query_;
+                query.relation = new TransitiveClosureRelation(query.relation);
+                return query;
+            }
+            
+            MappingRelation mappingRelation;
+            try {
+                mappingRelation = Environments.getMappingRelation(
+                        context.getEnvironment(), relationName);
+            } catch (AmbiguousNameException e) {
+                context.getErrorLog().log(function.location, e.getMessage());
+                return null;
+            }
+            if(mappingRelation != null) {
+                if(parameters.length != 2)
+                    context.getErrorLog().log(function.location,
+                            "An arity of mapping relation should always be 2.");
+                for(int i=0;i<parameters.length;++i)
+                    parameters[i] = parameters[i].resolve(context);
+                return new QMapping(mappingRelation, parameters);
+            }
+            
+            SCLRelation relation = context.resolveRelation(function.getLocation(), relationName);
+            if(relation != null) {
+                for(int i=0;i<parameters.length;++i)
+                    parameters[i] = parameters[i].resolve(context);
+                return new QAtom(relation, parameters);
+            }
+        }
+        return null;
+    }
+    
+    private static Query resolveAsQuery(TranslationContext context, Expression expression) {
+        if(expression instanceof EApply) {
+            EApply apply = (EApply)expression;
+            Query query = resolveAsQuery(context, apply.getFunction(), apply.getParameters());
+            if(query != null)
+                return query;
+        }
+        else if(expression instanceof EEntityTypeAnnotation) {
+            expression = new ESimpleLet(new Variable("_"), expression, new ELiteral(new BooleanConstant(true)));
+        }
+        return new QAtom(CheckRelation.INSTANCE,
+                new Expression[] { expression.resolve(context) });
+    }
+    
+    @Override
+    public Query resolve(TranslationContext context) {
+        PreQuery oldPreQuery = context.currentPreQuery;
+        context.currentPreQuery = this;
+        Query query = resolveAsQuery(context, guard);
+        context.currentPreQuery = oldPreQuery;
+        query.location = location;
+        return withSideQueries(query);
+    }
+    
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            location = loc;
+            guard.setLocationDeep(loc);
+        }
+    }
+    
+    @Override
+    public Query accept(QueryTransformer transformer) {
+        return transformer.transform(this);
+    }
+}