(refs #6878) validateOnly flag to ExpressionEvaluator and CommandSession 15/515/4
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 12 May 2017 10:58:22 +0000 (13:58 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 12 May 2017 13:57:45 +0000 (16:57 +0300)
Added a new flag validateOnly to ExpressionEvaluator and CommandSession.
This prevents the execution of the expression. In command session,
variable types are however updated, so it is possible to run longer
command sequences and check their types. To use the flag, run the script
in CommandSession with static method validate.

Change-Id: I3fbb5501c8a902f2f3ea547d5c5bc7d693df3a77

bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLExpressionCompilationException.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestCommandSession.java

index 82d615ca89f476e248615ffb158075d5b7fa5826..1cf6d0de9c5f0786fe4df80072602e22670f514e 100644 (file)
@@ -76,7 +76,12 @@ public class CommandSession {
     THashMap<String,Type> variableTypes = new THashMap<String,Type>();
     
     PrintStream fileOutput;
-
+    
+    /**
+     * Only checks the commands for compilation errors but does not run them.
+     */
+    private boolean validateOnly; 
+    
     public CommandSession(ModuleRepository moduleRepository, SCLReportingHandler handler) {
         this.moduleRepository = moduleRepository;
         this.defaultHandler = new PrintDecorator(
@@ -320,6 +325,7 @@ public class CommandSession {
         Function command = (Function)evaluator
             .localEnvironment(localEnvironment)
             .decorateExpression(true)
+            .validateOnly(validateOnly)
             .eval();
         return new CompiledCommand(command, evaluator.getType());
     }
@@ -361,7 +367,9 @@ public class CommandSession {
                 handler.printCommand(reader.extractString(expression.location));
                 command = compile(expression);
             } catch (SCLExpressionCompilationException e) {
-                CompilationError[] errors = ((SCLExpressionCompilationException)e).getErrors();
+                if(validateOnly)
+                    throw e;
+                CompilationError[] errors = e.getErrors();
                 for(CompilationError error : errors) {
                     if(error.location != Locations.NO_LOCATION)
                         handler.printError(reader.locationUnderlining(error.location));
@@ -371,11 +379,15 @@ public class CommandSession {
             }
             reader.forgetEverythingBefore(Locations.endOf(expression.location));
 
-            Object resultValue = command.command.apply(variableValues);
-            String resultString = toString(resultValue, command.type);
-            if(!resultString.isEmpty())
-                handler.print(resultString);
+            if(!validateOnly) {
+                Object resultValue = command.command.apply(variableValues);
+                String resultString = toString(resultValue, command.type);
+                if(!resultString.isEmpty())
+                    handler.print(resultString);
+            }
         } catch(Exception e) {
+            if(validateOnly)
+                throw e;
             if(!(e instanceof CancelExecution)) {
                 if(e instanceof InterruptedException)
                     handler.printError("Execution interrupted.");
@@ -463,6 +475,24 @@ public class CommandSession {
         }
     }
     
+    private CompilationError[] validate(Reader commandReader) {
+        CommandParser parser = new CommandParser(defaultHandler, new MemoReader(commandReader));
+        validateOnly = true;
+        try {
+            parser.parseCommands();
+            parser.finishBlock();
+            return CompilationError.EMPTY_ARRAY;
+        } catch(SCLExpressionCompilationException e) {
+            return e.getErrors();
+        } catch(SCLSyntaxErrorException e) {
+            return new CompilationError[] { new CompilationError(e.location, e.getMessage()) };
+        } catch(Exception e) {
+            return new CompilationError[] { new CompilationError(Locations.NO_LOCATION, e.getMessage()) };
+        } finally {
+            validateOnly = false;
+        }
+    }
+    
     public void execute(Reader commandReader, SCLReportingHandler handler) {
         if(handler == null)
             handler = defaultHandler;
@@ -494,16 +524,6 @@ public class CommandSession {
         execute(new StringReader(command), handler);
     }
 
-    public CompilationError[] validate(String command) {
-        return CompilationError.EMPTY_ARRAY;
-        /*try {
-            compile(command);
-            return CompilationError.EMPTY_ARRAY;
-        } catch(SCLExpressionCompilationException e) {
-            return e.getErrors();
-        }*/
-    }
-
     private static final String THIS_CLASS_NAME = CommandSession.class.getName(); 
 
     public static void formatException(
@@ -632,4 +652,18 @@ public class CommandSession {
             formatException(handler, e);
         }
     }
+    
+    public static CompilationError[] validate(ModuleRepository moduleRepository,StringReader commandReader) {
+        CommandSession session = new CommandSession(moduleRepository, null);
+        return session.validate(commandReader);
+    }
+    
+    public static CompilationError[] validate(ModuleRepository moduleRepository,String command) {
+        return validate(moduleRepository, new StringReader(command));
+    }
+
+    public CompilationError[] validate(String command) {
+        return validate(new StringReader(command));
+    }
+
 }
index c1881fbca53acb2ffc20a21a01a4f4291ed77cb4..2b42bc7bab865c75d8873ba8150504eb6aa47cc6 100644 (file)
@@ -27,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;
@@ -77,6 +78,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) {
@@ -115,6 +117,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.
      */
@@ -175,6 +182,16 @@ 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();
@@ -243,6 +260,8 @@ 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))
@@ -293,6 +312,9 @@ public class ExpressionEvaluator {
 
             if(localEnvironment != null)
                 expression = localEnvironment.postDecorateExpression(expression);
+            
+            if(validateOnly)
+                return null;
 
             Type type = expression.getType();
             type = type.convertMetaVarsToVars();
index f5b2632d13b397b627251f2fe17a3475a16d7461..a4cb30582cdafb68578be4cf6051c191f7e81bdf 100644 (file)
@@ -2,7 +2,7 @@ package org.simantics.scl.compiler.top;
 
 import org.simantics.scl.compiler.errors.CompilationError;
 
-public class SCLExpressionCompilationException extends Exception {
+public class SCLExpressionCompilationException extends RuntimeException {
 
     private static final long serialVersionUID = 970640318254433797L;
 
index 4a9bffd093c0b0737804008a4f7f148e63e3c058..784a80b4c6072383d659786d57bd9e0eb48fd1ec 100644 (file)
@@ -1,12 +1,16 @@
 package org.simantics.scl.compiler.tests;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.simantics.scl.compiler.commands.CommandSession;
+import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.compiler.errors.CompilationErrorFormatter;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
 import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler;
 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
 
+
 public class TestCommandSession {
 
     ModuleRepository moduleRepository;
@@ -72,5 +76,33 @@ public class TestCommandSession {
         session.execute("iter (\\i -> print i) [1,2,3]");
         session.execute("iter (\\i -> print i) [(),(),()]");
     }
+    
+    @Test
+    public void testValidation() {
+        {
+            CompilationError[] errors = CommandSession.validate(moduleRepository, "1+1");
+            Assert.assertEquals(0, errors.length);
+        }
+        {
+            CompilationError[] errors = CommandSession.validate(moduleRepository, "\"a\"+1");
+            Assert.assertEquals(1, errors.length);
+        }
+        {
+            CompilationError[] errors = CommandSession.validate(moduleRepository,
+                    "a = 1\n" +
+                    "b = 2\n" +
+                    "a + b");
+            Assert.assertEquals(0, errors.length);
+        }
+        {
+            String source = 
+                    "a = 1\n" +
+                    "b = 2.0\n" +
+                    "a + b"; 
+            CompilationError[] errors = CommandSession.validate(moduleRepository, source);
+            //System.out.println(CompilationErrorFormatter.toString(source, errors));
+            Assert.assertEquals(1, errors.length);
+        }
+    }
 
 }