1 package org.simantics.scl.compiler.top;
3 import java.io.StringReader;
4 import java.lang.reflect.Method;
5 import java.util.ArrayList;
6 import java.util.ListIterator;
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.ErrorLog;
31 import org.simantics.scl.compiler.internal.codegen.references.IVal;
32 import org.simantics.scl.compiler.internal.codegen.ssa.SSAModule;
33 import org.simantics.scl.compiler.internal.codegen.types.DummyJavaReferenceValidator;
34 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
35 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuildingException;
36 import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
37 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
38 import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder;
39 import org.simantics.scl.compiler.internal.codegen.utils.ValueFromMethod;
40 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
41 import org.simantics.scl.compiler.internal.codegen.writer.ExternalConstant;
42 import org.simantics.scl.compiler.internal.codegen.writer.ModuleWriter;
43 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
44 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
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;
61 import gnu.trove.set.hash.THashSet;
63 public class ExpressionEvaluator {
65 public static final boolean TRACE_INTERPRETATION_VS_COMPILATION = false;
66 private static final String COMPUTATION_METHOD_NAME = "main";
68 private final RuntimeEnvironment runtimeEnvironment;
69 private final String expressionText;
70 private Expression expression;
71 private Type expressionType;
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;
81 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
82 String expressionText) {
83 if(runtimeEnvironment == null)
84 throw new NullPointerException();
85 if(expressionText == null)
86 throw new NullPointerException();
87 this.runtimeEnvironment = runtimeEnvironment;
88 this.expressionText = expressionText;
91 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
92 LocalStorage localStorage, Expression expression) {
93 if(runtimeEnvironment == null)
94 throw new NullPointerException();
95 if(expression == null)
96 throw new NullPointerException();
97 this.runtimeEnvironment = runtimeEnvironment;
98 this.localStorage = localStorage;
99 this.expressionText = null;
100 this.expression = expression;
103 public ExpressionEvaluator expectedEffect(Type expectedEffect) {
104 this.expectedEffect = expectedEffect;
108 public ExpressionEvaluator decorateExpression(boolean decorateExpression) {
109 this.decorateExpression = decorateExpression;
113 public ExpressionEvaluator expectedType(Type expectedType) {
114 this.expectedType = expectedType;
119 * Sets a local environment that can arbitrarily modify the resolving of the expression.
121 public ExpressionEvaluator localEnvironment(LocalEnvironment localEnvironment) {
122 this.localEnvironment = localEnvironment;
127 * Evaluates the expression by interpretation instead of compilation to bytecode
128 * if the expression does not contain language constructs that interpretation does
131 public ExpressionEvaluator interpretIfPossible(boolean interpretIfPossible) {
132 this.interpretIfPossible = interpretIfPossible;
137 * Assumes that top level of the expression is similar to the content
140 public ExpressionEvaluator parseAsBlock(boolean parseAsBlock) {
141 this.parseMode = parseAsBlock ? ExpressionParseMode.BLOCK : ExpressionParseMode.EXPRESSION;
145 public ExpressionEvaluator parseModel(ExpressionParseMode parseMode) {
146 this.parseMode = parseMode;
150 private void fillDefaults() {
151 if(expectedEffect == null)
152 expectedEffect = Types.metaVar(Kinds.EFFECT);
153 if(expectedType == null)
154 expectedType = Types.metaVar(Kinds.STAR);
157 private static class StoreFunction extends FunctionImpl1<Object, Object> {
158 final LocalStorage storage;
161 public StoreFunction(LocalStorage storage, String name, Type type) {
162 this.storage = storage;
167 public Object apply(Object value) {
168 Type type = Types.closure(this.type.convertMetaVarsToVars());
169 storage.store(name, value, type);
170 return Tuple0.INSTANCE;
174 public String toString() {
175 return "store_" + name;
179 public Object eval() throws SCLExpressionCompilationException {
182 final CompilationContext compilationContext = new CompilationContext();
183 final ErrorLog errorLog = compilationContext.errorLog;
184 final Environment environment = runtimeEnvironment.getEnvironment();
185 compilationContext.environment = environment;
188 if(expressionText != null) {
192 SCLBlockParser parser = new SCLBlockParser(new StringReader(expressionText));
193 parser.parseCommands();
194 expression = parser.block;
197 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
198 expression = (Expression)parser.parseExp();
200 case EQUATION_BLOCK: {
201 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
202 SCLParserOptions parserOptions = new SCLParserOptions();
203 parserOptions.supportEq = true;
204 parser.setParserOptions(parserOptions);
205 expression = (Expression)parser.parseEquationBlock();
208 } catch(SCLSyntaxErrorException e) {
209 errorLog.log(e.location, e.getMessage());
210 //System.out.println(errorLog.getErrorsAsString());
211 throw new SCLExpressionCompilationException(errorLog.getErrors());
212 } catch(Exception e) {
214 throw new SCLExpressionCompilationException(errorLog.getErrors());
218 // Store local variables
219 ArrayList<Type> lvTypes = new ArrayList<Type>();
220 if(expression instanceof EBlock) {
221 EBlock block = (EBlock)expression;
222 if(localStorage != null && !(block.getStatements().getLast() instanceof GuardStatement)) {
223 THashSet<String> localVariables = new THashSet<String>();
224 ListIterator<Statement> it = block.getStatements().listIterator();
225 while(it.hasNext()) {
226 Statement stat = it.next();
227 if(!(stat instanceof LetStatement))
231 variableName = ((LetStatement)stat).pattern.getPatternHead().name;
232 } catch (NotPatternException e) {
235 localVariables.add(variableName);
237 for(String variableName : localVariables) {
238 Type type = Types.metaVar(Kinds.STAR);
240 block.addStatement(new GuardStatement(new EApply(
241 new EExternalConstant(
242 new StoreFunction(localStorage, variableName, type),
243 Types.functionE(type, Types.PROC, Types.UNIT)),
244 new EVar(variableName)
248 if(!(block.getStatements().getLast() instanceof GuardStatement))
249 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
254 TranslationContext context = new TranslationContext(compilationContext, localEnvironment);
255 expression = expression.resolve(context);
256 if(!errorLog.isEmpty())
257 throw new SCLExpressionCompilationException(errorLog.getErrors());
260 // Apply local environment
261 if(localEnvironment != null) {
262 expression = localEnvironment.preDecorateExpression(expression);
263 ProcedureType procedureType = localEnvironment.decorateExpectedType(expectedType, expectedEffect);
264 expectedType = procedureType.type;
265 expectedEffect = procedureType.effect;
270 TypingContext context = new TypingContext(compilationContext);
272 context.pushEffectUpperBound(expression.location, expectedEffect);
273 expression = expression.checkType(context, expectedType);
274 context.popEffectUpperBound();
276 for(Type lvType : lvTypes)
277 lvType.addPolarity(Polarity.POSITIVE);
279 expectedType.addPolarity(Polarity.POSITIVE);
280 context.solveSubsumptions(expression.location);
281 if(!errorLog.isEmpty())
282 throw new SCLExpressionCompilationException(errorLog.getErrors());
283 if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
284 ExpressionDecorator decorator =
285 new ToplevelEffectDecorator(errorLog, environment);
286 expression = expression.decorate(decorator);
288 expression = context.solveConstraints(environment, expression);
289 expressionType = expression.getType();
291 if(!errorLog.isEmpty())
292 throw new SCLExpressionCompilationException(errorLog.getErrors());
294 if(localEnvironment != null)
295 expression = localEnvironment.postDecorateExpression(expression);
297 Type type = expression.getType();
298 type = type.convertMetaVarsToVars();
300 for(Type lvType : lvTypes)
301 lvType.convertMetaVarsToVars();
303 ArrayList<TVar> varsList = Types.freeVars(type);
304 expression = expression.closure(varsList.toArray(new TVar[varsList.size()]));
307 // Initialize code generation
308 MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
309 String moduleName = classLoader.getFreshPackageName();
310 JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
311 compilationContext.javaTypeTranslator = javaTypeTranslator;
312 JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
313 compilationContext.namingPolicy = namingPolicy;
315 ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
318 SimplificationContext context =
319 new SimplificationContext(compilationContext, DummyJavaReferenceValidator.INSTANCE);
320 expression = expression.simplify(context);
322 if(!errorLog.isEmpty())
323 throw new SCLExpressionCompilationException(errorLog.getErrors());
325 if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
326 System.out.println(expression);
328 if(interpretIfPossible) {
331 ExpressionInterpretationContext expressionInterpretationContext =
332 new ExpressionInterpretationContext(runtimeEnvironment,
333 new TransientClassBuilder(classLoader, javaTypeTranslator));
334 IExpression iexp = expression.toIExpression(expressionInterpretationContext);
335 if(TRACE_INTERPRETATION_VS_COMPILATION)
336 System.out.println("INTERPRETED " + expressionText);
337 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
338 System.out.println("INTERPRETED AS: " + iexp);
339 return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
340 } catch(UnsupportedOperationException e) {
341 // This is normal when expression cannot be interpreted. We compile it instead.
346 ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
347 DecomposedExpression decomposed =
348 DecomposedExpression.decompose(expression);
350 SCLConstant constant = new SCLConstant(
351 Name.create(moduleName, COMPUTATION_METHOD_NAME),
352 expression.getType());
353 constant.setBase(new JavaStaticMethod(
354 moduleName, COMPUTATION_METHOD_NAME,
356 decomposed.typeParameters,
357 decomposed.returnType,
358 decomposed.parameterTypes));
360 CodeWriter w = mw.createFunction(constant,
361 decomposed.typeParameters,
363 decomposed.returnType,
364 decomposed.parameterTypes);
365 constant.setDefinition(w.getFunction());
366 IVal[] parameterVals = w.getParameters();
367 for(int i=0;i<decomposed.parameters.length;++i)
368 decomposed.parameters[i].setVal(parameterVals[i]);
369 w.return_(decomposed.body.toVal(environment, w));
370 } catch(RuntimeException e) {
371 errorLog.setExceptionPosition(expression.location);
372 throw new SCLExpressionCompilationException(errorLog.getErrors());
375 SSAModule ssaModule = mw.getModule();
376 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
377 System.out.println("=== SSA before optimization ==================================");
378 System.out.println(ssaModule);
380 if(SCLCompilerConfiguration.DEBUG)
381 ssaModule.validate();
383 ExternalConstant[] externalConstants = mw.getExternalConstants();
386 for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
388 while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
389 //System.out.println("simplify " + optCount);
392 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
393 System.out.println("=== SSA before lambda lifting ==================================");
394 System.out.println(ssaModule);
396 //ssaModule.saveInlinableDefinitions();
397 ssaModule.lambdaLift(errorLog);
398 //ssaModule.validate();
399 ssaModule.markGenerateOnFly();
402 if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
403 System.out.println(ssaModule);
405 ssaModule.generateCode(moduleBuilder);
406 } catch (CodeBuildingException e) {
408 throw new SCLExpressionCompilationException(errorLog.getErrors());
410 Map<String, byte[]> classes = moduleBuilder.getClasses();
412 // Load generated code and execute
414 classLoader.addClasses(classes);
415 Class<?> clazz = classLoader.loadClass(MutableClassLoader.SCL_PACKAGE_PREFIX + moduleName);
416 for(ExternalConstant externalConstant : externalConstants)
417 clazz.getField(externalConstant.fieldName).set(null, externalConstant.value);
418 for(Method method : clazz.getMethods()) {
419 if(method.getName().equals(COMPUTATION_METHOD_NAME))
420 return ValueFromMethod.getValueFromStaticMethod(method);
422 errorLog.log("Internal compiler error: didn't find method " +
423 COMPUTATION_METHOD_NAME + " from generated byte code.");
424 throw new SCLExpressionCompilationException(errorLog.getErrors());
425 } catch(ReflectiveOperationException e) {
427 throw new SCLExpressionCompilationException(errorLog.getErrors());
431 public Type getType() {
432 return expressionType;
435 public String getExpressionText() {
436 return expressionText;