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