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; 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 collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { parent.collectRefs(allRefs, refs); accessor.collectRefs(allRefs, refs); } @Override public void collectVars(TObjectIntHashMap 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 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 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 Expression decorate(ExpressionDecorator decorator) { return decorator.decorate(this); } @Override public void collectEffects(THashSet 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 void forVariables(VariableProcedure procedure) { parent.forVariables(procedure); accessor.forVariables(procedure); } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } }