]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/ast/CHRAstAtom.java
CHR query translation and support for assignment in CHR bodies
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / ast / CHRAstAtom.java
1 package org.simantics.scl.compiler.elaboration.chr.ast;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6
7 import org.simantics.scl.compiler.common.names.Name;
8 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
9 import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;
10 import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelation;
11 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
12 import org.simantics.scl.compiler.elaboration.expressions.EApply;
13 import org.simantics.scl.compiler.elaboration.expressions.EBinary;
14 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
15 import org.simantics.scl.compiler.elaboration.expressions.ERecord;
16 import org.simantics.scl.compiler.elaboration.expressions.EVar;
17 import org.simantics.scl.compiler.elaboration.expressions.Expression;
18 import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
19 import org.simantics.scl.compiler.environment.AmbiguousNameException;
20 import org.simantics.scl.compiler.environment.Environments;
21 import org.simantics.scl.compiler.errors.Locations;
22 import org.simantics.scl.compiler.types.Types;
23
24 public class CHRAstAtom extends CHRAstQuery {
25     public Expression expression;
26     public boolean remove;
27
28     public CHRAstAtom(Expression expression, boolean remove) {
29         this.expression = expression;
30         this.remove = remove;
31     }
32     
33     @Override
34     public void accept(CHRAstQueryVisitor visitor) {
35         visitor.visit(this);
36     }
37     
38     public static CHRAstQuery atom(Expression expression) {
39         boolean remove = false;
40         if(expression instanceof EVar) {
41             EVar var = (EVar)expression;
42             if(var.name.equals("True")) {
43                 CHRAstConjunction query = new CHRAstConjunction(Collections.emptyList());
44                 query.location = expression.location;
45                 return query;
46             }
47         }
48         else if(expression instanceof EBinary) {
49             EBinary binary = (EBinary)expression;
50             if(binary.negation != null && binary.rights.isEmpty()) {
51                 remove = true;
52                 expression = binary.left;
53             }
54             // If query is marked for removal, it must be an atom
55         }
56         else if(expression instanceof EApply) {
57             EApply apply = (EApply)expression;
58             if(apply.function instanceof EVar && ((EVar)apply.function).name.equals("not")) {
59                 Expression subExpression;
60                 if(apply.parameters.length == 1)
61                     subExpression = apply.parameters[0];
62                 else
63                     subExpression = new EApply(
64                             Locations.combine(apply.parameters[0].location, apply.parameters[apply.parameters.length-1].location),
65                             apply.parameters[0],
66                             Arrays.copyOfRange(apply.parameters, 1, apply.parameters.length));
67                 CHRAstNegation query = new CHRAstNegation(atom(subExpression));
68                 query.location = expression.location;
69                 return query;
70             }
71             else if(apply.function instanceof EConstant) {
72                 Name valueName = ((EConstant)apply.function).getValue().getName();
73                 if(valueName.module.equals(Types.BUILTIN) && valueName.name.startsWith("(")) {
74                     CHRAstQuery[] conjuncts = new CHRAstQuery[apply.parameters.length];
75                     for(int i=0;i<conjuncts.length;++i)
76                         conjuncts[i] = atom(apply.parameters[i]);
77                     CHRAstQuery query = CHRAstConjunction.conjunction(conjuncts);
78                     query.location = expression.location;
79                     return query;
80                 }
81             }
82         }
83         CHRAstAtom query = new CHRAstAtom(expression, remove);
84         query.location = expression.location;
85         return query;
86     }
87
88     @Override
89     protected void translate(TranslationContext context, CHRQueryTranslationMode mode, ArrayList<CHRLiteral> literals) {
90         if(isConstraint(context, expression)) {
91             literals.add(convertConstraint(remove, expression));
92         }
93         else {
94             if(remove)
95                 context.getErrorLog().log(location, "Only constraints can be marked for removal");
96             else
97                 literals.add(convertExpression(mode, expression));
98         }
99     }
100     
101     private static boolean isConstraint(TranslationContext context, Expression expression) {
102         if(expression instanceof EApply)
103             expression = ((EApply)expression).function;
104         else if(expression instanceof ERecord)
105             expression = ((ERecord)expression).constructor;
106         if(!(expression instanceof EVar))
107             return false;
108         String name = ((EVar)expression).name;
109         if(TranslationContext.isConstructorName(name))
110             return true;
111         try {
112             return Environments.getRelation(context.getEnvironment(), name) != null;
113         } catch (AmbiguousNameException e) {
114             return true;
115         }
116     }
117     
118     private static CHRLiteral convertExpression(CHRQueryTranslationMode mode, Expression expression) {
119         if(mode.isHead)
120             return new CHRLiteral(expression.location, SpecialCHRRelation.CHECK, new Expression[] {expression}, false, false);
121         else
122             return new CHRLiteral(expression.location, SpecialCHRRelation.EXECUTE, new Expression[] {expression}, false, false);
123     }
124
125     private static CHRLiteral convertConstraint(boolean remove, Expression expression) {
126         long location = expression.location;
127         Expression[] parameters;
128         FieldAssignment[] fields = null;
129         if(expression instanceof EApply) {
130             EApply apply = (EApply)expression;
131             parameters = apply.parameters;
132             expression = apply.function;
133         }
134         else if(expression instanceof ERecord) {
135             ERecord record = (ERecord)expression;
136             parameters = null;
137             fields = record.fields;
138             expression = record.constructor;
139         }
140         else // if(expression instanceof EVar)
141             parameters = Expression.EMPTY_ARRAY;
142         EVar var = (EVar)expression; // this should succeed because of isConstraint test
143         CHRLiteral literal = new CHRLiteral(location, new UnresolvedCHRRelation(var.location, var.name),
144                 parameters, remove, false);
145         literal.fields = fields;
146         return literal;
147     }
148 }