ab72524b3f6260b75686d3538a8bafc1b2dab491
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / request / ServerSCLHandlerValueRequest.java
1 package org.simantics.document.server.request;\r
2 \r
3 import java.util.List;\r
4 import java.util.Map;\r
5 \r
6 import org.simantics.databoard.Bindings;\r
7 import org.simantics.db.ReadGraph;\r
8 import org.simantics.db.Resource;\r
9 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
10 import org.simantics.db.common.request.IndexRoot;\r
11 import org.simantics.db.common.request.UnaryRead;\r
12 import org.simantics.db.exception.DatabaseException;\r
13 import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext;\r
14 import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest;\r
15 import org.simantics.db.layer0.util.RuntimeEnvironmentRequest;\r
16 import org.simantics.db.layer0.variable.Variable;\r
17 import org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext;\r
18 import org.simantics.layer0.Layer0;\r
19 import org.simantics.scl.compiler.elaboration.expressions.EApply;\r
20 import org.simantics.scl.compiler.elaboration.expressions.EConstant;\r
21 import org.simantics.scl.compiler.elaboration.expressions.EVariable;\r
22 import org.simantics.scl.compiler.elaboration.expressions.Expression;\r
23 import org.simantics.scl.compiler.elaboration.modules.SCLValue;\r
24 import org.simantics.scl.compiler.environment.Environment;\r
25 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;\r
26 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;\r
27 import org.simantics.scl.compiler.types.TCon;\r
28 import org.simantics.scl.compiler.types.Type;\r
29 import org.simantics.scl.compiler.types.Types;\r
30 import org.simantics.scl.compiler.types.kinds.Kinds;\r
31 import org.simantics.scl.runtime.SCLContext;\r
32 import org.simantics.scl.runtime.function.Function1;\r
33 import org.simantics.structural2.scl.ComponentTypeProperty;\r
34 import org.simantics.structural2.scl.FindPossibleComponentTypeRequest;\r
35 import org.simantics.structural2.scl.ReadComponentTypeInterfaceRequest;\r
36 import org.simantics.utils.datastructures.Pair;\r
37 \r
38 public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationRequest<CompilationContext, Variable> {\r
39 \r
40         private final Pair<Resource,Resource> componentTypeAndRoot;\r
41         private final Resource literal;\r
42 \r
43         public static class CompilationContext extends AbstractExpressionCompilationContext {\r
44                 public final Map<String, ComponentTypeProperty> propertyMap;\r
45 \r
46                 public CompilationContext(RuntimeEnvironment runtimeEnvironment,\r
47                                 Map<String, ComponentTypeProperty> propertyMap) {\r
48                         super(runtimeEnvironment);\r
49                         this.propertyMap = propertyMap;\r
50                 }\r
51         }\r
52 \r
53         private ServerSCLHandlerValueRequest(Pair<Resource,Resource> componentTypeAndRoot, Resource literal) {\r
54                 assert(literal != null);\r
55                 this.literal = literal;\r
56                 this.componentTypeAndRoot = componentTypeAndRoot;\r
57         }\r
58 \r
59         public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException {\r
60                 this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph));\r
61         }\r
62 \r
63         private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Variable property)  throws DatabaseException {\r
64                 Variable parent = property.getParent(graph);\r
65                 Resource represents = parent.getRepresents(graph);\r
66                 if(represents != null) {\r
67                         Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(represents));\r
68                         if(type != null) {\r
69                                 Resource root = graph.syncRequest(new IndexRoot(type));\r
70                                 return Pair.make(type, root);\r
71                         }\r
72                 }\r
73                 parent = parent.getParent(graph);\r
74                 Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph)));\r
75                 return Pair.make(parent.getType(graph), root);\r
76         }\r
77 \r
78 \r
79     public static List<TCon> getEffects(ReadGraph graph, Variable context) throws DatabaseException {\r
80         try {\r
81                 ServerSCLHandlerValueRequest req = new ServerSCLHandlerValueRequest(graph, context);\r
82                 return req.getExpressionEffects(graph);\r
83         } catch (DatabaseException e) {\r
84             throw (DatabaseException)e;\r
85         } catch (Throwable t) {\r
86             throw new DatabaseException(t);\r
87         }\r
88     }\r
89 \r
90         public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException {\r
91                 SCLContext sclContext = SCLContext.getCurrent();\r
92         Object oldGraph = sclContext.get("graph");\r
93                 try {\r
94                         Function1<Variable,Object> exp = graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context),\r
95                                         TransientCacheListener.<Function1<Variable,Object>>instance());\r
96                         sclContext.put("graph", graph);\r
97                         return exp.apply(context);\r
98                 } catch (DatabaseException e) {\r
99                         throw (DatabaseException)e;\r
100                 } catch (Throwable t) {\r
101                         throw new DatabaseException(t);\r
102                 } finally {\r
103             sclContext.put("graph", oldGraph);\r
104                 }\r
105         }\r
106 \r
107         @Override\r
108         protected String getExpressionText(ReadGraph graph)\r
109                         throws DatabaseException {\r
110                 Layer0 L0 = Layer0.getInstance(graph);\r
111                 String exp = graph.getRelatedValue(literal, L0.SCLValue_expression, Bindings.STRING);\r
112                 return "\\context -> " + exp;\r
113         }\r
114 \r
115         protected RuntimeEnvironmentRequest getRuntimeEnvironmentRequest(Resource indexRoot) {\r
116                 return new RuntimeEnvironmentRequest(indexRoot) {\r
117                         @Override\r
118                         protected void fillEnvironmentSpecification(\r
119                                         EnvironmentSpecification environmentSpecification) {\r
120                         }\r
121                 };\r
122         }\r
123 \r
124         @Override\r
125         protected CompilationContext getCompilationContext(ReadGraph graph)\r
126                         throws DatabaseException {\r
127                 return graph.syncRequest(new UnaryRead<Pair<Resource,Resource>,CompilationContext>(componentTypeAndRoot) {\r
128                         @Override\r
129                         public CompilationContext perform(ReadGraph graph)\r
130                                         throws DatabaseException {\r
131                                 RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.second));\r
132                                 Map<String, ComponentTypeProperty> propertyMap =\r
133                                                 graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),\r
134                                                                 TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());\r
135                                 return new CompilationContext(runtimeEnvironment, propertyMap);\r
136                         }\r
137                 });\r
138         }\r
139 \r
140         @Override\r
141         protected Type getContextVariableType() {\r
142                 return VARIABLE; \r
143         }\r
144 \r
145         private static Expression accessInputVariable(Environment environment,\r
146                         org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable) {\r
147                 SCLValue variableParentFunction = environment.getValue(VARIABLE_PARENT);\r
148                 return new EApply(new EConstant(variableParentFunction),\r
149                                 new EApply(new EConstant(variableParentFunction),\r
150                                                 new EVariable(contextVariable)));\r
151         }\r
152 \r
153         protected static Expression standardGetProperty(\r
154                         Environment environment,\r
155                         org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,\r
156                         String name,\r
157                         Type type) {\r
158                 return getPropertyFlexible(environment, accessInputVariable(environment, contextVariable), name, type);\r
159         }\r
160 \r
161 \r
162         @Override\r
163         protected Expression getVariableAccessExpression(\r
164                         ReadGraph graph,\r
165                         CompilationContext context,\r
166                         org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,\r
167                         String name) throws DatabaseException {\r
168                 ComponentTypeProperty property = context.propertyMap.get(name);\r
169                 if(property != null)\r
170                         return standardGetProperty(\r
171                                         context.runtimeEnvironment.getEnvironment(),\r
172                                         contextVariable,\r
173                                         name,\r
174                                         property.type == null ? Types.metaVar(Kinds.STAR) : property.type);\r
175                 else\r
176                         return getSpecialVariableAccessExpression(graph, context, contextVariable, name);\r
177         }\r
178 \r
179         protected Expression getSpecialVariableAccessExpression(ReadGraph graph,\r
180                         CompilationContext context,\r
181                         org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,\r
182                         String name) throws DatabaseException {\r
183                 if(name.equals("input")) {\r
184                         Environment environment = context.runtimeEnvironment.getEnvironment();\r
185                         return accessInputVariable(environment, contextVariable);\r
186                 } else if(name.equals("self"))\r
187                         return new EVariable(contextVariable);\r
188                 else\r
189                         return null;\r
190         }\r
191 \r
192         @Override\r
193         public int hashCode() {\r
194                 return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();\r
195         }\r
196 \r
197         @Override\r
198         public boolean equals(Object obj) {\r
199                 if(this == obj)\r
200                         return true;\r
201                 if(obj == null || obj.getClass() != getClass())\r
202                         return false;\r
203                 ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest)obj;\r
204                 return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);\r
205         }\r
206 }\r