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.elaboration.utils.ExpressionDecorator;
+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;
private static final Type VARIABLE = Types.con("Simantics/Variables", "Variable");
Expression parent;
- FieldAccessor[] accessors;
+ FieldAccessor accessor;
+ boolean lastAccessor = true;
- public EFieldAccess(Expression parent, FieldAccessor[] accessors) {
- if(parent instanceof EFieldAccess) {
- EFieldAccess parentAccess = (EFieldAccess)parent;
- parent = parentAccess.parent;
- accessors = concat(parentAccess.accessors, accessors);
- }
+ public EFieldAccess(Expression parent, FieldAccessor accessor) {
this.parent = parent;
- this.accessors = accessors;
+ this.accessor = accessor;
+ if(parent instanceof EFieldAccess)
+ ((EFieldAccess)parent).lastAccessor = false;
}
@Override
public void collectRefs(TObjectIntHashMap<Object> allRefs,
TIntHashSet refs) {
parent.collectRefs(allRefs, refs);
- for(FieldAccessor accessor : accessors)
- accessor.collectRefs(allRefs, refs);
+ accessor.collectRefs(allRefs, refs);
}
@Override
public void collectVars(TObjectIntHashMap<Variable> allVars,
TIntHashSet vars) {
parent.collectVars(allVars, vars);
- for(FieldAccessor accessor : accessors)
- accessor.collectVars(allVars, vars);
+ accessor.collectVars(allVars, vars);
}
private boolean returnsValue() {
- FieldAccessor lastAccessor = accessors[accessors.length-1];
- return lastAccessor.accessSeparator=='#' && !lastAccessor.isVariableId();
+ return accessor.accessSeparator == '#' && !accessor.isVariableId();
}
@Override
// 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("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();
+ }
+ };
+ }
+ accessorExpression = new EAmbiguous(alternatives);
+ }
+ 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 {
context.subsume(this, requiredType);
}
parent = parent.checkType(context, VARIABLE);
- for(FieldAccessor accessor : accessors)
- accessor.checkType(context);
+ accessor.checkType(context);
context.declareEffect(getLocation(), Types.READ_GRAPH);
return this;
}
@Override
public void collectFreeVariables(THashSet<Variable> vars) {
parent.collectFreeVariables(vars);
- for(FieldAccessor accessor : accessors)
- accessor.collectFreeVariables(vars);
+ accessor.collectFreeVariables(vars);
}
@Override
public Expression simplify(SimplificationContext context) {
// Simplify subexpressions
parent = parent.simplify(context);
- for(FieldAccessor accessor : accessors)
- accessor.simplify(context);
+ accessor.simplify(context);
- // ...
- Expression result = parent;
- for(int i=0;i<accessors.length;++i) {
- FieldAccessor accessor = accessors[i];
- if(accessor.accessSeparator == '.')
- result = new EApply(
- getLocation(),
- Types.READ_GRAPH,
- context.getConstant(Names.Simantics_Variables_child_),
- result,
- accessor.asExpression()
- );
- else if(i < accessors.length-1)
- result = new EApply(
- getLocation(),
- Types.READ_GRAPH,
- context.getConstant(Names.Simantics_Variables_property),
- result,
- accessor.asExpression()
- );
- else if(accessor.isVariableId())
- ;
- else
- result = new EApply(
- getLocation(),
- Types.READ_GRAPH,
- context.getConstant(Names.Simantics_Variables_untypedPropertyValue, getType()),
- result,
- accessor.asExpression()
- );
- }
- return result;
- }
-
- private static FieldAccessor[] concat(FieldAccessor[] accessors1,
- FieldAccessor[] accessors2) {
- FieldAccessor[] result = new FieldAccessor[accessors1.length + accessors2.length];
- System.arraycopy(accessors1, 0, result, 0, accessors1.length);
- System.arraycopy(accessors2, 0, result, accessors1.length, accessors2.length);
- return result;
+ 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);
- for(FieldAccessor accessor : accessors)
- accessor.resolve(context);
+ accessor.resolve(context);
return this;
}
if(location == Locations.NO_LOCATION) {
location = loc;
parent.setLocationDeep(loc);
- for(FieldAccessor accessor : accessors)
- accessor.setLocationDeep(loc);
+ accessor.setLocationDeep(loc);
}
}
@Override
public void forVariables(VariableProcedure procedure) {
parent.forVariables(procedure);
- for(FieldAccessor accessor : accessors)
- accessor.forVariables(procedure);
+ accessor.forVariables(procedure);
}
@Override