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