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