--- /dev/null
+package org.simantics.scl.compiler.elaboration.expressions;\r
+\r
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.*;\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;\r
+import org.simantics.scl.compiler.elaboration.java.EqRelation;\r
+import org.simantics.scl.compiler.elaboration.query.QAtom;\r
+import org.simantics.scl.compiler.elaboration.query.Query;\r
+import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;\r
+import org.simantics.scl.compiler.elaboration.relations.SCLEntityType.Attribute;\r
+import org.simantics.scl.compiler.elaboration.relations.SCLEntityType.AttributeBinding;\r
+import org.simantics.scl.compiler.environment.AmbiguousNameException;\r
+import org.simantics.scl.compiler.environment.Environments;\r
+import org.simantics.scl.compiler.errors.Locations;\r
+import org.simantics.scl.compiler.internal.parsing.Token;\r
+\r
+public class EEntityTypeAnnotation extends ASTExpression {\r
+ \r
+ Expression expression;\r
+ Token entityTypeName;\r
+ SCLEntityType entityType;\r
+ Query query; // optional\r
+ THashMap<String, AttributeBinding> attributeBindingMap;\r
+\r
+ public EEntityTypeAnnotation(Expression expression, Token entityTypeName,\r
+ Query query) {\r
+ this.expression = expression;\r
+ this.entityTypeName = entityTypeName;\r
+ this.query = query;\r
+ }\r
+\r
+ @Override\r
+ public Expression resolve(TranslationContext context) {\r
+ // Resolve a subexpression\r
+ expression = expression.resolve(context);\r
+ \r
+ // Check that we are inside a query\r
+ if(context.currentPreQuery == null) {\r
+ context.getErrorLog().log(location, "Entity type annotations can be used only in queries.");\r
+ return new EError(location);\r
+ }\r
+ \r
+ // Resolve entity type\r
+ try {\r
+ entityType = Environments.getEntityType(context.getEnvironment(), entityTypeName.text);\r
+ } catch (AmbiguousNameException e) {\r
+ context.getErrorLog().log(location, e.getMessage());\r
+ return new EError(location);\r
+ }\r
+ if(entityType == null) {\r
+ context.getErrorLog().log(location, "Couldn't resolve entity type " + entityTypeName.text + ".");\r
+ return new EError(location);\r
+ }\r
+\r
+ // Rewrite the subexpression as a separate query if it is not a variable\r
+ Variable base;\r
+ if(expression instanceof EVariable)\r
+ base = ((EVariable)expression).variable;\r
+ else {\r
+ base = new Variable("?" + entityTypeName.text);\r
+ context.currentPreQuery.extraVariables.add(base);\r
+ context.currentPreQuery.sideQueries.add(loc(expression.location,\r
+ new QAtom(EqRelation.INSTANCE, new EVariable(base), expression)));\r
+ expression = loc(expression.location, new EVariable(base));\r
+ }\r
+ \r
+ // Resolve a related query if it exists\r
+ if(query != null) {\r
+ EEntityTypeAnnotation oldEntityTypeAnnotation = context.currentEntityTypeAnnotation;\r
+ attributeBindingMap = new THashMap<String, AttributeBinding>();\r
+ context.currentEntityTypeAnnotation = this;\r
+ query = query.resolve(context);\r
+ context.currentPreQuery.sideQueries.add(query);\r
+ context.currentEntityTypeAnnotation = oldEntityTypeAnnotation;\r
+ AttributeBinding[] attributeBindings;\r
+ if(attributeBindingMap.isEmpty())\r
+ attributeBindings = AttributeBinding.EMPTY_ARRAY;\r
+ else {\r
+ attributeBindings = attributeBindingMap.values().toArray(new AttributeBinding[attributeBindingMap.size()]);\r
+ for(AttributeBinding binding : attributeBindings)\r
+ context.currentPreQuery.extraVariables.add(binding.variable);\r
+ }\r
+ context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, attributeBindings));\r
+ }\r
+ else\r
+ context.currentPreQuery.sideQueries.add(entityType.generateQuery(context, base, AttributeBinding.EMPTY_ARRAY));\r
+ return expression;\r
+ }\r
+ \r
+ @Override\r
+ public void setLocationDeep(long loc) {\r
+ if(location == Locations.NO_LOCATION) {\r
+ location = loc;\r
+ expression.setLocationDeep(loc);\r
+ query.setLocationDeep(loc);\r
+ }\r
+ }\r
+\r
+ public Expression resolveAttribute(TranslationContext context, long location, String name) {\r
+ AttributeBinding binding = attributeBindingMap.get(name);\r
+ if(binding == null) {\r
+ Attribute attribute = entityType.getAttribute(name);\r
+ if(attribute == null) {\r
+ context.getErrorLog().log(location, "Attribute " + name + " is not defined in entity type " + entityTypeName.text + ".");\r
+ return new EError(location);\r
+ }\r
+ binding = new AttributeBinding(attribute, new Variable("#"+name));\r
+ attributeBindingMap.put(name, binding);\r
+ }\r
+ return new EVariable(binding.variable);\r
+ }\r
+ \r
+ @Override\r
+ public Expression accept(ExpressionTransformer transformer) {\r
+ return transformer.transform(this);\r
+ }\r
+\r
+}\r