]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
Collect reference hierarchy for SCL values
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / top / ExpressionEvaluator.java
1 package org.simantics.scl.compiler.top;
2
3 import java.io.StringReader;
4 import java.lang.reflect.Method;
5 import java.util.ArrayList;
6 import java.util.ListIterator;
7 import java.util.Map;
8
9 import org.simantics.scl.compiler.common.names.Name;
10 import org.simantics.scl.compiler.compilation.CodeGeneration;
11 import org.simantics.scl.compiler.compilation.CompilationContext;
12 import org.simantics.scl.compiler.constants.JavaStaticMethod;
13 import org.simantics.scl.compiler.constants.SCLConstant;
14 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
15 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
16 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
17 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
18 import org.simantics.scl.compiler.elaboration.expressions.EApply;
19 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
20 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
21 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
22 import org.simantics.scl.compiler.elaboration.expressions.EVar;
23 import org.simantics.scl.compiler.elaboration.expressions.Expression;
24 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
25 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
26 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
27 import org.simantics.scl.compiler.elaboration.java.Builtins;
28 import org.simantics.scl.compiler.environment.Environment;
29 import org.simantics.scl.compiler.environment.LocalEnvironment;
30 import org.simantics.scl.compiler.errors.CompilationError;
31 import org.simantics.scl.compiler.errors.ErrorLog;
32 import org.simantics.scl.compiler.internal.codegen.references.IVal;
33 import org.simantics.scl.compiler.internal.codegen.ssa.SSAModule;
34 import org.simantics.scl.compiler.internal.codegen.types.DummyJavaReferenceValidator;
35 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
36 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuildingException;
37 import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
38 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
39 import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder;
40 import org.simantics.scl.compiler.internal.codegen.utils.ValueFromMethod;
41 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
42 import org.simantics.scl.compiler.internal.codegen.writer.ExternalConstant;
43 import org.simantics.scl.compiler.internal.codegen.writer.ModuleWriter;
44 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
45 import org.simantics.scl.compiler.internal.interpreted.IExpression;
46 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
47 import org.simantics.scl.compiler.internal.parsing.parser.SCLBlockParser;
48 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
49 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions;
50 import org.simantics.scl.compiler.runtime.MutableClassLoader;
51 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
52 import org.simantics.scl.compiler.types.TVar;
53 import org.simantics.scl.compiler.types.Type;
54 import org.simantics.scl.compiler.types.Types;
55 import org.simantics.scl.compiler.types.kinds.Kinds;
56 import org.simantics.scl.compiler.types.util.Polarity;
57 import org.simantics.scl.compiler.types.util.ProcedureType;
58 import org.simantics.scl.runtime.function.FunctionImpl1;
59 import org.simantics.scl.runtime.tuple.Tuple0;
60
61 import gnu.trove.set.hash.THashSet;
62
63 public class ExpressionEvaluator {
64
65     public static final boolean TRACE_INTERPRETATION_VS_COMPILATION = false;
66     private static final String COMPUTATION_METHOD_NAME = "main";
67     
68     private final RuntimeEnvironment runtimeEnvironment;
69     private final String expressionText;
70     private Expression expression;
71     private Type expressionType;
72     
73     private Type expectedEffect;
74     private boolean decorateExpression;
75     private Type expectedType;
76     private LocalEnvironment localEnvironment;
77     private LocalStorage localStorage;
78     private boolean interpretIfPossible = true;
79     private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION;
80     private boolean validateOnly;
81     
82     public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
83             String expressionText) {
84         if(runtimeEnvironment == null)
85             throw new NullPointerException();
86         if(expressionText == null)
87             throw new NullPointerException();
88         this.runtimeEnvironment = runtimeEnvironment;
89         this.expressionText = expressionText;
90     }
91     
92     public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
93             LocalStorage localStorage, Expression expression) {
94         if(runtimeEnvironment == null)
95             throw new NullPointerException();
96         if(expression == null)
97             throw new NullPointerException();
98         this.runtimeEnvironment = runtimeEnvironment;
99         this.localStorage = localStorage;
100         this.expressionText = null;
101         this.expression = expression;
102     }
103     
104     public ExpressionEvaluator expectedEffect(Type expectedEffect) {
105         this.expectedEffect = expectedEffect;
106         return this;
107     }
108     
109     public ExpressionEvaluator decorateExpression(boolean decorateExpression) {
110         this.decorateExpression = decorateExpression;
111         return this;
112     }
113     
114     public ExpressionEvaluator expectedType(Type expectedType) {
115         this.expectedType = expectedType;
116         return this;
117     }
118     
119     public ExpressionEvaluator validateOnly(boolean validateOnly) {
120         this.validateOnly = validateOnly;
121         return this;
122     }
123     
124     /**
125      * Sets a local environment that can arbitrarily modify the resolving of the expression.
126      */
127     public ExpressionEvaluator localEnvironment(LocalEnvironment localEnvironment) {
128         this.localEnvironment = localEnvironment;
129         return this;
130     }
131     
132     /**
133      * Evaluates the expression by interpretation instead of compilation to bytecode
134      * if the expression does not contain language constructs that interpretation does
135      * not support.
136      */
137     public ExpressionEvaluator interpretIfPossible(boolean interpretIfPossible) {
138         this.interpretIfPossible = interpretIfPossible;
139         return this;
140     }
141     
142     /**
143      * Assumes that top level of the expression is similar to the content
144      * of a do-block.
145      */
146     public ExpressionEvaluator parseAsBlock(boolean parseAsBlock) {
147         this.parseMode = parseAsBlock ? ExpressionParseMode.BLOCK : ExpressionParseMode.EXPRESSION;
148         return this;
149     }
150     
151     public ExpressionEvaluator parseModel(ExpressionParseMode parseMode) {
152         this.parseMode = parseMode;
153         return this;
154     }
155     
156     private void fillDefaults() {
157         if(expectedEffect == null)
158             expectedEffect = Types.metaVar(Kinds.EFFECT);
159         if(expectedType == null)
160             expectedType = Types.metaVar(Kinds.STAR);
161     }
162     
163     private static class StoreFunction extends FunctionImpl1<Object, Object> {
164         final LocalStorage storage;
165         final String name;
166         final Type type;
167         public StoreFunction(LocalStorage storage, String name, Type type) {
168             this.storage = storage;
169             this.name = name;
170             this.type = type;
171         }
172         @Override
173         public Object apply(Object value) {
174             Type type = Types.closure(this.type.convertMetaVarsToVars());
175             storage.store(name, value, type);
176             return Tuple0.INSTANCE;
177         }
178         
179         @Override
180         public String toString() {
181             return "store_" + name;
182         }
183     }
184     
185     public CompilationError[] validate() {
186         try {
187             validateOnly = true;
188             eval();
189             return CompilationError.EMPTY_ARRAY;
190         } catch(SCLExpressionCompilationException e) {
191             return e.getErrors();
192         }
193     }
194
195     public Object eval() throws SCLExpressionCompilationException {
196         fillDefaults();
197         
198         final CompilationContext compilationContext = new CompilationContext();
199         final ErrorLog errorLog = compilationContext.errorLog;
200         final Environment environment = runtimeEnvironment.getEnvironment();
201         compilationContext.environment = environment;
202         
203         // Parse expression
204         if(expressionText != null) {
205             try {
206                 switch(parseMode) {
207                 case BLOCK: {
208                     SCLBlockParser parser = new SCLBlockParser(new StringReader(expressionText));
209                     parser.parseCommands();
210                     expression = parser.block;
211                 } break;
212                 case EXPRESSION: {
213                     SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
214                     expression = (Expression)parser.parseExp();
215                 } break;
216                 case EQUATION_BLOCK: {
217                     SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
218                     SCLParserOptions parserOptions = new SCLParserOptions();
219                     parserOptions.supportEq = true;
220                     parser.setParserOptions(parserOptions);
221                     expression = (Expression)parser.parseEquationBlock();
222                 } break;
223                 }
224             } catch(SCLSyntaxErrorException e) {
225                 errorLog.log(e.location, e.getMessage());
226                 //System.out.println(errorLog.getErrorsAsString());
227                 throw new SCLExpressionCompilationException(errorLog.getErrors());
228             } catch(Exception e) {
229                 errorLog.log(e);
230                 throw new SCLExpressionCompilationException(errorLog.getErrors());
231             }
232         }
233         
234         // Store local variables
235         ArrayList<Type> lvTypes = new ArrayList<Type>(); 
236         if(expression instanceof EBlock) {
237             EBlock block = (EBlock)expression;
238             if(localStorage != null && !(block.getLast() instanceof GuardStatement)) {
239                 THashSet<String> localVariables = new THashSet<String>();
240                 ListIterator<Statement> it = block.getStatements().listIterator();
241                 while(it.hasNext()) {
242                     Statement stat = it.next();
243                     if(!(stat instanceof LetStatement))
244                         continue;
245                     String variableName;
246                     try {
247                         variableName = ((LetStatement)stat).pattern.getPatternHead().name;
248                     } catch (NotPatternException e) {
249                         continue;
250                     }
251                     localVariables.add(variableName);
252                 }
253                 for(String variableName : localVariables) {
254                     Type type = Types.metaVar(Kinds.STAR);
255                     lvTypes.add(type);
256                     block.addStatement(new GuardStatement(new EApply(
257                             new EExternalConstant(
258                                     new StoreFunction(localStorage, variableName, type),
259                                     Types.functionE(type, Types.PROC, Types.UNIT)),
260                                     new EVar(variableName)
261                             )));
262                     if(validateOnly)
263                         localStorage.store(variableName, null, type);
264                 }
265             }
266             if(!(block.getLast() instanceof GuardStatement))
267                 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
268         }
269         
270         // Elaboration
271         {
272             TranslationContext context = new TranslationContext(compilationContext, localEnvironment, "expression");
273             expression = expression.resolve(context);
274             if(!errorLog.hasNoErrors())
275                 throw new SCLExpressionCompilationException(errorLog.getErrors());
276         }
277         
278         // Apply local environment
279         if(localEnvironment != null) {
280             expression = localEnvironment.preDecorateExpression(expression);
281             ProcedureType procedureType = localEnvironment.decorateExpectedType(expectedType, expectedEffect);
282             expectedType = procedureType.type;
283             expectedEffect = procedureType.effect;
284         }
285         
286         // Type checking
287         {
288             TypingContext context = new TypingContext(compilationContext);
289
290             context.pushEffectUpperBound(expression.location, expectedEffect);
291             expression = expression.checkType(context, expectedType);
292             context.popEffectUpperBound();
293
294             for(Type lvType : lvTypes)
295                 lvType.addPolarity(Polarity.POSITIVE);
296             
297             expectedType.addPolarity(Polarity.POSITIVE);
298             context.solveSubsumptions(expression.location);
299             if(!errorLog.hasNoErrors())
300                 throw new SCLExpressionCompilationException(errorLog.getErrors());
301             if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
302                 ToplevelEffectDecorator decorator =
303                         new ToplevelEffectDecorator(errorLog, environment);
304                 expression = expression.accept(decorator);
305             }
306             expression = context.solveConstraints(environment, expression);
307             expressionType = expression.getType();
308             
309             if(!errorLog.hasNoErrors())
310                 throw new SCLExpressionCompilationException(errorLog.getErrors());
311
312             if(localEnvironment != null)
313                 expression = localEnvironment.postDecorateExpression(expression);
314             
315             if(validateOnly)
316                 return null;
317
318             Type type = expression.getType();
319             type = type.convertMetaVarsToVars();
320             
321             for(Type lvType : lvTypes)
322                 lvType.convertMetaVarsToVars();
323             
324             ArrayList<TVar> varsList = Types.freeVars(type);
325             expression = expression.closure(varsList.toArray(new TVar[varsList.size()]));
326         }
327         
328         // Initialize code generation
329         MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
330         String moduleName = classLoader.getFreshPackageName();
331         JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
332         compilationContext.javaTypeTranslator = javaTypeTranslator;
333         JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
334         compilationContext.namingPolicy = namingPolicy;
335
336         ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
337         
338         // Simplify
339         SimplificationContext context = 
340                 new SimplificationContext(compilationContext, DummyJavaReferenceValidator.INSTANCE);
341         expression = expression.simplify(context);
342         
343         if(!errorLog.hasNoErrors())
344             throw new SCLExpressionCompilationException(errorLog.getErrors());
345         
346         if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
347             System.out.println(expression);
348         
349         if(interpretIfPossible) {
350         // Try to interpret
351         try {
352             ExpressionInterpretationContext expressionInterpretationContext =
353                     new ExpressionInterpretationContext(runtimeEnvironment, 
354                             new TransientClassBuilder(classLoader, javaTypeTranslator));
355             IExpression iexp = expression.toIExpression(expressionInterpretationContext);
356                 if(TRACE_INTERPRETATION_VS_COMPILATION)
357                 System.out.println("INTERPRETED " + expressionText);
358                 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
359                     System.out.println("INTERPRETED AS: " + iexp);
360             return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
361         } catch(UnsupportedOperationException e) {
362             // This is normal when expression cannot be interpreted. We compile it instead.
363         }
364         }
365         
366         // Convert to SSA
367         ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
368         DecomposedExpression decomposed = 
369                 DecomposedExpression.decompose(errorLog, expression);
370
371         SCLConstant constant = new SCLConstant(
372                 Name.create(moduleName, COMPUTATION_METHOD_NAME),
373                 expression.getType());
374         constant.setBase(new JavaStaticMethod(
375                 moduleName, COMPUTATION_METHOD_NAME,
376                 decomposed.effect,
377                 decomposed.typeParameters,
378                 decomposed.returnType, 
379                 decomposed.parameterTypes));
380         try {
381             CodeWriter w = mw.createFunction(constant,
382                     decomposed.typeParameters,
383                     decomposed.effect,
384                     decomposed.returnType, 
385                     decomposed.parameterTypes);
386             constant.setDefinition(w.getFunction());
387             IVal[] parameterVals = w.getParameters();
388             for(int i=0;i<decomposed.parameters.length;++i)
389                 decomposed.parameters[i].setVal(parameterVals[i]);
390             w.return_(decomposed.body.toVal(compilationContext, w));
391         } catch(RuntimeException e) {
392             errorLog.setExceptionPosition(expression.location);
393             throw new SCLExpressionCompilationException(errorLog.getErrors());
394         }
395
396         SSAModule ssaModule = mw.getModule();
397         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
398             System.out.println("=== SSA before optimization ==================================");
399             System.out.println(ssaModule);            
400         }
401         if(SCLCompilerConfiguration.DEBUG)
402             ssaModule.validate();
403
404         ExternalConstant[] externalConstants = mw.getExternalConstants();
405         
406         // Optimize SSA
407         for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
408             int optCount = 0;
409             while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
410                 //System.out.println("simplify " + optCount);
411             }
412         }
413         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
414             System.out.println("=== SSA before lambda lifting ==================================");
415             System.out.println(ssaModule);            
416         }
417         //ssaModule.saveInlinableDefinitions();
418         ssaModule.lambdaLift(errorLog);
419         //ssaModule.validate();
420         ssaModule.markGenerateOnFly();
421         
422         // Generate code
423         if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
424             System.out.println(ssaModule);
425         try {
426             ssaModule.generateCode(moduleBuilder);
427         } catch (CodeBuildingException e) {
428             errorLog.log(e);
429             throw new SCLExpressionCompilationException(errorLog.getErrors());
430         }
431         Map<String, byte[]> classes = moduleBuilder.getClasses();
432         ssaModule.cleanup();
433         
434         // Load generated code and execute
435         try {
436             classLoader.addClasses(classes);
437             Class<?> clazz = classLoader.loadClass(MutableClassLoader.SCL_PACKAGE_PREFIX + moduleName);
438             for(ExternalConstant externalConstant : externalConstants)
439                 clazz.getField(externalConstant.fieldName).set(null, externalConstant.value);
440             for(Method method : clazz.getMethods()) {
441                 if(method.getName().equals(COMPUTATION_METHOD_NAME))
442                     return ValueFromMethod.getValueFromStaticMethod(method);
443             }
444             errorLog.log("Internal compiler error: didn't find method " +
445                     COMPUTATION_METHOD_NAME + " from generated byte code.");
446             throw new SCLExpressionCompilationException(errorLog.getErrors());
447         } catch(ReflectiveOperationException e) {
448             errorLog.log(e);
449             throw new SCLExpressionCompilationException(errorLog.getErrors());
450         }
451     }
452
453     public Type getType() {
454         return expressionType;
455     }
456
457     public String getExpressionText() {
458         return expressionText;
459     }
460     
461 }