]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EFieldAccess.java
(refs #7375) Replaced ExpressionDecorator by ExpressionTransformer
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EFieldAccess.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.List;
4
5 import org.simantics.scl.compiler.common.names.Names;
6 import org.simantics.scl.compiler.constants.Constant;
7 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
8 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
9 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
10 import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous.Alternative;
11 import org.simantics.scl.compiler.elaboration.expressions.accessor.FieldAccessor;
12 import org.simantics.scl.compiler.elaboration.expressions.accessor.IdAccessor;
13 import org.simantics.scl.compiler.errors.Locations;
14 import org.simantics.scl.compiler.internal.header.ModuleHeader;
15 import org.simantics.scl.compiler.types.Type;
16 import org.simantics.scl.compiler.types.Types;
17 import org.simantics.scl.compiler.types.exceptions.MatchException;
18
19 import gnu.trove.map.hash.TObjectIntHashMap;
20 import gnu.trove.set.hash.THashSet;
21 import gnu.trove.set.hash.TIntHashSet;
22
23 public class EFieldAccess extends SimplifiableExpression {
24
25     private static final Type VARIABLE = Types.con("Simantics/Variables", "Variable");
26     
27     Expression parent;
28     FieldAccessor accessor;
29     boolean lastAccessor = true;
30
31     public EFieldAccess(Expression parent, FieldAccessor accessor) {
32         this.parent = parent;
33         this.accessor = accessor;
34         if(parent instanceof EFieldAccess)
35                 ((EFieldAccess)parent).lastAccessor = false;
36     }
37
38     @Override
39     public void collectRefs(TObjectIntHashMap<Object> allRefs,
40             TIntHashSet refs) {
41         parent.collectRefs(allRefs, refs);
42         accessor.collectRefs(allRefs, refs);
43     }
44
45     @Override
46     public void collectVars(TObjectIntHashMap<Variable> allVars,
47             TIntHashSet vars) {
48         parent.collectVars(allVars, vars);
49         accessor.collectVars(allVars, vars);
50     }
51
52     private boolean returnsValue() {
53         return accessor.accessSeparator == '#' && !accessor.isVariableId();
54     }
55
56     @Override
57     protected void updateType() throws MatchException {
58         // Type is already updated in checkBasicType
59     }
60     
61     private Expression resolveAccessor(TypingContext context, Type requiredType) {
62         if(!(accessor instanceof IdAccessor))
63             return null;
64         IdAccessor idAccessor = (IdAccessor)accessor;
65         if(idAccessor.accessSeparator != '.')
66             return null;
67         List<Constant> accessors = context.getEnvironment().getFieldAccessors(idAccessor.fieldName);
68         if(accessors == null) {
69             context.getErrorLog().log(idAccessor.location, "Couldn't resolve accessor ." + idAccessor.fieldName + ".");
70             return new EError(location);
71         }
72         Expression accessorExpression;
73         if(accessors.size() == 1)
74             accessorExpression = new ELiteral(accessors.get(0));
75         else {
76             Alternative[] alternatives = new Alternative[accessors.size()];
77             for(int i=0;i<alternatives.length;++i) {
78                 final int index = i;
79                 alternatives[i] = new Alternative() {
80                     @Override
81                     public Expression realize() {
82                         return new ELiteral(accessors.get(index));
83                     }
84                     @Override
85                     public Type getType() {
86                         return accessors.get(index).getType();
87                     }
88                     @Override
89                     public String toString() {
90                         return accessors.get(index).toString();
91                     }
92                 };
93             }
94             accessorExpression = new EAmbiguous(alternatives);
95             accessorExpression.location = location;
96         }
97         return new EApply(location, accessorExpression, parent).checkType(context, requiredType);
98     }
99     
100     @Override
101     public Expression checkBasicType(TypingContext context, Type requiredType) {
102         ModuleHeader header = context.getCompilationContext().header;
103         if(header != null && header.fields) {
104             Expression expression = resolveAccessor(context, requiredType);
105             if(expression != null)
106                 return expression;
107         }
108         
109         // Default case
110         if(returnsValue())
111             setType(requiredType);
112         else {
113             setType(VARIABLE);
114             context.subsume(this, requiredType);
115         }
116         parent = parent.checkType(context, VARIABLE);
117         accessor.checkType(context);
118         context.declareEffect(getLocation(), Types.READ_GRAPH);
119         return this;
120     }
121
122     @Override
123     public void collectFreeVariables(THashSet<Variable> vars) {
124         parent.collectFreeVariables(vars);
125         accessor.collectFreeVariables(vars);
126     }
127
128     @Override
129     public Expression simplify(SimplificationContext context) {
130         // Simplify subexpressions
131         parent = parent.simplify(context);
132         accessor.simplify(context);
133         
134         if(accessor.accessSeparator == '.')
135                 return new EApply(
136                                 getLocation(),
137                                 Types.READ_GRAPH,
138                                 context.getConstant(Names.Simantics_Variables_child_),
139                                 parent,
140                                 accessor.asExpression()
141                                 );
142         else if(!lastAccessor)
143                 return new EApply(
144                                 getLocation(),
145                                 Types.READ_GRAPH,
146                                 context.getConstant(Names.Simantics_Variables_property),
147                                 parent,
148                                 accessor.asExpression()
149                                 );
150         else if(accessor.isVariableId())
151                 return parent;
152         else
153                 return new EApply(
154                                 getLocation(),
155                                 Types.READ_GRAPH,
156                                 context.getConstant(Names.Simantics_Variables_untypedPropertyValue, getType()),
157                                 parent,
158                                 accessor.asExpression()
159                                 );
160     }
161
162     @Override
163     public Expression resolve(TranslationContext context) {
164         parent = parent.resolve(context);
165         accessor.resolve(context);
166         return this;
167     }
168
169     @Override
170     public void collectEffects(THashSet<Type> effects) {
171         // FIXME
172         effects.add(Types.READ_GRAPH);
173     }
174     
175     @Override
176     public void setLocationDeep(long loc) {
177         if(location == Locations.NO_LOCATION) {
178             location = loc;
179             parent.setLocationDeep(loc);
180             accessor.setLocationDeep(loc);
181         }
182     }
183     
184     @Override
185     public void accept(ExpressionVisitor visitor) {
186         visitor.visit(this);
187     }
188
189     @Override
190     public void forVariables(VariableProcedure procedure) {
191         parent.forVariables(procedure);
192         accessor.forVariables(procedure);
193     }
194     
195     @Override
196     public Expression accept(ExpressionTransformer transformer) {
197         return transformer.transform(this);
198     }
199
200 }