package org.simantics.scl.compiler.elaboration.expressions; import org.simantics.scl.compiler.common.names.Name; 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.accessor.FieldAccessor; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; 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[] accessors; public EFieldAccess(Expression parent, FieldAccessor[] accessors) { if(parent instanceof EFieldAccess) { EFieldAccess parentAccess = (EFieldAccess)parent; parent = parentAccess.parent; accessors = concat(parentAccess.accessors, accessors); } this.parent = parent; this.accessors = accessors; } @Override public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { parent.collectRefs(allRefs, refs); for(FieldAccessor accessor : accessors) accessor.collectRefs(allRefs, refs); } @Override public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { parent.collectVars(allVars, vars); for(FieldAccessor accessor : accessors) accessor.collectVars(allVars, vars); } private boolean returnsValue() { FieldAccessor lastAccessor = accessors[accessors.length-1]; return lastAccessor.accessSeparator=='#' && !lastAccessor.isVariableId(); } @Override protected void updateType() throws MatchException { // Type is already updated in checkBasicType } @Override public Expression checkBasicType(TypingContext context, Type requiredType) { if(returnsValue()) setType(requiredType); else { setType(VARIABLE); context.subsume(this, requiredType); } parent = parent.checkType(context, VARIABLE); for(FieldAccessor accessor : accessors) accessor.checkType(context); context.declareEffect(getLocation(), Types.READ_GRAPH); return this; } @Override public void collectFreeVariables(THashSet vars) { parent.collectFreeVariables(vars); for(FieldAccessor accessor : accessors) accessor.collectFreeVariables(vars); } private static final Name CHILD = Name.create("Simantics/Variables", "child_"); private static final Name PROPERTY = Name.create("Simantics/Variables", "property"); private static final Name PROPERTY_VALUE = Name.create("Simantics/Variables", "untypedPropertyValue"); @Override public Expression simplify(SimplificationContext context) { // Simplify subexpressions parent = parent.simplify(context); for(FieldAccessor accessor : accessors) accessor.simplify(context); // ... Expression result = parent; for(int i=0;i effects) { // FIXME effects.add(Types.READ_GRAPH); } @Override public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) { location = loc; parent.setLocationDeep(loc); for(FieldAccessor accessor : accessors) accessor.setLocationDeep(loc); } } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } @Override public void forVariables(VariableProcedure procedure) { parent.forVariables(procedure); for(FieldAccessor accessor : accessors) accessor.forVariables(procedure); } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } }