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