]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
Make it possible to debug SCL compiler in production builds
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / top / ExpressionEvaluator.java
index 39f0ac721ee2a2bd32d366a9e17123e6c9ab6e74..f14a3be967438af2e93d134e9e1024513e5eb193 100644 (file)
@@ -8,6 +8,7 @@ import java.util.Map;
 
 import org.simantics.scl.compiler.common.names.Name;
 import org.simantics.scl.compiler.compilation.CodeGeneration;
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.constants.JavaStaticMethod;
 import org.simantics.scl.compiler.constants.SCLConstant;
 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
@@ -26,6 +27,7 @@ import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
 import org.simantics.scl.compiler.elaboration.java.Builtins;
 import org.simantics.scl.compiler.environment.Environment;
 import org.simantics.scl.compiler.environment.LocalEnvironment;
+import org.simantics.scl.compiler.errors.CompilationError;
 import org.simantics.scl.compiler.errors.ErrorLog;
 import org.simantics.scl.compiler.internal.codegen.references.IVal;
 import org.simantics.scl.compiler.internal.codegen.ssa.SSAModule;
@@ -40,12 +42,12 @@ import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
 import org.simantics.scl.compiler.internal.codegen.writer.ExternalConstant;
 import org.simantics.scl.compiler.internal.codegen.writer.ModuleWriter;
 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
-import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
 import org.simantics.scl.compiler.internal.interpreted.IExpression;
 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
 import org.simantics.scl.compiler.internal.parsing.parser.SCLBlockParser;
 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions;
+import org.simantics.scl.compiler.internal.parsing.utils.LineLocators;
 import org.simantics.scl.compiler.runtime.MutableClassLoader;
 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
 import org.simantics.scl.compiler.types.TVar;
@@ -56,11 +58,15 @@ import org.simantics.scl.compiler.types.util.Polarity;
 import org.simantics.scl.compiler.types.util.ProcedureType;
 import org.simantics.scl.runtime.function.FunctionImpl1;
 import org.simantics.scl.runtime.tuple.Tuple0;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
 
 import gnu.trove.set.hash.THashSet;
 
 public class ExpressionEvaluator {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExpressionEvaluator.class);
+
     public static final boolean TRACE_INTERPRETATION_VS_COMPILATION = false;
     private static final String COMPUTATION_METHOD_NAME = "main";
     
@@ -76,6 +82,7 @@ public class ExpressionEvaluator {
     private LocalStorage localStorage;
     private boolean interpretIfPossible = true;
     private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION;
+    private boolean validateOnly;
     
     public ExpressionEvaluator(RuntimeEnvironment runtimeEnvironment,
             String expressionText) {
@@ -114,6 +121,11 @@ public class ExpressionEvaluator {
         return this;
     }
     
+    public ExpressionEvaluator validateOnly(boolean validateOnly) {
+        this.validateOnly = validateOnly;
+        return this;
+    }
+    
     /**
      * Sets a local environment that can arbitrarily modify the resolving of the expression.
      */
@@ -174,15 +186,28 @@ public class ExpressionEvaluator {
             return "store_" + name;
         }
     }
+    
+    public CompilationError[] validate() {
+        try {
+            validateOnly = true;
+            eval();
+            return CompilationError.EMPTY_ARRAY;
+        } catch(SCLExpressionCompilationException e) {
+            return e.getErrors();
+        }
+    }
 
     public Object eval() throws SCLExpressionCompilationException {
         fillDefaults();
         
-        final ErrorLog errorLog = new ErrorLog();
+        final CompilationContext compilationContext = new CompilationContext();
+        final ErrorLog errorLog = compilationContext.errorLog;
         final Environment environment = runtimeEnvironment.getEnvironment();
+        compilationContext.environment = environment;
         
         // Parse expression
-        if(expressionText != null && !expressionText.trim().isEmpty()) {
+        if(expressionText != null) {
+            compilationContext.lineLocator = LineLocators.createLineLocator(expressionText);
             try {
                 switch(parseMode) {
                 case BLOCK: {
@@ -204,19 +229,21 @@ public class ExpressionEvaluator {
                 }
             } catch(SCLSyntaxErrorException e) {
                 errorLog.log(e.location, e.getMessage());
-                //System.out.println(errorLog.getErrorsAsString());
+                //LOGGER.info(errorLog.getErrorsAsString());
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
             } catch(Exception e) {
                 errorLog.log(e);
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
             }
         }
+        else
+            compilationContext.lineLocator = LineLocators.DUMMY_LOCATOR;
         
         // Store local variables
         ArrayList<Type> lvTypes = new ArrayList<Type>(); 
         if(expression instanceof EBlock) {
             EBlock block = (EBlock)expression;
-            if(localStorage != null && !(block.getStatements().getLast() instanceof GuardStatement)) {
+            if(localStorage != null && !(block.getLast() instanceof GuardStatement)) {
                 THashSet<String> localVariables = new THashSet<String>();
                 ListIterator<Statement> it = block.getStatements().listIterator();
                 while(it.hasNext()) {
@@ -240,18 +267,19 @@ public class ExpressionEvaluator {
                                     Types.functionE(type, Types.PROC, Types.UNIT)),
                                     new EVar(variableName)
                             )));
+                    if(validateOnly)
+                        localStorage.store(variableName, null, type);
                 }
             }
-            if(!(block.getStatements().getLast() instanceof GuardStatement))
+            if(!(block.getLast() instanceof GuardStatement))
                 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
         }
         
         // Elaboration
         {
-            TranslationContext context = new TranslationContext(errorLog,
-                    environment, localEnvironment);
+            TranslationContext context = new TranslationContext(compilationContext, localEnvironment, "expression");
             expression = expression.resolve(context);
-            if(!errorLog.isEmpty())
+            if(!errorLog.hasNoErrors())
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
         }
         
@@ -265,7 +293,7 @@ public class ExpressionEvaluator {
         
         // Type checking
         {
-            TypingContext context = new TypingContext(errorLog, environment);
+            TypingContext context = new TypingContext(compilationContext);
 
             context.pushEffectUpperBound(expression.location, expectedEffect);
             expression = expression.checkType(context, expectedType);
@@ -276,21 +304,24 @@ public class ExpressionEvaluator {
             
             expectedType.addPolarity(Polarity.POSITIVE);
             context.solveSubsumptions(expression.location);
-            if(!errorLog.isEmpty())
+            if(!errorLog.hasNoErrors())
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
             if(decorateExpression && Types.canonical(expectedEffect) != Types.NO_EFFECTS) {
-                ExpressionDecorator decorator =
+                ToplevelEffectDecorator decorator =
                         new ToplevelEffectDecorator(errorLog, environment);
-                expression = expression.decorate(decorator);
+                expression = expression.accept(decorator);
             }
             expression = context.solveConstraints(environment, expression);
             expressionType = expression.getType();
             
-            if(!errorLog.isEmpty())
+            if(!errorLog.hasNoErrors())
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
 
             if(localEnvironment != null)
                 expression = localEnvironment.postDecorateExpression(expression);
+            
+            if(validateOnly)
+                return null;
 
             Type type = expression.getType();
             type = type.convertMetaVarsToVars();
@@ -306,21 +337,22 @@ public class ExpressionEvaluator {
         MutableClassLoader classLoader = runtimeEnvironment.getMutableClassLoader();
         String moduleName = classLoader.getFreshPackageName();
         JavaTypeTranslator javaTypeTranslator = new JavaTypeTranslator(environment);
+        compilationContext.javaTypeTranslator = javaTypeTranslator;
         JavaNamingPolicy namingPolicy = new JavaNamingPolicy(moduleName);
+        compilationContext.namingPolicy = namingPolicy;
 
         ModuleBuilder moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator);
         
         // Simplify
         SimplificationContext context = 
-                new SimplificationContext(environment, errorLog, 
-                        javaTypeTranslator, DummyJavaReferenceValidator.INSTANCE);
+                new SimplificationContext(compilationContext, DummyJavaReferenceValidator.INSTANCE);
         expression = expression.simplify(context);
         
-        if(!errorLog.isEmpty())
+        if(!errorLog.hasNoErrors())
             throw new SCLExpressionCompilationException(errorLog.getErrors());
         
         if(SCLCompilerConfiguration.SHOW_EXPRESSION_BEFORE_EVALUATION)
-            System.out.println(expression);
+            LOGGER.info("{}", expression);
         
         if(interpretIfPossible) {
         // Try to interpret
@@ -330,9 +362,9 @@ public class ExpressionEvaluator {
                             new TransientClassBuilder(classLoader, javaTypeTranslator));
             IExpression iexp = expression.toIExpression(expressionInterpretationContext);
                 if(TRACE_INTERPRETATION_VS_COMPILATION)
-                System.out.println("INTERPRETED " + expressionText);
+                LOGGER.info("INTERPRETED " + expressionText);
                 if(SCLCompilerConfiguration.SHOW_INTERPRETED_EXPRESSION)
-                    System.out.println("INTERPRETED AS: " + iexp);
+                    LOGGER.info("INTERPRETED AS: " + iexp);
             return iexp.execute(new Object[expressionInterpretationContext.getMaxVariableId()]);
         } catch(UnsupportedOperationException e) {
             // This is normal when expression cannot be interpreted. We compile it instead.
@@ -340,9 +372,9 @@ public class ExpressionEvaluator {
         }
         
         // Convert to SSA
-        ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
+        ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName(), compilationContext.lineLocator);
         DecomposedExpression decomposed = 
-                DecomposedExpression.decompose(expression);
+                DecomposedExpression.decompose(errorLog, expression);
 
         SCLConstant constant = new SCLConstant(
                 Name.create(moduleName, COMPUTATION_METHOD_NAME),
@@ -363,16 +395,17 @@ public class ExpressionEvaluator {
             IVal[] parameterVals = w.getParameters();
             for(int i=0;i<decomposed.parameters.length;++i)
                 decomposed.parameters[i].setVal(parameterVals[i]);
-            w.return_(decomposed.body.toVal(environment, w));
+            w.return_(decomposed.body.location, decomposed.body.toVal(compilationContext, w));
         } catch(RuntimeException e) {
             errorLog.setExceptionPosition(expression.location);
+            errorLog.log(e);
             throw new SCLExpressionCompilationException(errorLog.getErrors());
         }
 
         SSAModule ssaModule = mw.getModule();
         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
-            System.out.println("=== SSA before optimization ==================================");
-            System.out.println(ssaModule);            
+            LOGGER.info("=== SSA before optimization ==================================");
+            LOGGER.info("{}", ssaModule);
         }
         if(SCLCompilerConfiguration.DEBUG)
             ssaModule.validate();
@@ -383,12 +416,12 @@ public class ExpressionEvaluator {
         for(int phase=0;phase<CodeGeneration.OPTIMIZATION_PHASES;++phase) {
             int optCount = 0;
             while(optCount++ < 4 && ssaModule.simplify(environment, phase)) {
-                //System.out.println("simplify " + optCount);
+                //LOGGER.info("simplify " + optCount);
             }
         }
         if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
-            System.out.println("=== SSA before lambda lifting ==================================");
-            System.out.println(ssaModule);            
+            LOGGER.info("=== SSA before lambda lifting ==================================");
+            LOGGER.info("{}", ssaModule);
         }
         //ssaModule.saveInlinableDefinitions();
         ssaModule.lambdaLift(errorLog);
@@ -397,7 +430,7 @@ public class ExpressionEvaluator {
         
         // Generate code
         if(SCLCompilerConfiguration.SHOW_FINAL_SSA)
-            System.out.println(ssaModule);
+            LOGGER.info("{}", ssaModule);
         try {
             ssaModule.generateCode(moduleBuilder);
         } catch (CodeBuildingException e) {
@@ -405,6 +438,7 @@ public class ExpressionEvaluator {
             throw new SCLExpressionCompilationException(errorLog.getErrors());
         }
         Map<String, byte[]> classes = moduleBuilder.getClasses();
+        ssaModule.cleanup();
         
         // Load generated code and execute
         try {