1 package org.simantics.scl.compiler.elaboration.expressions;
\r
3 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.*;
\r
4 import gnu.trove.map.hash.THashMap;
\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
18 public class EEntityTypeAnnotation extends ASTExpression {
\r
20 Expression expression;
\r
21 Token entityTypeName;
\r
22 SCLEntityType entityType;
\r
23 Query query; // optional
\r
24 THashMap<String, AttributeBinding> attributeBindingMap;
\r
26 public EEntityTypeAnnotation(Expression expression, Token entityTypeName,
\r
28 this.expression = expression;
\r
29 this.entityTypeName = entityTypeName;
\r
34 public Expression resolve(TranslationContext context) {
\r
35 // Resolve a subexpression
\r
36 expression = expression.resolve(context);
\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
44 // Resolve entity type
\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
51 if(entityType == null) {
\r
52 context.getErrorLog().log(location, "Couldn't resolve entity type " + entityTypeName.text + ".");
\r
53 return new EError(location);
\r
56 // Rewrite the subexpression as a separate query if it is not a variable
\r
58 if(expression instanceof EVariable)
\r
59 base = ((EVariable)expression).variable;
\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
68 // Resolve a related query if it exists
\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
80 attributeBindings = attributeBindingMap.values().toArray(new AttributeBinding[attributeBindingMap.size()]);
\r
81 for(AttributeBinding binding : attributeBindings)
\r
82 context.currentPreQuery.extraVariables.add(binding.variable);
\r
84 context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, attributeBindings));
\r
87 context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, AttributeBinding.EMPTY_ARRAY));
\r
92 public void setLocationDeep(long loc) {
\r
93 if(location == Locations.NO_LOCATION) {
\r
95 expression.setLocationDeep(loc);
\r
96 query.setLocationDeep(loc);
\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
108 binding = new AttributeBinding(attribute, new Variable("#"+name));
\r
109 attributeBindingMap.put(name, binding);
\r
111 return new EVariable(binding.variable);
\r
115 public Expression accept(ExpressionTransformer transformer) {
\r
116 return transformer.transform(this);
\r