]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java
Improved environment resolution for document SCL expressions
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / request / ServerSCLHandlerValueRequest.java
1 package org.simantics.document.server.request;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.simantics.databoard.Bindings;
9 import org.simantics.db.ReadGraph;
10 import org.simantics.db.Resource;
11 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
12 import org.simantics.db.common.request.IndexRoot;
13 import org.simantics.db.common.request.UnaryRead;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext;
16 import org.simantics.db.layer0.util.RuntimeEnvironmentRequest2;
17 import org.simantics.db.layer0.variable.Variable;
18 import org.simantics.layer0.Layer0;
19 import org.simantics.scl.compiler.elaboration.expressions.EApply;
20 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
21 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
22 import org.simantics.scl.compiler.elaboration.expressions.Expression;
23 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
24 import org.simantics.scl.compiler.environment.Environment;
25 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
26 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
27 import org.simantics.scl.compiler.types.TCon;
28 import org.simantics.scl.compiler.types.Type;
29 import org.simantics.scl.compiler.types.Types;
30 import org.simantics.scl.compiler.types.exceptions.MatchException;
31 import org.simantics.scl.compiler.types.kinds.Kinds;
32 import org.simantics.scl.compiler.types.util.MultiFunction;
33 import org.simantics.scl.runtime.SCLContext;
34 import org.simantics.scl.runtime.function.Function1;
35 import org.simantics.scl.runtime.function.FunctionImpl1;
36 import org.simantics.structural2.scl.ComponentTypeProperty;
37 import org.simantics.structural2.scl.FindPossibleComponentTypeRequest;
38 import org.simantics.structural2.scl.ReadComponentTypeInterfaceRequest;
39 import org.simantics.utils.datastructures.Pair;
40
41 public class ServerSCLHandlerValueRequest extends ServerSCLValueRequestBase<org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext> {
42
43     private final Pair<Resource,Resource> componentTypeAndRoot;
44     private final Resource literal;
45     protected String possibleExpectedValueType;
46
47     public static class CompilationContext extends AbstractExpressionCompilationContext {
48         public final Map<String, ComponentTypeProperty> propertyMap;
49
50         public CompilationContext(RuntimeEnvironment runtimeEnvironment,
51                 Map<String, ComponentTypeProperty> propertyMap) {
52             super(runtimeEnvironment);
53             this.propertyMap = propertyMap;
54         }
55     }
56
57     private ServerSCLHandlerValueRequest(Pair<Resource,Resource> componentTypeAndRoot, Resource literal, String possibleExpectedValueType) {
58         assert(literal != null);
59         this.literal = literal;
60         this.componentTypeAndRoot = componentTypeAndRoot;
61         this.possibleExpectedValueType = possibleExpectedValueType;
62     }
63
64     public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException {
65         this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context.getPredicateResource(graph)));
66     }
67
68     public ServerSCLHandlerValueRequest(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
69         this(getComponentTypeAndRoot(graph, s, o), o, resolveExpectedValueType(graph, p));
70     }
71
72     private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Variable property)  throws DatabaseException {
73         Variable parent = property.getParent(graph);
74         Resource represents = parent.getRepresents(graph);
75         if(represents != null) {
76             Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(represents));
77             if(type != null) {
78                 Resource root = graph.syncRequest(new IndexRoot(type));
79                 return Pair.make(type, root);
80             }
81         }
82         parent = parent.getParent(graph);
83         Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph)));
84         return Pair.make(parent.getType(graph), root);
85     }
86
87
88     public static List<TCon> getEffects(ReadGraph graph, Variable context) throws DatabaseException {
89         HandlerFn fn = (HandlerFn)compile(graph, context);
90         return fn.effects;
91     }
92
93     public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException {
94         SCLContext sclContext = SCLContext.getCurrent();
95         Object oldGraph = sclContext.get("graph");
96         try {
97             Function1<Object,Object> exp = graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context),
98                     TransientCacheListener.instance());
99             sclContext.put("graph", graph);
100             return exp.apply(context);
101         } catch (DatabaseException e) {
102             throw (DatabaseException)e;
103         } catch (Throwable t) {
104             throw new DatabaseException(t);
105         } finally {
106             sclContext.put("graph", oldGraph);
107         }
108     }
109
110     public static Function1<Object, Object> compile(ReadGraph graph, Variable context) throws DatabaseException {
111         return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context), TransientCacheListener.instance());
112     }
113
114     public static Function1<Object, Object> compile(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
115         return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, s, o, p), TransientCacheListener.instance());
116     }
117
118     public static class HandlerFn extends FunctionImpl1<Object,Object> {
119
120         Function1<Object,Object> handler;
121         ArrayList<TCon> effects;
122
123         HandlerFn(Function1<Object,Object> handler, Type type) {
124             try {
125                 this.handler = handler;
126                 this.effects = new ArrayList<TCon>();
127                 MultiFunction mfun = Types.matchFunction(type, 1);
128                 mfun.effect.collectConcreteEffects(this.effects);
129             } catch(MatchException e) {
130                 // Should not happen!
131                 throw new RuntimeException(e);
132             }
133         }
134
135         @Override
136         public Object apply(Object p0) {
137             return handler.apply(p0);
138         }
139
140     }
141
142     @Override
143     public Function1<Object, Object> perform(ReadGraph graph) throws DatabaseException {
144
145         CompilationContext context = getCompilationContext(graph);
146         Type expectedType = getExpectedType(graph, context);
147         Function1<Object,Object> handler = eval(prepareEvaluator(graph, context, expectedType), graph);
148         return new HandlerFn(handler, expectedType);
149
150     }
151
152     @Override
153     protected String getExpressionText(ReadGraph graph)
154             throws DatabaseException {
155         Layer0 L0 = Layer0.getInstance(graph);
156         String exp = graph.getRelatedValue(literal, L0.SCLValue_expression, Bindings.STRING);
157         return "\\context -> " + exp;
158     }
159
160     protected RuntimeEnvironmentRequest2 getRuntimeEnvironmentRequest(Resource componentType, Resource indexRoot) {
161         return new RuntimeEnvironmentRequest2(componentType, indexRoot) {
162             @Override
163             protected void fillEnvironmentSpecification(
164                     EnvironmentSpecification environmentSpecification) {
165             }
166         };
167     }
168
169     @Override
170     protected CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException {
171         return graph.syncRequest(new UnaryRead<Pair<Resource,Resource>,CompilationContext>(componentTypeAndRoot) {
172             @Override
173             public CompilationContext perform(ReadGraph graph) throws DatabaseException {
174                 RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.first, parameter.second));
175                 Map<String, ComponentTypeProperty> propertyMap;
176                 if (parameter.first != null) {
177                     propertyMap =
178                             graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),
179                                     TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());
180                 } else {
181                     // TODO: Antti to consider
182                     // To handle procedural user components
183                     propertyMap = Collections.emptyMap();
184                 }
185 //              Map<String, ComponentTypeProperty> propertyMap =
186 //                      graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),
187 //                              TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());
188                 return new CompilationContext(runtimeEnvironment, propertyMap);
189             }
190         });
191     }
192
193     @Override
194     protected Type getContextVariableType() {
195         return VARIABLE; 
196     }
197
198     private static Expression accessInputVariable(Environment environment,
199             org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable) {
200         SCLValue variableParentFunction = environment.getValue(VARIABLE_PARENT);
201         return new EApply(new EConstant(variableParentFunction),
202                 new EApply(new EConstant(variableParentFunction),
203                         new EVariable(contextVariable)));
204     }
205
206     protected static Expression standardGetProperty(
207             Environment environment,
208             org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
209             String name,
210             Type type) {
211         return getPropertyFlexible(environment, accessInputVariable(environment, contextVariable), name, type);
212     }
213
214     @Override
215     protected Expression getVariableAccessExpression(
216             ReadGraph graph,
217             CompilationContext context,
218             org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
219             String name) throws DatabaseException {
220         ComponentTypeProperty property = context.propertyMap.get(name);
221         if(property != null)
222             return standardGetProperty(
223                     context.runtimeEnvironment.getEnvironment(),
224                     contextVariable,
225                     name,
226                     property.type == null ? Types.metaVar(Kinds.STAR) : property.type);
227         else {
228
229 //          if(context.propertyMap.containsKey(name)) {
230 //              
231 //              org.simantics.scl.compiler.elaboration.expressions.Variable parametersVariable = new org.simantics.scl.compiler.elaboration.expressions.Variable("context", COMMAND_CONTEXT);
232 //              
233 //              Environment environment = context.runtimeEnvironment.getEnvironment();
234 //              
235 ////                return new EApply(
236 ////                        new EConstant(environment.getValue(FROM_DYNAMIC), Types.STRING),
237 //                      return new EApply(
238 //                              new EConstant(environment.getValue(CONTEXT_VARIABLE), Types.DYNAMIC),
239 //                              new EVariable(parametersVariable),
240 //                              new ELiteral(new StringConstant(name)));
241 //              
242 //          }
243
244             return getSpecialVariableAccessExpression(graph, context, contextVariable, name);
245
246         }
247     }
248
249     protected Expression getSpecialVariableAccessExpression(ReadGraph graph,
250             CompilationContext context,
251             org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
252             String name) throws DatabaseException {
253         if(name.equals("input")) {
254             Environment environment = context.runtimeEnvironment.getEnvironment();
255             return accessInputVariable(environment, contextVariable);
256         } else if(name.equals("self"))
257             return new EVariable(contextVariable);
258         else
259             return null;
260     }
261
262     @Override
263     protected Type getExpectedType(ReadGraph graph, CompilationContext context) throws DatabaseException {
264         return super.getExpectedType(graph, context);
265     }
266
267     @Override
268     public int hashCode() {
269         return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();
270     }
271
272     @Override
273     public boolean equals(Object obj) {
274         if (this == obj)
275             return true;
276         if (obj == null)
277             return false;
278         if (getClass() != obj.getClass())
279             return false;
280         ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest) obj;
281         return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);
282     }
283
284 }