From bea2a8313dd7408716eda5d4e46bba53ef523d54 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Hannu=20Niemist=C3=B6?= Date: Fri, 12 May 2017 13:58:22 +0300 Subject: [PATCH] (refs #6878) validateOnly flag to ExpressionEvaluator and CommandSession 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 --- .../scl/compiler/commands/CommandSession.java | 66 ++++++++++++++----- .../scl/compiler/top/ExpressionEvaluator.java | 22 +++++++ .../SCLExpressionCompilationException.java | 2 +- .../compiler/tests/TestCommandSession.java | 32 +++++++++ 4 files changed, 105 insertions(+), 17 deletions(-) diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java index 82d615ca8..1cf6d0de9 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java @@ -76,7 +76,12 @@ public class CommandSession { THashMap variableTypes = new THashMap(); 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)); + } + } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java index c1881fbca..2b42bc7ba 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java @@ -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(); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLExpressionCompilationException.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLExpressionCompilationException.java index f5b2632d1..a4cb30582 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLExpressionCompilationException.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLExpressionCompilationException.java @@ -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; diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestCommandSession.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestCommandSession.java index 4a9bffd09..784a80b4c 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestCommandSession.java +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestCommandSession.java @@ -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); + } + } } -- 2.43.2