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