1 package org.simantics.scl.compiler.elaboration.expressions;
3 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.loc;
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;
17 import gnu.trove.map.hash.THashMap;
19 public class EEntityTypeAnnotation extends ASTExpression {
21 Expression expression;
23 SCLEntityType entityType;
24 Query query; // optional
25 THashMap<String, AttributeBinding> attributeBindingMap;
27 public EEntityTypeAnnotation(Expression expression, Token entityTypeName,
29 this.expression = expression;
30 this.entityTypeName = entityTypeName;
35 public Expression resolve(TranslationContext context) {
36 // Resolve a subexpression
37 expression = expression.resolve(context);
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);
45 // Resolve entity type
47 entityType = Environments.getEntityType(context.getEnvironment(), entityTypeName.text);
48 } catch (AmbiguousNameException e) {
49 context.getErrorLog().log(location, e.getMessage());
50 return new EError(location);
52 if(entityType == null) {
53 context.getErrorLog().log(location, "Couldn't resolve entity type " + entityTypeName.text + ".");
54 return new EError(location);
57 // Rewrite the subexpression as a separate query if it is not a variable
59 if(expression instanceof EVariable)
60 base = ((EVariable)expression).variable;
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));
69 // Resolve a related query if it exists
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;
81 attributeBindings = attributeBindingMap.values().toArray(new AttributeBinding[attributeBindingMap.size()]);
82 for(AttributeBinding binding : attributeBindings)
83 context.currentPreQuery.extraVariables.add(binding.variable);
85 context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, attributeBindings));
88 context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, AttributeBinding.EMPTY_ARRAY));
93 public void setLocationDeep(long loc) {
94 if(location == Locations.NO_LOCATION) {
96 expression.setLocationDeep(loc);
97 query.setLocationDeep(loc);
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);
109 binding = new AttributeBinding(attribute, new Variable("#"+name));
110 attributeBindingMap.put(name, binding);
112 return new EVariable(binding.variable);
116 public Expression accept(ExpressionTransformer transformer) {
117 return transformer.transform(this);