]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7250) Error messages for undefined existentials 92/592/2
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 17:06:29 +0000 (20:06 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 18:09:38 +0000 (21:09 +0300)
Change-Id: Iaddc3d0536350eef85086b0a73a5c1b08055398c

bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl [new file with mode: 0644]

index 20dda072cfa03cb7bfb9dc8c2f228c2b16dcb186..0c81daafd8d3ddfa3b36b5ec327b5ca73f0c8a43 100644 (file)
@@ -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();
     }
index d9746bb04c1d9a2524e82a03193c80a6773ee450..75090ae3833f9f07c2643874bf95fdc9c6bd41c2 100644 (file)
@@ -43,13 +43,18 @@ import gnu.trove.set.hash.THashSet;
 
 public class TranslationContext extends TypeTranslationContext implements EnvironmentalContext {
 
+    public static class ExistentialFrame {
+        THashSet<String> variables = new THashSet<String>(4);
+        ArrayList<Variable> blanks = new ArrayList<Variable>(2); 
+        boolean disallowNewExistentials;
+    }
+    
     THashMap<String, Variable> variables = new THashMap<String, Variable>();
     ArrayList<Entry> variableEntries = new ArrayList<Entry>();
     LocalEnvironment localEnvironment;
     TIntArrayList frames = new TIntArrayList();
     ArrayList<THashSet<String>> frameNameSets = new ArrayList<THashSet<String>>(); 
-    ArrayList<THashSet<String>> existentialFrames = new ArrayList<THashSet<String>>();
-    ArrayList<ArrayList<Variable>> blanksInExistentialFrame = new ArrayList<ArrayList<Variable>>();
+    ArrayList<ExistentialFrame> existentialFrames = new ArrayList<ExistentialFrame>(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<String>());
-        blanksInExistentialFrame.add(new ArrayList<Variable>(2));
+        existentialFrames.add(new ExistentialFrame());
     }
     
     public Variable[] popExistentialFrame() {
         popFrame();
-        THashSet<String> set = existentialFrames.remove(existentialFrames.size()-1);
-        ArrayList<Variable> 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;
+    }
 }
index 3aa3f4281380dad972b26a98b1098264602b8656..50cbb1ac461ea271e0c4700d37d149fc23a351a2 100644 (file)
@@ -93,13 +93,13 @@ public abstract class TextualModuleSource implements ModuleSource {
             if(compiler.getErrorLog().hasNoErrors())
                 return new Success<Module>(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);
         }
index 769a1bde952daaa9de2d5f25d4b1d6c1b6f866bf..f3aa463d5e579344f5099cc243476d41efce994c 100644 (file)
@@ -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 (file)
index 0000000..6576cf4
--- /dev/null
@@ -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 (file)
index 0000000..ce3064a
--- /dev/null
@@ -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