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