-package org.simantics.scl.compiler.elaboration.expressions;\r
-\r
-import org.simantics.scl.compiler.common.names.Names;\r
-import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;\r
-import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;\r
-import org.simantics.scl.compiler.elaboration.contexts.TypingContext;\r
-import org.simantics.scl.compiler.elaboration.expressions.accessor.FieldAccessor;\r
-import org.simantics.scl.compiler.errors.Locations;\r
-import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;\r
-import org.simantics.scl.compiler.types.Type;\r
-import org.simantics.scl.compiler.types.Types;\r
-import org.simantics.scl.compiler.types.exceptions.MatchException;\r
-\r
-import gnu.trove.map.hash.TObjectIntHashMap;\r
-import gnu.trove.set.hash.THashSet;\r
-import gnu.trove.set.hash.TIntHashSet;\r
-\r
-public class EFieldAccess extends SimplifiableExpression {\r
-\r
- private static final Type VARIABLE = Types.con("Simantics/Variables", "Variable");\r
- \r
- Expression parent;\r
- FieldAccessor[] accessors;\r
-\r
- public EFieldAccess(Expression parent, FieldAccessor[] accessors) {\r
- if(parent instanceof EFieldAccess) {\r
- EFieldAccess parentAccess = (EFieldAccess)parent;\r
- parent = parentAccess.parent;\r
- accessors = concat(parentAccess.accessors, accessors);\r
- }\r
- this.parent = parent;\r
- this.accessors = accessors;\r
- }\r
-\r
- @Override\r
- public void collectRefs(TObjectIntHashMap<Object> allRefs,\r
- TIntHashSet refs) {\r
- parent.collectRefs(allRefs, refs);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.collectRefs(allRefs, refs);\r
- }\r
-\r
- @Override\r
- public void collectVars(TObjectIntHashMap<Variable> allVars,\r
- TIntHashSet vars) {\r
- parent.collectVars(allVars, vars);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.collectVars(allVars, vars);\r
- }\r
-\r
- private boolean returnsValue() {\r
- FieldAccessor lastAccessor = accessors[accessors.length-1];\r
- return lastAccessor.accessSeparator=='#' && !lastAccessor.isVariableId();\r
- }\r
-\r
- @Override\r
- protected void updateType() throws MatchException {\r
- // Type is already updated in checkBasicType\r
- }\r
- \r
- @Override\r
- public Expression checkBasicType(TypingContext context, Type requiredType) {\r
- if(returnsValue())\r
- setType(requiredType);\r
- else {\r
- setType(VARIABLE);\r
- context.subsume(this, requiredType);\r
- }\r
- parent = parent.checkType(context, VARIABLE);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.checkType(context);\r
- context.declareEffect(getLocation(), Types.READ_GRAPH);\r
- return this;\r
- }\r
-\r
- @Override\r
- public void collectFreeVariables(THashSet<Variable> vars) {\r
- parent.collectFreeVariables(vars);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.collectFreeVariables(vars);\r
- }\r
-\r
- @Override\r
- public Expression simplify(SimplificationContext context) {\r
- // Simplify subexpressions\r
- parent = parent.simplify(context);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.simplify(context);\r
- \r
- // ...\r
- Expression result = parent;\r
- for(int i=0;i<accessors.length;++i) {\r
- FieldAccessor accessor = accessors[i];\r
- if(accessor.accessSeparator == '.')\r
- result = new EApply(\r
- getLocation(),\r
- Types.READ_GRAPH,\r
- context.getConstant(Names.Simantics_Variables_child_),\r
- result,\r
- accessor.asExpression()\r
- );\r
- else if(i < accessors.length-1)\r
- result = new EApply(\r
- getLocation(),\r
- Types.READ_GRAPH,\r
- context.getConstant(Names.Simantics_Variables_property),\r
- result,\r
- accessor.asExpression()\r
- );\r
- else if(accessor.isVariableId())\r
- ;\r
- else\r
- result = new EApply(\r
- getLocation(),\r
- Types.READ_GRAPH,\r
- context.getConstant(Names.Simantics_Variables_untypedPropertyValue, getType()),\r
- result,\r
- accessor.asExpression()\r
- );\r
- }\r
- return result;\r
- }\r
-\r
- private static FieldAccessor[] concat(FieldAccessor[] accessors1,\r
- FieldAccessor[] accessors2) {\r
- FieldAccessor[] result = new FieldAccessor[accessors1.length + accessors2.length];\r
- System.arraycopy(accessors1, 0, result, 0, accessors1.length);\r
- System.arraycopy(accessors2, 0, result, accessors1.length, accessors2.length);\r
- return result;\r
- }\r
-\r
- @Override\r
- public Expression resolve(TranslationContext context) {\r
- parent = parent.resolve(context);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.resolve(context);\r
- return this;\r
- }\r
-\r
- @Override\r
- public Expression decorate(ExpressionDecorator decorator) {\r
- return decorator.decorate(this);\r
- }\r
-\r
- @Override\r
- public void collectEffects(THashSet<Type> effects) {\r
- // FIXME\r
- effects.add(Types.READ_GRAPH);\r
- }\r
- \r
- @Override\r
- public void setLocationDeep(long loc) {\r
- if(location == Locations.NO_LOCATION) {\r
- location = loc;\r
- parent.setLocationDeep(loc);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.setLocationDeep(loc);\r
- }\r
- }\r
- \r
- @Override\r
- public void accept(ExpressionVisitor visitor) {\r
- visitor.visit(this);\r
- }\r
-\r
- @Override\r
- public void forVariables(VariableProcedure procedure) {\r
- parent.forVariables(procedure);\r
- for(FieldAccessor accessor : accessors)\r
- accessor.forVariables(procedure);\r
- }\r
- \r
- @Override\r
- public Expression accept(ExpressionTransformer transformer) {\r
- return transformer.transform(this);\r
- }\r
-\r
-}\r
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import java.util.List;
+
+import org.simantics.scl.compiler.common.names.Names;
+import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous.Alternative;
+import org.simantics.scl.compiler.elaboration.expressions.accessor.FieldAccessor;
+import org.simantics.scl.compiler.elaboration.expressions.accessor.IdAccessor;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.header.ModuleHeader;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+public class EFieldAccess extends SimplifiableExpression {
+
+ private static final Type VARIABLE = Types.con("Simantics/Variables", "Variable");
+
+ Expression parent;
+ FieldAccessor accessor;
+ boolean lastAccessor = true;
+
+ public EFieldAccess(Expression parent, FieldAccessor accessor) {
+ this.parent = parent;
+ this.accessor = accessor;
+ if(parent instanceof EFieldAccess)
+ ((EFieldAccess)parent).lastAccessor = false;
+ }
+
+ @Override
+ public void collectVars(TObjectIntHashMap<Variable> allVars,
+ TIntHashSet vars) {
+ parent.collectVars(allVars, vars);
+ accessor.collectVars(allVars, vars);
+ }
+
+ private boolean returnsValue() {
+ return accessor.accessSeparator == '#' && !accessor.isVariableId();
+ }
+
+ @Override
+ protected void updateType() throws MatchException {
+ // Type is already updated in checkBasicType
+ }
+
+ private Expression resolveAccessor(TypingContext context, Type requiredType) {
+ if(!(accessor instanceof IdAccessor))
+ return null;
+ IdAccessor idAccessor = (IdAccessor)accessor;
+ if(idAccessor.accessSeparator != '.')
+ return null;
+ List<Constant> accessors = context.getEnvironment().getFieldAccessors(idAccessor.fieldName);
+ if(accessors == null) {
+ context.getErrorLog().log(idAccessor.location, "Couldn't resolve accessor ." + idAccessor.fieldName + ".");
+ return new EError(location);
+ }
+ Expression accessorExpression;
+ if(accessors.size() == 1)
+ accessorExpression = new ELiteral(accessors.get(0));
+ else {
+ Alternative[] alternatives = new Alternative[accessors.size()];
+ for(int i=0;i<alternatives.length;++i) {
+ final int index = i;
+ alternatives[i] = new Alternative() {
+ @Override
+ public Expression realize() {
+ return new ELiteral(accessors.get(index));
+ }
+ @Override
+ public Type getType() {
+ return accessors.get(index).getType();
+ }
+ @Override
+ public String toString() {
+ return accessors.get(index).toString();
+ }
+ };
+ }
+ accessorExpression = new EAmbiguous(alternatives);
+ accessorExpression.location = location;
+ }
+ return new EApply(location, accessorExpression, parent).checkType(context, requiredType);
+ }
+
+ @Override
+ public Expression checkBasicType(TypingContext context, Type requiredType) {
+ ModuleHeader header = context.getCompilationContext().header;
+ if(header != null && header.fields) {
+ Expression expression = resolveAccessor(context, requiredType);
+ if(expression != null)
+ return expression;
+ }
+
+ // Default case
+ if(returnsValue())
+ setType(requiredType);
+ else {
+ setType(VARIABLE);
+ context.subsume(this, requiredType);
+ }
+ parent = parent.checkType(context, VARIABLE);
+ accessor.checkType(context);
+ context.declareEffect(getLocation(), Types.READ_GRAPH);
+ return this;
+ }
+
+ @Override
+ public void collectFreeVariables(THashSet<Variable> vars) {
+ parent.collectFreeVariables(vars);
+ accessor.collectFreeVariables(vars);
+ }
+
+ @Override
+ public Expression simplify(SimplificationContext context) {
+ // Simplify subexpressions
+ parent = parent.simplify(context);
+ accessor.simplify(context);
+
+ if(accessor.accessSeparator == '.')
+ return new EApply(
+ getLocation(),
+ Types.READ_GRAPH,
+ context.getConstant(Names.Simantics_Variables_child_),
+ parent,
+ accessor.asExpression()
+ );
+ else if(!lastAccessor)
+ return new EApply(
+ getLocation(),
+ Types.READ_GRAPH,
+ context.getConstant(Names.Simantics_Variables_property),
+ parent,
+ accessor.asExpression()
+ );
+ else if(accessor.isVariableId())
+ return parent;
+ else
+ return new EApply(
+ getLocation(),
+ Types.READ_GRAPH,
+ context.getConstant(Names.Simantics_Variables_untypedPropertyValue, getType()),
+ parent,
+ accessor.asExpression()
+ );
+ }
+
+ @Override
+ public Expression resolve(TranslationContext context) {
+ parent = parent.resolve(context);
+ accessor.resolve(context);
+ return this;
+ }
+
+ @Override
+ public void collectEffects(THashSet<Type> effects) {
+ // FIXME
+ effects.add(Types.READ_GRAPH);
+ }
+
+ @Override
+ public void setLocationDeep(long loc) {
+ if(location == Locations.NO_LOCATION) {
+ location = loc;
+ parent.setLocationDeep(loc);
+ accessor.setLocationDeep(loc);
+ }
+ }
+
+ @Override
+ public void accept(ExpressionVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public Expression accept(ExpressionTransformer transformer) {
+ return transformer.transform(this);
+ }
+
+}