1 package org.simantics.scl.compiler.top;
3 import gnu.trove.set.hash.THashSet;
5 import java.io.StringReader;
6 import java.lang.reflect.Method;
7 import java.util.ArrayList;
8 import java.util.ListIterator;
11 import org.simantics.scl.compiler.common.names.Name;
12 import org.simantics.scl.compiler.compilation.CodeGeneration;
13 import org.simantics.scl.compiler.constants.JavaStaticMethod;
14 import org.simantics.scl.compiler.constants.SCLConstant;
15 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
16 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
17 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
18 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
19 import org.simantics.scl.compiler.elaboration.expressions.EApply;
20 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
21 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
22 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
23 import org.simantics.scl.compiler.elaboration.expressions.EVar;
24 import org.simantics.scl.compiler.elaboration.expressions.Expression;
25 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
26 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
27 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
28 import org.simantics.scl.compiler.elaboration.java.Builtins;
29 import org.simantics.scl.compiler.environment.Environment;
30 import org.simantics.scl.compiler.environment.LocalEnvironment;
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;
62 public class ExpressionEvaluator {
64 public static final boolean TRACE_INTERPRETATION_VS_COMPILATION = false;
65 private static final String COMPUTATION_METHOD_NAME = "main";
67 private final RuntimeEnvironment runtimeEnvironment;
68 private final String expressionText;
69 private Expression expression;
70 private Type expressionType;
72 private Type expectedEffect;
73 private boolean decorateExpression;
74 private Type expectedType;
75 private LocalEnvironment localEnvironment;
76 private LocalStorage localStorage;
77 private boolean interpretIfPossible = true;
78 private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION;
80 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
81 String expressionText) {
82 if(runtimeEnvironment == null)
83 throw new NullPointerException();
84 if(expressionText == null)
85 throw new NullPointerException();
86 this.runtimeEnvironment = runtimeEnvironment;
87 this.expressionText = expressionText;
90 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
91 LocalStorage localStorage, Expression expression) {
92 if(runtimeEnvironment == null)
93 throw new NullPointerException();
94 if(expression == null)
95 throw new NullPointerException();
96 this.runtimeEnvironment = runtimeEnvironment;
97 this.localStorage = localStorage;
98 this.expressionText = null;
99 this.expression = expression;
102 public ExpressionEvaluator expectedEffect(Type expectedEffect) {
103 this.expectedEffect = expectedEffect;
107 public ExpressionEvaluator decorateExpression(boolean decorateExpression) {
108 this.decorateExpression = decorateExpression;
112 public ExpressionEvaluator expectedType(Type expectedType) {
113 this.expectedType = expectedType;
118 * Sets a local environment that can arbitrarily modify the resolving of the expression.
120 public ExpressionEvaluator localEnvironment(LocalEnvironment localEnvironment) {
121 this.localEnvironment = localEnvironment;
126 * Evaluates the expression by interpretation instead of compilation to bytecode
127 * if the expression does not contain language constructs that interpretation does
130 public ExpressionEvaluator interpretIfPossible(boolean interpretIfPossible) {
131 this.interpretIfPossible = interpretIfPossible;
136 * Assumes that top level of the expression is similar to the content
139 public ExpressionEvaluator parseAsBlock(boolean parseAsBlock) {
140 this.parseMode = parseAsBlock ? ExpressionParseMode.BLOCK : ExpressionParseMode.EXPRESSION;
144 public ExpressionEvaluator parseModel(ExpressionParseMode parseMode) {
145 this.parseMode = parseMode;
149 private void fillDefaults() {
150 if(expectedEffect == null)
151 expectedEffect = Types.metaVar(Kinds.EFFECT);
152 if(expectedType == null)
153 expectedType = Types.metaVar(Kinds.STAR);
156 private static class StoreFunction extends FunctionImpl1<Object, Object> {
157 final LocalStorage storage;
160 public StoreFunction(LocalStorage storage, String name, Type type) {
161 this.storage = storage;
166 public Object apply(Object value) {
167 Type type = Types.closure(this.type.convertMetaVarsToVars());
168 storage.store(name, value, type);
169 return Tuple0.INSTANCE;
173 public String toString() {
174 return "store_" + name;
178 public Object eval() throws SCLExpressionCompilationException {
181 final ErrorLog errorLog = new ErrorLog();
182 final Environment environment = runtimeEnvironment.getEnvironment();
185 if(expressionText != null) {
189 SCLBlockParser parser = new SCLBlockParser(new StringReader(expressionText));
190 parser.parseCommands();
191 expression = parser.block;
194 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
195 expression = (Expression)parser.parseExp();
197 case EQUATION_BLOCK: {
198 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
199 SCLParserOptions parserOptions = new SCLParserOptions();
200 parserOptions.supportEq = true;
201 parser.setParserOptions(parserOptions);
202 expression = (Expression)parser.parseEquationBlock();
205 } catch(SCLSyntaxErrorException e) {
206 errorLog.log(e.location, e.getMessage());
207 //System.out.println(errorLog.getErrorsAsString());
208 throw new SCLExpressionCompilationException(errorLog.getErrors());
209 } catch(Exception e) {
211 throw new SCLExpressionCompilationException(errorLog.getErrors());
215 // Store local variables
216 ArrayList<Type> lvTypes = new ArrayList<Type>();
217 if(expression instanceof EBlock) {
218 EBlock block = (EBlock)expression;
219 if(localStorage != null && !(block.getStatements().getLast() instanceof GuardStatement)) {
220 THashSet<String> localVariables = new THashSet<String>();
221 ListIterator<Statement> it = block.getStatements().listIterator();
222 while(it.hasNext()) {
223 Statement stat = it.next();
224 if(!(stat instanceof LetStatement))
228 variableName = ((LetStatement)stat).pattern.getPatternHead().name;
229 } catch (NotPatternException e) {
232 localVariables.add(variableName);
234 for(String variableName : localVariables) {
235 Type type = Types.metaVar(Kinds.STAR);
237 block.addStatement(new GuardStatement(new EApply(
238 new EExternalConstant(
239 new StoreFunction(localStorage, variableName, type),
240 Types.functionE(type, Types.PROC, Types.UNIT)),
241 new EVar(variableName)
245 if(!(block.getStatements().getLast() instanceof GuardStatement))
246 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
251 TranslationContext context = new TranslationContext(errorLog,
252 environment, localEnvironment);
253 expression = expression.resolve(context);
254 if(!errorLog.isEmpty())
255 throw new SCLExpressionCompilationException(errorLog.getErrors());
258 // Apply local environment
259 if(localEnvironment != null) {
260 expression = localEnvironment.preDecorateExpression(expression);
261 ProcedureType procedureType = localEnvironment.decorateExpectedType(expectedType, expectedEffect);
262 expectedType = procedureType.type;
263 expectedEffect = procedureType.effect;
268 TypingContext context = new TypingContext(errorLog, environment);
270 context.pushEffectUpperBound(expression.location, expectedEffect);
271 expression = expression.checkType(context, expectedType);
272 context.popEffectUpperBound();
274 for(Type lvType : lvTypes)
275 lvType.addPolarity(Polarity.POSITIVE);
277 expectedType.addPolarity(Polarity.POSITIVE);
278 context.solveSubsumptions(expression.location);
279 if(!errorLog.isEmpty())
280 throw new SCLExpressionCompilationException(errorLog.getErrors());
281 if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
282 ExpressionDecorator decorator =
283 new ToplevelEffectDecorator(errorLog, environment);
284 expression = expression.decorate(decorator);
286 expression = context.solveConstraints(environment, expression);
287 expressionType = expression.getType();
289 if(!errorLog.isEmpty())
290 throw new SCLExpressionCompilationException(errorLog.getErrors());
292 if(localEnvironment != null)
293 expression = localEnvironment.postDecorateExpression(expression);
295 Type type = expression.getType();
296 type = type.convertMetaVarsToVars();
298 for(Type lvType : lvTypes)
299 lvType.convertMetaVarsToVars();
301 ArrayList<TVar> varsList = Types.freeVars(type);
302 expression = expression.closure(varsList.toArray(new TVar[varsList.size()]));
305 // Initialize code generation
306 MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
307 String moduleName = classLoader.getFreshPackageName();
308 JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
309 JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
311 ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
314 SimplificationContext context =
315 new SimplificationContext(environment, errorLog,
316 javaTypeTranslator, DummyJavaReferenceValidator.INSTANCE);
317 expression = expression.simplify(context);
319 if(!errorLog.isEmpty())
320 throw new SCLExpressionCompilationException(errorLog.getErrors());
322 if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
323 System.out.println(expression);
325 if(interpretIfPossible) {
328 ExpressionInterpretationContext expressionInterpretationContext =
329 new ExpressionInterpretationContext(runtimeEnvironment,
330 new TransientClassBuilder(classLoader, javaTypeTranslator));
331 IExpression iexp = expression.toIExpression(expressionInterpretationContext);
332 if(TRACE_INTERPRETATION_VS_COMPILATION)
333 System.out.println("INTERPRETED " + expressionText);
334 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
335 System.out.println("INTERPRETED AS: " + iexp);
336 return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
337 } catch(UnsupportedOperationException e) {
338 // This is normal when expression cannot be interpreted. We compile it instead.
343 ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
344 DecomposedExpression decomposed =
345 DecomposedExpression.decompose(expression);
347 SCLConstant constant = new SCLConstant(
348 Name.create(moduleName, COMPUTATION_METHOD_NAME),
349 expression.getType());
350 constant.setBase(new JavaStaticMethod(
351 moduleName, COMPUTATION_METHOD_NAME,
353 decomposed.typeParameters,
354 decomposed.returnType,
355 decomposed.parameterTypes));
357 CodeWriter w = mw.createFunction(constant,
358 decomposed.typeParameters,
360 decomposed.returnType,
361 decomposed.parameterTypes);
362 constant.setDefinition(w.getFunction());
363 IVal[] parameterVals = w.getParameters();
364 for(int i=0;i<decomposed.parameters.length;++i)
365 decomposed.parameters[i].setVal(parameterVals[i]);
366 w.return_(decomposed.body.toVal(environment, w));
367 } catch(RuntimeException e) {
368 errorLog.setExceptionPosition(expression.location);
369 throw new SCLExpressionCompilationException(errorLog.getErrors());
372 SSAModule ssaModule = mw.getModule();
373 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
374 System.out.println("=== SSA before optimization ==================================");
375 System.out.println(ssaModule);
377 if(SCLCompilerConfiguration.DEBUG)
378 ssaModule.validate();
380 ExternalConstant[] externalConstants = mw.getExternalConstants();
383 for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
385 while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
386 //System.out.println("simplify " + optCount);
389 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
390 System.out.println("=== SSA before lambda lifting ==================================");
391 System.out.println(ssaModule);
393 //ssaModule.saveInlinableDefinitions();
394 ssaModule.lambdaLift(errorLog);
395 //ssaModule.validate();
396 ssaModule.markGenerateOnFly();
399 if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
400 System.out.println(ssaModule);
402 ssaModule.generateCode(moduleBuilder);
403 } catch (CodeBuildingException e) {
405 throw new SCLExpressionCompilationException(errorLog.getErrors());
407 Map<String, byte[]> classes = moduleBuilder.getClasses();
409 // Load generated code and execute
411 classLoader.addClasses(classes);
412 Class<?> clazz = classLoader.loadClass(MutableClassLoader.SCL_PACKAGE_PREFIX + moduleName);
413 for(ExternalConstant externalConstant : externalConstants)
414 clazz.getField(externalConstant.fieldName).set(null, externalConstant.value);
415 for(Method method : clazz.getMethods()) {
416 if(method.getName().equals(COMPUTATION_METHOD_NAME))
417 return ValueFromMethod.getValueFromStaticMethod(method);
419 errorLog.log("Internal compiler error: didn't find method " +
420 COMPUTATION_METHOD_NAME + " from generated byte code.");
421 throw new SCLExpressionCompilationException(errorLog.getErrors());
422 } catch(ReflectiveOperationException e) {
424 throw new SCLExpressionCompilationException(errorLog.getErrors());
428 public Type getType() {
429 return expressionType;
432 public String getExpressionText() {
433 return expressionText;