]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EFieldAccess.java
(refs #7375) Replace collectRefs by CollectRefsVisitor
[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 collectVars(TObjectIntHashMap<Variable> allVars,
40             TIntHashSet vars) {
41         parent.collectVars(allVars, vars);
42         accessor.collectVars(allVars, vars);
43     }
44
45     private boolean returnsValue() {
46         return accessor.accessSeparator == '#' && !accessor.isVariableId();
47     }
48
49     @Override
50     protected void updateType() throws MatchException {
51         // Type is already updated in checkBasicType
52     }
53     
54     private Expression resolveAccessor(TypingContext context, Type requiredType) {
55         if(!(accessor instanceof IdAccessor))
56             return null;
57         IdAccessor idAccessor = (IdAccessor)accessor;
58         if(idAccessor.accessSeparator != '.')
59             return null;
60         List<Constant> accessors = context.getEnvironment().getFieldAccessors(idAccessor.fieldName);
61         if(accessors == null) {
62             context.getErrorLog().log(idAccessor.location, "Couldn't resolve accessor ." + idAccessor.fieldName + ".");
63             return new EError(location);
64         }
65         Expression accessorExpression;
66         if(accessors.size() == 1)
67             accessorExpression = new ELiteral(accessors.get(0));
68         else {
69             Alternative[] alternatives = new Alternative[accessors.size()];
70             for(int i=0;i<alternatives.length;++i) {
71                 final int index = i;
72                 alternatives[i] = new Alternative() {
73                     @Override
74                     public Expression realize() {
75                         return new ELiteral(accessors.get(index));
76                     }
77                     @Override
78                     public Type getType() {
79                         return accessors.get(index).getType();
80                     }
81                     @Override
82                     public String toString() {
83                         return accessors.get(index).toString();
84                     }
85                 };
86             }
87             accessorExpression = new EAmbiguous(alternatives);
88             accessorExpression.location = location;
89         }
90         return new EApply(location, accessorExpression, parent).checkType(context, requiredType);
91     }
92     
93     @Override
94     public Expression checkBasicType(TypingContext context, Type requiredType) {
95         ModuleHeader header = context.getCompilationContext().header;
96         if(header != null && header.fields) {
97             Expression expression = resolveAccessor(context, requiredType);
98             if(expression != null)
99                 return expression;
100         }
101         
102         // Default case
103         if(returnsValue())
104             setType(requiredType);
105         else {
106             setType(VARIABLE);
107             context.subsume(this, requiredType);
108         }
109         parent = parent.checkType(context, VARIABLE);
110         accessor.checkType(context);
111         context.declareEffect(getLocation(), Types.READ_GRAPH);
112         return this;
113     }
114
115     @Override
116     public void collectFreeVariables(THashSet<Variable> vars) {
117         parent.collectFreeVariables(vars);
118         accessor.collectFreeVariables(vars);
119     }
120
121     @Override
122     public Expression simplify(SimplificationContext context) {
123         // Simplify subexpressions
124         parent = parent.simplify(context);
125         accessor.simplify(context);
126         
127         if(accessor.accessSeparator == '.')
128                 return new EApply(
129                                 getLocation(),
130                                 Types.READ_GRAPH,
131                                 context.getConstant(Names.Simantics_Variables_child_),
132                                 parent,
133                                 accessor.asExpression()
134                                 );
135         else if(!lastAccessor)
136                 return new EApply(
137                                 getLocation(),
138                                 Types.READ_GRAPH,
139                                 context.getConstant(Names.Simantics_Variables_property),
140                                 parent,
141                                 accessor.asExpression()
142                                 );
143         else if(accessor.isVariableId())
144                 return parent;
145         else
146                 return new EApply(
147                                 getLocation(),
148                                 Types.READ_GRAPH,
149                                 context.getConstant(Names.Simantics_Variables_untypedPropertyValue, getType()),
150                                 parent,
151                                 accessor.asExpression()
152                                 );
153     }
154
155     @Override
156     public Expression resolve(TranslationContext context) {
157         parent = parent.resolve(context);
158         accessor.resolve(context);
159         return this;
160     }
161
162     @Override
163     public void collectEffects(THashSet<Type> effects) {
164         // FIXME
165         effects.add(Types.READ_GRAPH);
166     }
167     
168     @Override
169     public void setLocationDeep(long loc) {
170         if(location == Locations.NO_LOCATION) {
171             location = loc;
172             parent.setLocationDeep(loc);
173             accessor.setLocationDeep(loc);
174         }
175     }
176     
177     @Override
178     public void accept(ExpressionVisitor visitor) {
179         visitor.visit(this);
180     }
181     
182     @Override
183     public Expression accept(ExpressionTransformer transformer) {
184         return transformer.transform(this);
185     }
186
187 }