]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java
(refs #7250) Support for record syntax for CHR relations
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / translation / CHRTranslation.java
1 package org.simantics.scl.compiler.elaboration.chr.translation;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
8 import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
9 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
10 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
11 import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;
12 import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelation;
13 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
14 import org.simantics.scl.compiler.elaboration.expressions.EApply;
15 import org.simantics.scl.compiler.elaboration.expressions.EBinary;
16 import org.simantics.scl.compiler.elaboration.expressions.ERecord;
17 import org.simantics.scl.compiler.elaboration.expressions.EVar;
18 import org.simantics.scl.compiler.elaboration.expressions.Expression;
19 import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement;
20 import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement;
21 import org.simantics.scl.compiler.elaboration.expressions.list.ListAssignment;
22 import org.simantics.scl.compiler.elaboration.expressions.list.ListGenerator;
23 import org.simantics.scl.compiler.elaboration.expressions.list.ListGuard;
24 import org.simantics.scl.compiler.elaboration.expressions.list.ListQualifier;
25 import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
26 import org.simantics.scl.compiler.environment.AmbiguousNameException;
27 import org.simantics.scl.compiler.environment.Environments;
28 import org.simantics.scl.compiler.errors.Locations;
29 import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
30 import org.simantics.scl.compiler.internal.parsing.types.TypeAst;
31
32 public class CHRTranslation {
33
34     private static CHRLiteral convertExpression(boolean isHead, Expression expression) {
35         if(isHead)
36             return new CHRLiteral(expression.location, SpecialCHRRelation.CHECK, new Expression[] {expression}, false, false);
37         else
38             return new CHRLiteral(expression.location, SpecialCHRRelation.EXECUTE, new Expression[] {expression}, false, false);
39     }
40
41     private static CHRLiteral convertConstraint(boolean remove, boolean negated, Expression expression) {
42         long location = expression.location;
43         Expression[] parameters;
44         FieldAssignment[] fields = null;
45         if(expression instanceof EApply) {
46             EApply apply = (EApply)expression;
47             parameters = apply.parameters;
48             expression = apply.function;
49         }
50         else if(expression instanceof ERecord) {
51             ERecord record = (ERecord)expression;
52             parameters = null;
53             fields = record.fields;
54             expression = record.constructor;
55         }
56         else // if(expression instanceof EVar)
57             parameters = Expression.EMPTY_ARRAY;
58         EVar var = (EVar)expression; // this should succeed because of isConstraint test
59         CHRLiteral literal = new CHRLiteral(location, new UnresolvedCHRRelation(var.location, var.name),
60                 parameters, remove, negated);
61         literal.fields = fields;
62         return literal;
63     }
64     
65     private static CHRLiteral convertListQualifier(TranslationContext context, boolean isHead, ListQualifier qualifier) {
66         if(qualifier instanceof ListGuard) {
67             Expression originalExpression = ((ListGuard)qualifier).condition;
68             if(originalExpression instanceof EVar && ((EVar)originalExpression).name.equals("True"))
69                 return null;
70             Expression currentExpression = originalExpression;
71             boolean remove = false;
72             boolean negated = false;
73             if(currentExpression instanceof EBinary) {
74                 EBinary binary = (EBinary)currentExpression;
75                 if(binary.negation==null || !binary.rights.isEmpty())
76                     return convertExpression(isHead, originalExpression);
77                 currentExpression = binary.left;
78                 remove = true;
79             }
80             else if(currentExpression instanceof EApply) {
81                 EApply apply = (EApply)currentExpression;
82                 if(apply.function instanceof EVar && ((EVar)apply.function).name.equals("not")) {
83                     negated = true;
84                     if(apply.parameters.length == 1)
85                         currentExpression = apply.parameters[0];
86                     else {
87                         currentExpression = new EApply(
88                                 Locations.combine(apply.parameters[0].location, apply.parameters[apply.parameters.length-1].location),
89                                 apply.parameters[0],
90                                 Arrays.copyOfRange(apply.parameters, 1, apply.parameters.length));
91                     }
92                 }
93             }
94             if(isConstraint(context, currentExpression))
95                 return convertConstraint(remove, negated, currentExpression);
96             else
97                 return convertExpression(isHead, originalExpression);
98         }
99         else if(qualifier instanceof ListAssignment) {
100             ListAssignment assignment = (ListAssignment)qualifier;
101             return new CHRLiteral(assignment.location, SpecialCHRRelation.EQUALS, new Expression[] {
102                     assignment.pattern, assignment.value 
103             }, false, false);
104         }
105         else if(qualifier instanceof ListGenerator) {
106             ListGenerator generator = (ListGenerator)qualifier;
107             return new CHRLiteral(generator.location, SpecialCHRRelation.MEMBER, new Expression[] {
108                     generator.pattern, generator.value
109             }, false, false);
110         }
111         else {
112             context.getErrorLog().log(qualifier.location, "Invalid CHR literal.");
113             return null;
114         }
115     }
116     
117     private static boolean isConstraint(TranslationContext context, Expression expression) {
118         if(expression instanceof EApply)
119             expression = ((EApply)expression).function;
120         else if(expression instanceof ERecord)
121             expression = ((ERecord)expression).constructor;
122         if(!(expression instanceof EVar))
123             return false;
124         String name = ((EVar)expression).name;
125         if(TranslationContext.isConstructorName(name))
126             return true;
127         try {
128             return Environments.getRelation(context.getEnvironment(), name) != null;
129         } catch (AmbiguousNameException e) {
130             return true;
131         }
132     }
133
134     public static CHRRule convertCHRStatement(TranslationContext context, CHRStatement statement) {
135         ArrayList<CHRLiteral> head = new ArrayList<CHRLiteral>(statement.head.length);
136         for(ListQualifier qualifier : statement.head) {
137             CHRLiteral literal = convertListQualifier(context, true, qualifier);
138             if(literal != null)
139                 head.add(literal);
140         }
141         ArrayList<CHRLiteral> body = new ArrayList<CHRLiteral>(statement.body.length);
142         for(ListQualifier qualifier : statement.body) {
143             CHRLiteral literal = convertListQualifier(context, false, qualifier);
144             if(literal != null)
145                 body.add(literal);
146         }
147         return new CHRRule(statement.location,
148                 new CHRQuery(head.toArray(new CHRLiteral[head.size()])),
149                 new CHRQuery(body.toArray(new CHRLiteral[body.size()])),
150                 null);
151     }
152
153     public static CHRConstraint convertConstraintStatement(TranslationContext context, ConstraintStatement statement) {
154         CHRConstraint constraint = new CHRConstraint(statement.location, statement.name.text, TypeAst.toTypes(context, statement.parameterTypes));
155         for(DAnnotationAst annotation : statement.annotations)
156             applyConstraintAnnotation(context, constraint, annotation);
157         constraint.fieldNames = statement.fieldNames;
158         return constraint;
159     }
160
161     private static void applyConstraintAnnotation(TranslationContext context, CHRConstraint constraint, DAnnotationAst annotation) {
162         context.getErrorLog().log(annotation.location, "Invalid constraint annotation");
163     }
164     
165 }