]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
(refs #7278, refs #7279) Small fixes to InternalCompilerExceptions
[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.elaboration.utils.ExpressionDecorator;
46 import org.simantics.scl.compiler.internal.interpreted.IExpression;
47 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
48 import org.simantics.scl.compiler.internal.parsing.parser.SCLBlockParser;
49 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
50 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions;
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             try {
207                 switch(parseMode) {
208                 case BLOCK: {
209                     SCLBlockParser parser = new SCLBlockParser(new StringReader(expressionText));
210                     parser.parseCommands();
211                     expression = parser.block;
212                 } break;
213                 case EXPRESSION: {
214                     SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
215                     expression = (Expression)parser.parseExp();
216                 } break;
217                 case EQUATION_BLOCK: {
218                     SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
219                     SCLParserOptions parserOptions = new SCLParserOptions();
220                     parserOptions.supportEq = true;
221                     parser.setParserOptions(parserOptions);
222                     expression = (Expression)parser.parseEquationBlock();
223                 } break;
224                 }
225             } catch(SCLSyntaxErrorException e) {
226                 errorLog.log(e.location, e.getMessage());
227                 //System.out.println(errorLog.getErrorsAsString());
228                 throw new SCLExpressionCompilationException(errorLog.getErrors());
229             } catch(Exception e) {
230                 errorLog.log(e);
231                 throw new SCLExpressionCompilationException(errorLog.getErrors());
232             }
233         }
234         
235         // Store local variables
236         ArrayList<Type> lvTypes = new ArrayList<Type>(); 
237         if(expression instanceof EBlock) {
238             EBlock block = (EBlock)expression;
239             if(localStorage != null && !(block.getLast() instanceof GuardStatement)) {
240                 THashSet<String> localVariables = new THashSet<String>();
241                 ListIterator<Statement> it = block.getStatements().listIterator();
242                 while(it.hasNext()) {
243                     Statement stat = it.next();
244                     if(!(stat instanceof LetStatement))
245                         continue;
246                     String variableName;
247                     try {
248                         variableName = ((LetStatement)stat).pattern.getPatternHead().name;
249                     } catch (NotPatternException e) {
250                         continue;
251                     }
252                     localVariables.add(variableName);
253                 }
254                 for(String variableName : localVariables) {
255                     Type type = Types.metaVar(Kinds.STAR);
256                     lvTypes.add(type);
257                     block.addStatement(new GuardStatement(new EApply(
258                             new EExternalConstant(
259                                     new StoreFunction(localStorage, variableName, type),
260                                     Types.functionE(type, Types.PROC, Types.UNIT)),
261                                     new EVar(variableName)
262                             )));
263                     if(validateOnly)
264                         localStorage.store(variableName, null, type);
265                 }
266             }
267             if(!(block.getLast() instanceof GuardStatement))
268                 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
269         }
270         
271         // Elaboration
272         {
273             TranslationContext context = new TranslationContext(compilationContext, localEnvironment);
274             expression = expression.resolve(context);
275             if(!errorLog.hasNoErrors())
276                 throw new SCLExpressionCompilationException(errorLog.getErrors());
277         }
278         
279         // Apply local environment
280         if(localEnvironment != null) {
281             expression = localEnvironment.preDecorateExpression(expression);
282             ProcedureType procedureType = localEnvironment.decorateExpectedType(expectedType, expectedEffect);
283             expectedType = procedureType.type;
284             expectedEffect = procedureType.effect;
285         }
286         
287         // Type checking
288         {
289             TypingContext context = new TypingContext(compilationContext);
290
291             context.pushEffectUpperBound(expression.location, expectedEffect);
292             expression = expression.checkType(context, expectedType);
293             context.popEffectUpperBound();
294
295             for(Type lvType : lvTypes)
296                 lvType.addPolarity(Polarity.POSITIVE);
297             
298             expectedType.addPolarity(Polarity.POSITIVE);
299             context.solveSubsumptions(expression.location);
300             if(!errorLog.hasNoErrors())
301                 throw new SCLExpressionCompilationException(errorLog.getErrors());
302             if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
303                 ExpressionDecorator decorator =
304                         new ToplevelEffectDecorator(errorLog, environment);
305                 expression = expression.decorate(decorator);
306             }
307             expression = context.solveConstraints(environment, expression);
308             expressionType = expression.getType();
309             
310             if(!errorLog.hasNoErrors())
311                 throw new SCLExpressionCompilationException(errorLog.getErrors());
312
313             if(localEnvironment != null)
314                 expression = localEnvironment.postDecorateExpression(expression);
315             
316             if(validateOnly)
317                 return null;
318
319             Type type = expression.getType();
320             type = type.convertMetaVarsToVars();
321             
322             for(Type lvType : lvTypes)
323                 lvType.convertMetaVarsToVars();
324             
325             ArrayList<TVar> varsList = Types.freeVars(type);
326             expression = expression.closure(varsList.toArray(new TVar[varsList.size()]));
327         }
328         
329         // Initialize code generation
330         MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
331         String moduleName = classLoader.getFreshPackageName();
332         JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
333         compilationContext.javaTypeTranslator = javaTypeTranslator;
334         JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
335         compilationContext.namingPolicy = namingPolicy;
336
337         ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
338         
339         // Simplify
340         SimplificationContext context = 
341                 new SimplificationContext(compilationContext, DummyJavaReferenceValidator.INSTANCE);
342         expression = expression.simplify(context);
343         
344         if(!errorLog.hasNoErrors())
345             throw new SCLExpressionCompilationException(errorLog.getErrors());
346         
347         if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
348             System.out.println(expression);
349         
350         if(interpretIfPossible) {
351         // Try to interpret
352         try {
353             ExpressionInterpretationContext expressionInterpretationContext =
354                     new ExpressionInterpretationContext(runtimeEnvironment, 
355                             new TransientClassBuilder(classLoader, javaTypeTranslator));
356             IExpression iexp = expression.toIExpression(expressionInterpretationContext);
357                 if(TRACE_INTERPRETATION_VS_COMPILATION)
358                 System.out.println("INTERPRETED " + expressionText);
359                 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
360                     System.out.println("INTERPRETED AS: " + iexp);
361             return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
362         } catch(UnsupportedOperationException e) {
363             // This is normal when expression cannot be interpreted. We compile it instead.
364         }
365         }
366         
367         // Convert to SSA
368         ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
369         DecomposedExpression decomposed = 
370                 DecomposedExpression.decompose(errorLog, expression);
371
372         SCLConstant constant = new SCLConstant(
373                 Name.create(moduleName, COMPUTATION_METHOD_NAME),
374                 expression.getType());
375         constant.setBase(new JavaStaticMethod(
376                 moduleName, COMPUTATION_METHOD_NAME,
377                 decomposed.effect,
378                 decomposed.typeParameters,
379                 decomposed.returnType, 
380                 decomposed.parameterTypes));
381         try {
382             CodeWriter w = mw.createFunction(constant,
383                     decomposed.typeParameters,
384                     decomposed.effect,
385                     decomposed.returnType, 
386                     decomposed.parameterTypes);
387             constant.setDefinition(w.getFunction());
388             IVal[] parameterVals = w.getParameters();
389             for(int i=0;i<decomposed.parameters.length;++i)
390                 decomposed.parameters[i].setVal(parameterVals[i]);
391             w.return_(decomposed.body.toVal(compilationContext, w));
392         } catch(RuntimeException e) {
393             errorLog.setExceptionPosition(expression.location);
394             throw new SCLExpressionCompilationException(errorLog.getErrors());
395         }
396
397         SSAModule ssaModule = mw.getModule();
398         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
399             System.out.println("=== SSA before optimization ==================================");
400             System.out.println(ssaModule);            
401         }
402         if(SCLCompilerConfiguration.DEBUG)
403             ssaModule.validate();
404
405         ExternalConstant[] externalConstants = mw.getExternalConstants();
406         
407         // Optimize SSA
408         for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
409             int optCount = 0;
410             while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
411                 //System.out.println("simplify " + optCount);
412             }
413         }
414         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
415             System.out.println("=== SSA before lambda lifting ==================================");
416             System.out.println(ssaModule);            
417         }
418         //ssaModule.saveInlinableDefinitions();
419         ssaModule.lambdaLift(errorLog);
420         //ssaModule.validate();
421         ssaModule.markGenerateOnFly();
422         
423         // Generate code
424         if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
425             System.out.println(ssaModule);
426         try {
427             ssaModule.generateCode(moduleBuilder);
428         } catch (CodeBuildingException e) {
429             errorLog.log(e);
430             throw new SCLExpressionCompilationException(errorLog.getErrors());
431         }
432         Map<String, byte[]> classes = moduleBuilder.getClasses();
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 }