--- /dev/null
+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);
+ }
+}