]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/ast/CHRAstAtom.java
031d8edd84d2e733f99292f6ea7561759d2534a6
[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, boolean isHead, ArrayList<CHRLiteral> literals) {
90         literals.add(
91             isConstraint(context, expression) ?
92             convertConstraint(remove, expression) :
93             convertExpression(isHead, expression));
94     }
95     
96     private static boolean isConstraint(TranslationContext context, Expression expression) {
97         if(expression instanceof EApply)
98             expression = ((EApply)expression).function;
99         else if(expression instanceof ERecord)
100             expression = ((ERecord)expression).constructor;
101         if(!(expression instanceof EVar))
102             return false;
103         String name = ((EVar)expression).name;
104         if(TranslationContext.isConstructorName(name))
105             return true;
106         try {
107             return Environments.getRelation(context.getEnvironment(), name) != null;
108         } catch (AmbiguousNameException e) {
109             return true;
110         }
111     }
112     
113     private static CHRLiteral convertExpression(boolean isHead, Expression expression) {
114         if(isHead)
115             return new CHRLiteral(expression.location, SpecialCHRRelation.CHECK, new Expression[] {expression}, false, false);
116         else
117             return new CHRLiteral(expression.location, SpecialCHRRelation.EXECUTE, new Expression[] {expression}, false, false);
118     }
119
120     private static CHRLiteral convertConstraint(boolean remove, Expression expression) {
121         long location = expression.location;
122         Expression[] parameters;
123         FieldAssignment[] fields = null;
124         if(expression instanceof EApply) {
125             EApply apply = (EApply)expression;
126             parameters = apply.parameters;
127             expression = apply.function;
128         }
129         else if(expression instanceof ERecord) {
130             ERecord record = (ERecord)expression;
131             parameters = null;
132             fields = record.fields;
133             expression = record.constructor;
134         }
135         else // if(expression instanceof EVar)
136             parameters = Expression.EMPTY_ARRAY;
137         EVar var = (EVar)expression; // this should succeed because of isConstraint test
138         CHRLiteral literal = new CHRLiteral(location, new UnresolvedCHRRelation(var.location, var.name),
139                 parameters, remove, false);
140         literal.fields = fields;
141         return literal;
142     }
143 }