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