--- /dev/null
+package org.simantics.scl.compiler.elaboration.query;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+import java.util.Arrays;
+
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
+import org.simantics.scl.compiler.elaboration.query.pre.QPreExists;
+import org.simantics.scl.compiler.elaboration.query.pre.QPreGuard;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.types.Type;
+
+public abstract class QAbstractCombiner extends Query {
+ public Query[] queries;
+
+ public QAbstractCombiner(Query[] queries) {
+ this.queries = queries;
+ }
+
+ public void collectFreeVariables(THashSet<Variable> vars) {
+ for(Query query : queries)
+ query.collectFreeVariables(vars);
+ }
+
+ @Override
+ public Query resolve(TranslationContext context) {
+ Query modifiedQuery = handleExistsStatement(context);
+ if(modifiedQuery != null)
+ return modifiedQuery.resolve(context);
+
+ for(int i=0;i<queries.length;++i)
+ queries[i] = queries[i].resolve(context);
+ return this;
+ }
+
+ private QPreExists handleExistsStatement(TranslationContext context) {
+ if(queries.length == 0)
+ return null;
+ if(!(queries[0] instanceof QPreGuard))
+ return null;
+ Expression exp = ((QPreGuard)queries[0]).guard;
+ if(!(exp instanceof EApply))
+ return null;
+ EApply apply = (EApply)exp;
+ if(!(apply.getFunction() instanceof EVar))
+ return null;
+ if(!((EVar)apply.getFunction()).name.equals("exists"))
+ return null;
+
+ queries = Arrays.copyOfRange(queries, 1, queries.length);
+
+ Expression[] pars = apply.getParameters();
+ String[] variableNames = new String[pars.length];
+ for(int i=0;i<pars.length;++i) {
+ if(pars[i] instanceof EVar)
+ variableNames[i] = ((EVar)pars[i]).name;
+ else {
+ context.getErrorLog().log(pars[i].getLocation(), "Exists statement may only contain variables as parameters.");
+ return null;
+ }
+ }
+ return new QPreExists(variableNames, this);
+ }
+
+ @Override
+ public void checkType(TypingContext context) {
+ for(Query query : queries)
+ query.checkType(context);
+ }
+
+ @Override
+ public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
+ for(Query query : queries)
+ query.collectRefs(allRefs, refs);
+ }
+
+ @Override
+ public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
+ for(Query query : queries)
+ query.collectVars(allVars, vars);
+ }
+
+ @Override
+ public void setLocationDeep(long loc) {
+ if(location == Locations.NO_LOCATION) {
+ location = loc;
+ for(Query query : queries)
+ query.setLocationDeep(loc);
+ }
+ }
+
+ @Override
+ public void forVariables(VariableProcedure procedure) {
+ for(Query query : queries)
+ query.forVariables(procedure);
+ }
+}