]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/ast/CHRAstAtom.java
(refs #7377) Refactoring CHR query parsing
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / ast / CHRAstAtom.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/ast/CHRAstAtom.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/ast/CHRAstAtom.java
new file mode 100644 (file)
index 0000000..031d8ed
--- /dev/null
@@ -0,0 +1,143 @@
+package org.simantics.scl.compiler.elaboration.chr.ast;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
+import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;
+import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelation;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EBinary;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ERecord;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.types.Types;
+
+public class CHRAstAtom extends CHRAstQuery {
+    public Expression expression;
+    public boolean remove;
+
+    public CHRAstAtom(Expression expression, boolean remove) {
+        this.expression = expression;
+        this.remove = remove;
+    }
+    
+    @Override
+    public void accept(CHRAstQueryVisitor visitor) {
+        visitor.visit(this);
+    }
+    
+    public static CHRAstQuery atom(Expression expression) {
+        boolean remove = false;
+        if(expression instanceof EVar) {
+            EVar var = (EVar)expression;
+            if(var.name.equals("True")) {
+                CHRAstConjunction query = new CHRAstConjunction(Collections.emptyList());
+                query.location = expression.location;
+                return query;
+            }
+        }
+        else if(expression instanceof EBinary) {
+            EBinary binary = (EBinary)expression;
+            if(binary.negation != null && binary.rights.isEmpty()) {
+                remove = true;
+                expression = binary.left;
+            }
+            // If query is marked for removal, it must be an atom
+        }
+        else if(expression instanceof EApply) {
+            EApply apply = (EApply)expression;
+            if(apply.function instanceof EVar && ((EVar)apply.function).name.equals("not")) {
+                Expression subExpression;
+                if(apply.parameters.length == 1)
+                    subExpression = apply.parameters[0];
+                else
+                    subExpression = new EApply(
+                            Locations.combine(apply.parameters[0].location, apply.parameters[apply.parameters.length-1].location),
+                            apply.parameters[0],
+                            Arrays.copyOfRange(apply.parameters, 1, apply.parameters.length));
+                CHRAstNegation query = new CHRAstNegation(atom(subExpression));
+                query.location = expression.location;
+                return query;
+            }
+            else if(apply.function instanceof EConstant) {
+                Name valueName = ((EConstant)apply.function).getValue().getName();
+                if(valueName.module.equals(Types.BUILTIN) && valueName.name.startsWith("(")) {
+                    CHRAstQuery[] conjuncts = new CHRAstQuery[apply.parameters.length];
+                    for(int i=0;i<conjuncts.length;++i)
+                        conjuncts[i] = atom(apply.parameters[i]);
+                    CHRAstQuery query = CHRAstConjunction.conjunction(conjuncts);
+                    query.location = expression.location;
+                    return query;
+                }
+            }
+        }
+        CHRAstAtom query = new CHRAstAtom(expression, remove);
+        query.location = expression.location;
+        return query;
+    }
+
+    @Override
+    protected void translate(TranslationContext context, boolean isHead, ArrayList<CHRLiteral> literals) {
+        literals.add(
+            isConstraint(context, expression) ?
+            convertConstraint(remove, expression) :
+            convertExpression(isHead, expression));
+    }
+    
+    private static boolean isConstraint(TranslationContext context, Expression expression) {
+        if(expression instanceof EApply)
+            expression = ((EApply)expression).function;
+        else if(expression instanceof ERecord)
+            expression = ((ERecord)expression).constructor;
+        if(!(expression instanceof EVar))
+            return false;
+        String name = ((EVar)expression).name;
+        if(TranslationContext.isConstructorName(name))
+            return true;
+        try {
+            return Environments.getRelation(context.getEnvironment(), name) != null;
+        } catch (AmbiguousNameException e) {
+            return true;
+        }
+    }
+    
+    private static CHRLiteral convertExpression(boolean isHead, Expression expression) {
+        if(isHead)
+            return new CHRLiteral(expression.location, SpecialCHRRelation.CHECK, new Expression[] {expression}, false, false);
+        else
+            return new CHRLiteral(expression.location, SpecialCHRRelation.EXECUTE, new Expression[] {expression}, false, false);
+    }
+
+    private static CHRLiteral convertConstraint(boolean remove, Expression expression) {
+        long location = expression.location;
+        Expression[] parameters;
+        FieldAssignment[] fields = null;
+        if(expression instanceof EApply) {
+            EApply apply = (EApply)expression;
+            parameters = apply.parameters;
+            expression = apply.function;
+        }
+        else if(expression instanceof ERecord) {
+            ERecord record = (ERecord)expression;
+            parameters = null;
+            fields = record.fields;
+            expression = record.constructor;
+        }
+        else // if(expression instanceof EVar)
+            parameters = Expression.EMPTY_ARRAY;
+        EVar var = (EVar)expression; // this should succeed because of isConstraint test
+        CHRLiteral literal = new CHRLiteral(location, new UnresolvedCHRRelation(var.location, var.name),
+                parameters, remove, false);
+        literal.fields = fields;
+        return literal;
+    }
+}