]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EEntityTypeAnnotation.java
f0363dcdffa349fc8f85870ac211fff5085d3036
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EEntityTypeAnnotation.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.loc;
4
5 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
6 import org.simantics.scl.compiler.elaboration.java.EqRelation;
7 import org.simantics.scl.compiler.elaboration.query.QAtom;
8 import org.simantics.scl.compiler.elaboration.query.Query;
9 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
10 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType.Attribute;
11 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType.AttributeBinding;
12 import org.simantics.scl.compiler.environment.AmbiguousNameException;
13 import org.simantics.scl.compiler.environment.Environments;
14 import org.simantics.scl.compiler.errors.Locations;
15 import org.simantics.scl.compiler.internal.parsing.Token;
16
17 import gnu.trove.map.hash.THashMap;
18
19 public class EEntityTypeAnnotation extends ASTExpression {
20     
21     Expression expression;
22     Token entityTypeName;
23     SCLEntityType entityType;
24     Query query; // optional
25     THashMap<String, AttributeBinding> attributeBindingMap;
26
27     public EEntityTypeAnnotation(Expression expression, Token entityTypeName,
28             Query query) {
29         this.expression = expression;
30         this.entityTypeName = entityTypeName;
31         this.query = query;
32     }
33
34     @Override
35     public Expression resolve(TranslationContext context) {
36         // Resolve a subexpression
37         expression = expression.resolve(context);
38         
39         // Check that we are inside a query
40         if(context.currentPreQuery == null) {
41             context.getErrorLog().log(location, "Entity type annotations can be used only in queries.");
42             return new EError(location);
43         }
44         
45         // Resolve entity type
46         try {
47             entityType = Environments.getEntityType(context.getEnvironment(), entityTypeName.text);
48         } catch (AmbiguousNameException e) {
49             context.getErrorLog().log(location, e.getMessage());
50             return new EError(location);
51         }
52         if(entityType == null) {
53             context.getErrorLog().log(location, "Couldn't resolve entity type " + entityTypeName.text + ".");
54             return new EError(location);
55         }
56
57         // Rewrite the subexpression as a separate query if it is not a variable
58         Variable base;
59         if(expression instanceof EVariable)
60             base = ((EVariable)expression).variable;
61         else {
62             base = new Variable("?" + entityTypeName.text);
63             context.currentPreQuery.extraVariables.add(base);
64             context.currentPreQuery.sideQueries.add(loc(expression.location,
65                     new QAtom(EqRelation.INSTANCE, new EVariable(base), expression)));
66             expression = loc(expression.location, new EVariable(base));
67         }
68         
69         // Resolve a related query if it exists
70         if(query != null) {
71             EEntityTypeAnnotation oldEntityTypeAnnotation = context.currentEntityTypeAnnotation;
72             attributeBindingMap = new THashMap<String, AttributeBinding>();
73             context.currentEntityTypeAnnotation = this;
74             query = query.resolve(context);
75             context.currentPreQuery.sideQueries.add(query);
76             context.currentEntityTypeAnnotation = oldEntityTypeAnnotation;
77             AttributeBinding[] attributeBindings;
78             if(attributeBindingMap.isEmpty())
79                 attributeBindings = AttributeBinding.EMPTY_ARRAY;
80             else {
81                 attributeBindings = attributeBindingMap.values().toArray(new AttributeBinding[attributeBindingMap.size()]);
82                 for(AttributeBinding binding : attributeBindings)
83                     context.currentPreQuery.extraVariables.add(binding.variable);
84             }
85             context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, attributeBindings));
86         }
87         else
88             context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, AttributeBinding.EMPTY_ARRAY));
89         return expression;
90     }
91     
92     @Override
93     public void setLocationDeep(long loc) {
94         if(location == Locations.NO_LOCATION) {
95             location = loc;
96             expression.setLocationDeep(loc);
97             query.setLocationDeep(loc);
98         }
99     }
100
101     public Expression resolveAttribute(TranslationContext context, long location, String name) {
102         AttributeBinding binding = attributeBindingMap.get(name);
103         if(binding == null) {
104             Attribute attribute = entityType.getAttribute(name);
105             if(attribute == null) {
106                 context.getErrorLog().log(location, "Attribute " + name + " is not defined in entity type " + entityTypeName.text + ".");
107                 return new EError(location);
108             }
109             binding = new AttributeBinding(attribute, new Variable("#"+name));
110             attributeBindingMap.put(name, binding);
111         }
112         return new EVariable(binding.variable);
113     }
114     
115     @Override
116     public Expression accept(ExpressionTransformer transformer) {
117         return transformer.transform(this);
118     }
119
120 }