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.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 import org.slf4j.LoggerFactory;
62 import org.slf4j.Logger;
64 import gnu.trove.set.hash.THashSet;
66 public class ExpressionEvaluator {
68 private static final Logger LOGGER = LoggerFactory.getLogger(ExpressionEvaluator.class);
70 public static final boolean TRACE_INTERPRETATION_VS_COMPILATION = false;
71 private static final String COMPUTATION_METHOD_NAME = "main";
73 private final RuntimeEnvironment runtimeEnvironment;
74 private final String expressionText;
75 private Expression expression;
76 private Type expressionType;
78 private Type expectedEffect;
79 private boolean decorateExpression;
80 private Type expectedType;
81 private LocalEnvironment localEnvironment;
82 private LocalStorage localStorage;
83 private boolean interpretIfPossible = true;
84 private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION;
85 private boolean validateOnly;
87 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
88 String expressionText) {
89 if(runtimeEnvironment == null)
90 throw new NullPointerException();
91 if(expressionText == null)
92 throw new NullPointerException();
93 this.runtimeEnvironment = runtimeEnvironment;
94 this.expressionText = expressionText;
97 public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
98 LocalStorage localStorage, Expression expression) {
99 if(runtimeEnvironment == null)
100 throw new NullPointerException();
101 if(expression == null)
102 throw new NullPointerException();
103 this.runtimeEnvironment = runtimeEnvironment;
104 this.localStorage = localStorage;
105 this.expressionText = null;
106 this.expression = expression;
109 public ExpressionEvaluator expectedEffect(Type expectedEffect) {
110 this.expectedEffect = expectedEffect;
114 public ExpressionEvaluator decorateExpression(boolean decorateExpression) {
115 this.decorateExpression = decorateExpression;
119 public ExpressionEvaluator expectedType(Type expectedType) {
120 this.expectedType = expectedType;
124 public ExpressionEvaluator validateOnly(boolean validateOnly) {
125 this.validateOnly = validateOnly;
130 * Sets a local environment that can arbitrarily modify the resolving of the expression.
132 public ExpressionEvaluator localEnvironment(LocalEnvironment localEnvironment) {
133 this.localEnvironment = localEnvironment;
138 * Evaluates the expression by interpretation instead of compilation to bytecode
139 * if the expression does not contain language constructs that interpretation does
142 public ExpressionEvaluator interpretIfPossible(boolean interpretIfPossible) {
143 this.interpretIfPossible = interpretIfPossible;
148 * Assumes that top level of the expression is similar to the content
151 public ExpressionEvaluator parseAsBlock(boolean parseAsBlock) {
152 this.parseMode = parseAsBlock ? ExpressionParseMode.BLOCK : ExpressionParseMode.EXPRESSION;
156 public ExpressionEvaluator parseModel(ExpressionParseMode parseMode) {
157 this.parseMode = parseMode;
161 private void fillDefaults() {
162 if(expectedEffect == null)
163 expectedEffect = Types.metaVar(Kinds.EFFECT);
164 if(expectedType == null)
165 expectedType = Types.metaVar(Kinds.STAR);
168 private static class StoreFunction extends FunctionImpl1<Object, Object> {
169 final LocalStorage storage;
172 public StoreFunction(LocalStorage storage, String name, Type type) {
173 this.storage = storage;
178 public Object apply(Object value) {
179 Type type = Types.closure(this.type.convertMetaVarsToVars());
180 storage.store(name, value, type);
181 return Tuple0.INSTANCE;
185 public String toString() {
186 return "store_" + name;
190 public CompilationError[] validate() {
194 return CompilationError.EMPTY_ARRAY;
195 } catch(SCLExpressionCompilationException e) {
196 return e.getErrors();
200 public Object eval() throws SCLExpressionCompilationException {
203 final CompilationContext compilationContext = new CompilationContext();
204 final ErrorLog errorLog = compilationContext.errorLog;
205 final Environment environment = runtimeEnvironment.getEnvironment();
206 compilationContext.environment = environment;
209 if(expressionText != null) {
210 compilationContext.lineLocator = LineLocators.createLineLocator(expressionText);
214 SCLBlockParser parser = new SCLBlockParser(new StringReader(expressionText));
215 parser.parseCommands();
216 expression = parser.block;
219 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
220 expression = (Expression)parser.parseExp();
222 case EQUATION_BLOCK: {
223 SCLParserImpl parser = new SCLParserImpl(new StringReader(expressionText));
224 SCLParserOptions parserOptions = new SCLParserOptions();
225 parserOptions.supportEq = true;
226 parser.setParserOptions(parserOptions);
227 expression = (Expression)parser.parseEquationBlock();
230 } catch(SCLSyntaxErrorException e) {
231 errorLog.log(e.location, e.getMessage());
232 //LOGGER.info(errorLog.getErrorsAsString());
233 throw new SCLExpressionCompilationException(errorLog.getErrors());
234 } catch(Exception e) {
236 throw new SCLExpressionCompilationException(errorLog.getErrors());
240 compilationContext.lineLocator = LineLocators.DUMMY_LOCATOR;
242 // Store local variables
243 ArrayList<Type> lvTypes = new ArrayList<Type>();
244 if(expression instanceof EBlock) {
245 EBlock block = (EBlock)expression;
246 if(localStorage != null && !(block.getLast() instanceof GuardStatement)) {
247 THashSet<String> localVariables = new THashSet<String>();
248 ListIterator<Statement> it = block.getStatements().listIterator();
249 while(it.hasNext()) {
250 Statement stat = it.next();
251 if(!(stat instanceof LetStatement))
255 variableName = ((LetStatement)stat).pattern.getPatternHead().name;
256 } catch (NotPatternException e) {
259 localVariables.add(variableName);
261 for(String variableName : localVariables) {
262 Type type = Types.metaVar(Kinds.STAR);
264 block.addStatement(new GuardStatement(new EApply(
265 new EExternalConstant(
266 new StoreFunction(localStorage, variableName, type),
267 Types.functionE(type, Types.PROC, Types.UNIT)),
268 new EVar(variableName)
271 localStorage.store(variableName, null, type);
274 if(!(block.getLast() instanceof GuardStatement))
275 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
280 TranslationContext context = new TranslationContext(compilationContext, localEnvironment, "expression");
281 expression = expression.resolve(context);
282 if(!errorLog.hasNoErrors())
283 throw new SCLExpressionCompilationException(errorLog.getErrors());
286 // Apply local environment
287 if(localEnvironment != null) {
288 expression = localEnvironment.preDecorateExpression(expression);
289 ProcedureType procedureType = localEnvironment.decorateExpectedType(expectedType, expectedEffect);
290 expectedType = procedureType.type;
291 expectedEffect = procedureType.effect;
296 TypingContext context = new TypingContext(compilationContext);
298 context.pushEffectUpperBound(expression.location, expectedEffect);
299 expression = expression.checkType(context, expectedType);
300 context.popEffectUpperBound();
302 for(Type lvType : lvTypes)
303 lvType.addPolarity(Polarity.POSITIVE);
305 expectedType.addPolarity(Polarity.POSITIVE);
306 context.solveSubsumptions(expression.location);
307 if(!errorLog.hasNoErrors())
308 throw new SCLExpressionCompilationException(errorLog.getErrors());
309 if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
310 ToplevelEffectDecorator decorator =
311 new ToplevelEffectDecorator(errorLog, environment);
312 expression = expression.accept(decorator);
314 expression = context.solveConstraints(environment, expression);
315 expressionType = expression.getType();
317 if(!errorLog.hasNoErrors())
318 throw new SCLExpressionCompilationException(errorLog.getErrors());
320 if(localEnvironment != null)
321 expression = localEnvironment.postDecorateExpression(expression);
326 Type type = expression.getType();
327 type = type.convertMetaVarsToVars();
329 for(Type lvType : lvTypes)
330 lvType.convertMetaVarsToVars();
332 ArrayList<TVar> varsList = Types.freeVars(type);
333 expression = expression.closure(varsList.toArray(new TVar[varsList.size()]));
336 // Initialize code generation
337 MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
338 String moduleName = classLoader.getFreshPackageName();
339 JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
340 compilationContext.javaTypeTranslator = javaTypeTranslator;
341 JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
342 compilationContext.namingPolicy = namingPolicy;
344 ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
347 SimplificationContext context =
348 new SimplificationContext(compilationContext, DummyJavaReferenceValidator.INSTANCE);
349 expression = expression.simplify(context);
351 if(!errorLog.hasNoErrors())
352 throw new SCLExpressionCompilationException(errorLog.getErrors());
354 if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
355 LOGGER.info("{}", expression);
357 if(interpretIfPossible) {
360 ExpressionInterpretationContext expressionInterpretationContext =
361 new ExpressionInterpretationContext(runtimeEnvironment,
362 new TransientClassBuilder(classLoader, javaTypeTranslator));
363 IExpression iexp = expression.toIExpression(expressionInterpretationContext);
364 if(TRACE_INTERPRETATION_VS_COMPILATION)
365 LOGGER.info("INTERPRETED " + expressionText);
366 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
367 LOGGER.info("INTERPRETED AS: " + iexp);
368 return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
369 } catch(UnsupportedOperationException e) {
370 // This is normal when expression cannot be interpreted. We compile it instead.
375 ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName(), compilationContext.lineLocator);
376 DecomposedExpression decomposed =
377 DecomposedExpression.decompose(errorLog, expression);
379 SCLConstant constant = new SCLConstant(
380 Name.create(moduleName, COMPUTATION_METHOD_NAME),
381 expression.getType());
382 constant.setBase(new JavaStaticMethod(
383 moduleName, COMPUTATION_METHOD_NAME,
385 decomposed.typeParameters,
386 decomposed.returnType,
387 decomposed.parameterTypes));
389 CodeWriter w = mw.createFunction(constant,
390 decomposed.typeParameters,
392 decomposed.returnType,
393 decomposed.parameterTypes);
394 constant.setDefinition(w.getFunction());
395 IVal[] parameterVals = w.getParameters();
396 for(int i=0;i<decomposed.parameters.length;++i)
397 decomposed.parameters[i].setVal(parameterVals[i]);
398 w.return_(decomposed.body.location, decomposed.body.toVal(compilationContext, w));
399 } catch(RuntimeException e) {
400 errorLog.setExceptionPosition(expression.location);
402 throw new SCLExpressionCompilationException(errorLog.getErrors());
405 SSAModule ssaModule = mw.getModule();
406 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
407 LOGGER.info("=== SSA before optimization ==================================");
408 LOGGER.info("{}", ssaModule);
410 if(SCLCompilerConfiguration.DEBUG)
411 ssaModule.validate();
413 ExternalConstant[] externalConstants = mw.getExternalConstants();
416 for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
418 while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
419 //LOGGER.info("simplify " + optCount);
422 if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
423 LOGGER.info("=== SSA before lambda lifting ==================================");
424 LOGGER.info("{}", ssaModule);
426 //ssaModule.saveInlinableDefinitions();
427 ssaModule.lambdaLift(errorLog);
428 //ssaModule.validate();
429 ssaModule.markGenerateOnFly();
432 if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
433 LOGGER.info("{}", ssaModule);
435 ssaModule.generateCode(moduleBuilder);
436 } catch (CodeBuildingException e) {
438 throw new SCLExpressionCompilationException(errorLog.getErrors());
440 Map<String, byte[]> classes = moduleBuilder.getClasses();
443 // Load generated code and execute
445 classLoader.addClasses(classes);
446 Class<?> clazz = classLoader.loadClass(MutableClassLoader.SCL_PACKAGE_PREFIX + moduleName);
447 for(ExternalConstant externalConstant : externalConstants)
448 clazz.getField(externalConstant.fieldName).set(null, externalConstant.value);
449 for(Method method : clazz.getMethods()) {
450 if(method.getName().equals(COMPUTATION_METHOD_NAME))
451 return ValueFromMethod.getValueFromStaticMethod(method);
453 errorLog.log("Internal compiler error: didn't find method " +
454 COMPUTATION_METHOD_NAME + " from generated byte code.");
455 throw new SCLExpressionCompilationException(errorLog.getErrors());
456 } catch(ReflectiveOperationException e) {
458 throw new SCLExpressionCompilationException(errorLog.getErrors());
462 public Type getType() {
463 return expressionType;
466 public String getExpressionText() {
467 return expressionText;