From 9a17c7c202c7104631fa5d899a4583a0cc2ad6ac Mon Sep 17 00:00:00 2001 From: =?utf8?q?Hannu=20Niemist=C3=B6?= Date: Fri, 2 Jun 2017 20:06:29 +0300 Subject: [PATCH] (refs #7250) Error messages for undefined existentials Change-Id: Iaddc3d0536350eef85086b0a73a5c1b08055398c --- .../scl/compiler/elaboration/chr/CHRRule.java | 1 + .../contexts/TranslationContext.java | 53 +++++++++++++------ .../compiler/source/TextualModuleSource.java | 4 +- .../compiler/tests/ModuleRegressionTests.java | 4 +- .../simantics/scl/compiler/tests/scl/CHR7.scl | 20 +++++++ .../simantics/scl/compiler/tests/scl/CHR8.scl | 12 +++++ 6 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl create mode 100644 tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java index 20dda072c..0c81daafd 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java @@ -49,6 +49,7 @@ public class CHRRule extends Symbol { public void resolve(TranslationContext context) { context.pushExistentialFrame(); head.resolve(context); + context.disallowNewExistentials(); body.resolve(context); existentialVariables = context.popExistentialFrame(); } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java index d9746bb04..75090ae38 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java @@ -43,13 +43,18 @@ import gnu.trove.set.hash.THashSet; public class TranslationContext extends TypeTranslationContext implements EnvironmentalContext { + public static class ExistentialFrame { + THashSet variables = new THashSet(4); + ArrayList blanks = new ArrayList(2); + boolean disallowNewExistentials; + } + THashMap variables = new THashMap(); ArrayList variableEntries = new ArrayList(); LocalEnvironment localEnvironment; TIntArrayList frames = new TIntArrayList(); ArrayList> frameNameSets = new ArrayList>(); - ArrayList> existentialFrames = new ArrayList>(); - ArrayList> blanksInExistentialFrame = new ArrayList>(); + ArrayList existentialFrames = new ArrayList(2); SCLValue bindFunction; public PreQuery currentPreQuery; @@ -110,30 +115,42 @@ public class TranslationContext extends TypeTranslationContext implements Enviro char c = name.charAt(0); switch(c) { - case '?': - if(existentialFrames.isEmpty()) { - errorLog.log(location, "Existential variables can be used only in queries."); + case '?': { + ExistentialFrame existentialFrame = getCurrentExistentialFrame(); + if(existentialFrame == null || existentialFrame.disallowNewExistentials) { + errorLog.log(location, "New existential variables can be defined only in queries."); return new EError(location); } variable = new Variable(name); variables.put(name, variable); - existentialFrames.get(existentialFrames.size()-1).add(name); + existentialFrame.variables.add(name); return new EVariable(variable); - case '_': + } + case '_': { if(name.length()==1) { variable = new Variable("_"); - if(blanksInExistentialFrame.isEmpty()) { - errorLog.log(location, "Cannot use blank variables in this context."); + ExistentialFrame existentialFrame = getCurrentExistentialFrame(); + if(existentialFrame == null || existentialFrame.disallowNewExistentials) { + errorLog.log(location, "Blank variables can be used only in queries."); return new EError(location); } - blanksInExistentialFrame.get(blanksInExistentialFrame.size()-1).add(variable); + existentialFrame.blanks.add(variable); return new EVariable(variable); } break; } + } return null; } + private ExistentialFrame getCurrentExistentialFrame() { + int size = existentialFrames.size(); + if(size == 0) + return null; + else + return existentialFrames.get(size-1); + } + private Expression resolveFieldAccess(Expression base, int pos, String name) { while(pos != -1) { int p = findSeparator(name, pos+1); @@ -380,19 +397,17 @@ public class TranslationContext extends TypeTranslationContext implements Enviro public void pushExistentialFrame() { pushFrame(); - existentialFrames.add(new THashSet()); - blanksInExistentialFrame.add(new ArrayList(2)); + existentialFrames.add(new ExistentialFrame()); } public Variable[] popExistentialFrame() { popFrame(); - THashSet set = existentialFrames.remove(existentialFrames.size()-1); - ArrayList blanks = blanksInExistentialFrame.remove(blanksInExistentialFrame.size()-1); - Variable[] result = new Variable[set.size() + blanks.size()]; + ExistentialFrame frame = existentialFrames.remove(existentialFrames.size()-1); + Variable[] result = new Variable[frame.variables.size() + frame.blanks.size()]; int i=0; - for(String name : set) + for(String name : frame.variables) result[i++] = variables.remove(name); - for(Variable blank : blanks) + for(Variable blank : frame.blanks) result[i++] = blank; return result; } @@ -526,4 +541,8 @@ public class TranslationContext extends TypeTranslationContext implements Enviro public CHRRuleset resolveRuleset(String name) throws AmbiguousNameException { return Environments.getRuleset(environment, name); } + + public void disallowNewExistentials() { + getCurrentExistentialFrame().disallowNewExistentials = true; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java index 3aa3f4281..50cbb1ac4 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java @@ -93,13 +93,13 @@ public abstract class TextualModuleSource implements ModuleSource { if(compiler.getErrorLog().hasNoErrors()) return new Success(compiler.getModule()); else { - if(!options.silent) + if(options == null || !options.silent) LOGGER.error("While compiling " + getModuleName() + ":\n " + CompilationErrorFormatter.toString(getSourceReader(null), compiler.getErrorLog().getErrors()).replaceAll("\n", "\n ")); return new Failure(compiler.getErrorLog().getErrors()); } } catch (IOException e) { - if(!options.silent) + if(options == null || !options.silent) LOGGER.error("Compilation of module " + moduleName + " failed.", e); return new Failure(e); } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java index 769a1bde9..f3aa463d5 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java @@ -27,7 +27,9 @@ public class ModuleRegressionTests extends TestBase { @Test public void CHR3() { test(); } @Test public void CHR4() { test(); } @Test public void CHR5() { test(); } - @Test public void CHR6() { test(); } + @Test public void CHR6() { test(); } + @Test public void CHR7() { test(); } + @Test public void CHR8() { test(); } @Test public void ClosureRecursion() { test(); } @Test public void Collaz() { test(); } @Test public void Compose() { test(); } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl new file mode 100644 index 000000000..6576cf47e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl @@ -0,0 +1,20 @@ +module { + export = [main], + chr +} + +import "StandardLibrary" + +ruleset RS where + constraint X Integer + True => X 3 + +main = () + where + include RS createRS + -X ?value, ?value < 6 => print "X \(?value)", X (?value+1) +-- +X 3 +X 4 +X 5 +() \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl new file mode 100644 index 000000000..ce3064aa4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl @@ -0,0 +1,12 @@ +module { + export = [main], + chr +} + +import "StandardLibrary" + +main = () + where + X ?x => Y ?y +-- +10:15-10:17: New existential variables can be defined only in queries. \ No newline at end of file -- 2.43.2