]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EEntityTypeAnnotation.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EEntityTypeAnnotation.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EEntityTypeAnnotation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EEntityTypeAnnotation.java
new file mode 100644 (file)
index 0000000..108b4b7
--- /dev/null
@@ -0,0 +1,119 @@
+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