(refs #7250) CHR bugfixes, cleaning up unit tests 91/591/1
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 16:29:13 +0000 (19:29 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 16:29:13 +0000 (19:29 +0300)
Change-Id: If0f255ce74938029ab91975a2db7a09c517473aa

21 files changed:
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/chr/CHRRuleset.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanContext.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PostCommitOp.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/options/ModuleCompilationOptions.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/options/ModuleCompilationOptionsAdvisor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/source/TextualModuleSource.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/chr/CHRContext.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/reporting/WriterSCLReportingHandler.java [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestBase.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR1.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR3.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Formula.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation2.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation3.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation4.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation7.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TransformationOrder.scl

index b30021c1c514b1e9f7542973f8ec25c96560bfdc..20dda072cfa03cb7bfb9dc8c2f228c2b16dcb186 100644 (file)
@@ -2,7 +2,6 @@ package org.simantics.scl.compiler.elaboration.chr;
 
 import java.util.ArrayList;
 
-import org.junit.runners.ParentRunner;
 import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
 import org.simantics.scl.compiler.elaboration.chr.planning.QueryPlanningContext;
@@ -24,6 +23,7 @@ import gnu.trove.set.hash.THashSet;
 import gnu.trove.set.hash.TIntHashSet;
 
 public class CHRRule extends Symbol {
+    public CHRRuleset parentRuleset;
     public int priority;
     public CHRQuery head;
     public CHRQuery body;
@@ -94,7 +94,7 @@ public class CHRRule extends Symbol {
     }
 
     public void compile(CompilationContext compilationContext, CHRConstraint initConstraint) {
-        boolean hasActiveLiteral = false;
+        boolean hasLocalActiveLiteral = false;
         for(int i=0;i<head.literals.length;++i) {
             CHRLiteral literal = head.literals[i];
             if(literal.passive)
@@ -108,9 +108,10 @@ public class CHRRule extends Symbol {
             body.createEnforcePlan(context, priority);
             addPlan(new CHRSearchPlan(constraint, activeFact, context.getPlanOps()));
             
-            hasActiveLiteral = true;
+            if(constraint.parentRuleset == parentRuleset)
+                hasLocalActiveLiteral = true;
         }
-        if(!hasActiveLiteral) {
+        if(!hasLocalActiveLiteral) {
             Variable activeFact = new Variable("activeFact", initConstraint.factType);
             QueryPlanningContext context = new QueryPlanningContext(compilationContext, existentialVariables);
             if(!head.createQueryPlan(context, null, -1))
index bb00f08850f8fa3cd6f21586a8b60a6e052ff640..13eb8491b529bdeb2943d6b15eb996195d4014ff 100644 (file)
@@ -12,6 +12,7 @@ import org.simantics.scl.compiler.constants.JavaMethod;
 import org.simantics.scl.compiler.constants.NoRepConstant;
 import org.simantics.scl.compiler.constants.generic.CallJava;
 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
 import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef;
 import org.simantics.scl.compiler.elaboration.chr.analysis.CHRConstraintGGInfo;
 import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis;
@@ -32,13 +33,13 @@ import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
 import org.simantics.scl.compiler.internal.codegen.references.IVal;
 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
 import org.simantics.scl.compiler.internal.parsing.Symbol;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.compiler.types.TVar;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.Types;
-import org.simantics.scl.runtime.chr.CHRContext;
 
 import gnu.trove.map.hash.THashMap;
 import gnu.trove.map.hash.TObjectIntHashMap;
@@ -67,8 +68,13 @@ public class CHRRuleset extends Symbol {
     public TCon runtimeRulesetType;
     public BoundVar runtimeRulesetVariable;
     public TypeDesc runtimeRulesetTypeDesc;
-    public Constant readCurrentId;
-    public Constant writeCurrentId;
+    
+    public static final Constant READ_CURRENT_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
+            null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
+    public static final Constant WRITE_CURRENT_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER},
+            null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
+    public static final Constant GENERATE_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
+            null, new ObjectMethodRef(false, CHRCodeGenerationConstants.CHRContext_name, "generateId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE, Constants.EMPTY_TYPEDESC_ARRAY), null);
     
     // FIXME remove and change the parameter of Expression.toVal
     private CompilationContext cachedContext;
@@ -248,10 +254,6 @@ public class CHRRuleset extends Symbol {
         runtimeRulesetVariable = new BoundVar(runtimeRulesetType);
         for(CHRConstraint constraint : constraints)
             constraint.initializeCodeGeneration(context, this);
-        readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
-                null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
-        writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER},
-                null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
         if(createTypeDesc && context.module != null) // for unit testing
             context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc));
     }
@@ -310,7 +312,7 @@ public class CHRRuleset extends Symbol {
                         new JavaMethod(true, runtimeRulesetClassName, "initialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
                         object.getTarget(), chrContext);
             }
-            IVal initFact = w.apply(location, initConstraint.constructor, IntegerConstant.ZERO);
+            IVal initFact = w.apply(location, initConstraint.constructor, w.apply(location, GENERATE_ID, chrContext));
             w.apply(location, initConstraint.addProcedure, runtimeRulesetVariable, chrContext, initFact);
             w.apply(location, ACTIVATE, chrContext, new IntegerConstant(Integer.MAX_VALUE));
             if(deinitializer != null) {
@@ -330,4 +332,9 @@ public class CHRRuleset extends Symbol {
                 literal.collectEnforceEffects(effects);
         }
     }
+
+    public void addRule(CHRRule rule) {
+        rules.add(rule);
+        rule.parentRuleset = this;
+    }
 }
index bc6b7da580e3b43a5e43bbf3b646fb1902ee01e7..2a03c89435e7de85ab9a8ac75a7346b60ca0a45c 100644 (file)
@@ -40,7 +40,7 @@ public abstract class PlanContext {
 
     public IVal generateNewId(long location, CodeWriter w) {
         if(currentId == null)
-            currentId = w.apply(location, ruleset.readCurrentId, contextVar);
+            currentId = w.apply(location, CHRRuleset.READ_CURRENT_ID, contextVar);
         IVal result = currentId;
         currentId = w.apply(location, IncreaseByOne.INSTANCE, currentId);
         return result;
index 5b3057dd9dc099da6d13121568f399fc912d4285..a43e97d4cfcc1094933e56f93511c1016552c299 100644 (file)
@@ -25,7 +25,7 @@ public class PostCommitOp extends PlanOp {
     @Override
     public void generateCode(CompilationContext context, PlanContext planContext, CodeWriter w) {
         if(planContext.currentId != null) {
-            w.apply(location, planContext.ruleset.writeCurrentId, planContext.contextVar, planContext.currentId);
+            w.apply(location, CHRRuleset.WRITE_CURRENT_ID, planContext.contextVar, planContext.currentId);
             planContext.currentId = null;
             w.apply(location, CHRRuleset.ACTIVATE, planContext.contextVar, new IntegerConstant(priority+planContext.ruleset.initialPriorityNumber));
         }
index 157efb360302cdf5767ce936f7c64454f9a5baa1..a509616bbb4bf669e08e1ece55584d58355309a3 100644 (file)
@@ -92,7 +92,7 @@ public class EBlock extends ASTExpression {
         for(int i=begin;i<end;++i) {
             Statement statement = statements.get(i);
             if(statement instanceof CHRStatement)
-                ruleset.rules.add(CHRTranslation.convertCHRStatement(context, (CHRStatement)statement));
+                ruleset.addRule(CHRTranslation.convertCHRStatement(context, (CHRStatement)statement));
             else if(statement instanceof ConstraintStatement)
                 ruleset.constraints.add(CHRTranslation.convertConstraintStatement(context, (ConstraintStatement)statement));
             else if(statement instanceof IncludeStatement)
index 045741d35a34495f4bb662dfe2637bb1b53ae263..41c5f776314b9a948bcba47ddd119318a8f82f15 100644 (file)
@@ -2,8 +2,14 @@ package org.simantics.scl.compiler.module.options;
 
 public class ModuleCompilationOptions {
     public static final ModuleCompilationOptions STANDARD_OPTIONS = new ModuleCompilationOptions(false);
+    public static final ModuleCompilationOptions SILENT = new ModuleCompilationOptions(false);
 
-    public final boolean computeCoverage;
+    static {
+        SILENT.silent = true;
+    }
+    
+    public boolean computeCoverage;
+    public boolean silent = false;
 
     public ModuleCompilationOptions(boolean computeCoverage) {
         this.computeCoverage = computeCoverage;
index 9243758a909ce0ce66e87b1b0e94c943da6d9c63..2aaa0785aef5c7a51a0d514e4ce098314cffcc81 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.scl.compiler.module.options;
 
+@FunctionalInterface
 public interface ModuleCompilationOptionsAdvisor {
     ModuleCompilationOptions getOptions(String moduleName);
 }
index 9a6f4c97fb07c33689e21885a1a641d4bdcadf01..3aa3f4281380dad972b26a98b1098264602b8656 100644 (file)
@@ -93,11 +93,14 @@ public abstract class TextualModuleSource implements ModuleSource {
             if(compiler.getErrorLog().hasNoErrors())
                 return new Success<Module>(compiler.getModule());
             else {
-                LOGGER.error("While compiling " + getModuleName() + ":");
-                LOGGER.error(CompilationErrorFormatter.toString(getSourceReader(null), compiler.getErrorLog().getErrors()));
+                if(!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)
+                LOGGER.error("Compilation of module " + moduleName + " failed.", e);
             return new Failure(e);
         }
     }
index 59fe191f7cd68a392bbdc5aaf7c56a46624fb431..b79cf6d7da4743ad66360ce9b42d8953cf7f9591 100644 (file)
@@ -2,7 +2,7 @@ package org.simantics.scl.runtime.chr;
 
 public class CHRContext {
     public CHRPriority topPriority;
-    public int currentId = 1;
+    public int currentId = 0;
     
     public void activate(int maxPriority) {
         //System.out.println("--- ACTIVATE " + maxPriority + "---------------------------------------------");
@@ -14,4 +14,8 @@ public class CHRContext {
         }
         //System.out.println("--- FINISHED " + maxPriority + "---------------------------------------------");
     }
+    
+    public int generateId() {
+        return currentId++;
+    }
 }
diff --git a/bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/reporting/WriterSCLReportingHandler.java b/bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/reporting/WriterSCLReportingHandler.java
new file mode 100644 (file)
index 0000000..3cc3f4b
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.scl.runtime.reporting;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public class WriterSCLReportingHandler extends AbstractSCLReportingHandler {
+    private final Writer writer;
+
+    public WriterSCLReportingHandler(Writer writer) {
+        this.writer = writer;
+    }
+
+    @Override
+    public void print(String text) {
+        try {
+            writer.write(text);
+            writer.write('\n');
+        } catch(IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
index 2dfaafee3660907b6b493e86e9ded837379ce17f..fa90f524cb4364386de2d71ff13c64209877702a 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.scl.compiler.tests;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.StringWriter;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -12,12 +13,16 @@ import org.simantics.scl.compiler.errors.Failable;
 import org.simantics.scl.compiler.errors.Failure;
 import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.Module;
+import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
 import org.simantics.scl.compiler.module.repository.UpdateListener;
 import org.simantics.scl.compiler.source.ModuleSource;
 import org.simantics.scl.compiler.source.StringModuleSource;
 import org.simantics.scl.compiler.source.repository.MapModuleSourceRepository;
 import org.simantics.scl.compiler.top.ValueNotFound;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.reporting.SCLReportingHandler;
+import org.simantics.scl.runtime.reporting.WriterSCLReportingHandler;
 
 public class TestBase {
     
@@ -93,16 +98,25 @@ public class TestBase {
                     return ImportDeclaration.ONLY_BUILTINS;
                 }
             };
-        ModuleRepository testEnvironment = new ModuleRepository(
+        ModuleRepository testRepository = new ModuleRepository(
                 PRELUDE_MODULE_REPOSITORY,
                 new MapModuleSourceRepository(moduleSources));
+        testRepository.setAdvisor(moduleName -> ModuleCompilationOptions.SILENT);
         int lastId = moduleNames.length-1;
-        Failable<Module> result = testEnvironment.getModule(moduleNames[lastId]);
+        Failable<Module> result = testRepository.getModule(moduleNames[lastId]);
         if(!result.didSucceed())
             return ((Failure)result).toString(moduleTexts[lastId]);
         else {
-            Object main = testEnvironment.getRuntimeModule(moduleNames[lastId]).getResult().getValue("main");
-            return String.valueOf(main);
+            SCLContext context = SCLContext.getCurrent();
+            StringWriter writer = new StringWriter();
+            Object oldReportingHandler = context.put(SCLReportingHandler.REPORTING_HANDLER, new WriterSCLReportingHandler(writer));
+            try {
+                Object main = testRepository.getRuntimeModule(moduleNames[lastId]).getResult().getValue("main");
+                writer.write(String.valueOf(main));
+                return writer.toString();
+            } finally {
+                context.put(SCLReportingHandler.REPORTING_HANDLER, oldReportingHandler);
+            }
         }
     }
 
index d305a2a83ba262fc7c6ce684bfa4d7143363b51b..c1e3402afd56c512b040f7eb7967fda016b36b93 100644 (file)
@@ -140,6 +140,11 @@ main = sort (MList.freeze answer)
     
     Edge ?x ?y => MList.add answer (?x, ?y)
 --
+Remove loop (5,5)
+Remove dangling edge (3,5)
+Remove node 5
+Simplify path (1,2,3)
+Simplify path (1,3,4)
 [(1,4), (1,4)]
 --
 import "StandardLibrary"
index 03df6896f3e84b637ed1d77e7bb33f9d72303049..1d8451439ee92b8b9d6cb680ffd92cbb67fa9ca2 100644 (file)
@@ -6,6 +6,5 @@ main = ()
     A ?x, not A (?x+1) => A (?x-1)
     True => A 0
 --
-()
-      
-
+0
+()
\ No newline at end of file
index 00ca32bec06f5b887afd13e5b3a7d1800a939ead..edefae634f7925436fcf16b272e6ba9d41815a3e 100644 (file)
@@ -31,4 +31,10 @@ main = ()
     addSet set 1
     printSet set
 --
-()
+added 1
+added 2
+added 1
+removed duplicate 1
+printing 2
+printing 1
+()
\ No newline at end of file
index c18a13a5ad8d44535b80b687a6cfa66f84fcebba..325af52708e8a831d7e3a56bb9ea42b2ea829c4a 100644 (file)
@@ -20,4 +20,8 @@ main = ()
     True     => X 2
     True     => X 1
 --
-()
+A 1
+B 1
+A 2
+B 2
+()
\ No newline at end of file
index 10eafb0611a67377fcd775ad36e269a15a36cd64..d19263a53f60fd1212eba7e7fb730037eb6f806a 100644 (file)
@@ -128,4 +128,8 @@ main = do
     x := True
     print (evalV f)
 --
+("x" `UntilF` "y")
+false
+false
+("x" `UntilF` "y")
 ()
\ No newline at end of file
index 45ad0658afc17f8bced0682d0e1fb25262b77e0f..84e0c0b4f90dc1d04cd77a4c60e336174facb34c 100644 (file)
@@ -22,4 +22,26 @@ main = transformation OneShotForward where
     Fib 0 1
     Fib 1 1
 --
-()
+21 -> 11
+20 -> 11
+19 -> 10
+18 -> 10
+17 -> 9
+16 -> 9
+15 -> 8
+14 -> 8
+13 -> 7
+12 -> 7
+11 -> 6
+10 -> 6
+9 -> 5
+8 -> 5
+7 -> 4
+6 -> 4
+5 -> 3
+4 -> 3
+3 -> 2
+2 -> 2
+1 -> 1
+0 -> 1
+()
\ No newline at end of file
index f9b995cee1d98081588ec9f24372d0cce6d479aa..20c32335ce3316a3320a8e40b151f8031d22b2d3 100644 (file)
@@ -29,4 +29,25 @@ rule PrintIt where
 
 main = transformation OneShotForward where
 --
-()
+20 -> 10946
+19 -> 6765
+18 -> 4181
+17 -> 2584
+16 -> 1597
+15 -> 987
+14 -> 610
+13 -> 377
+12 -> 233
+11 -> 144
+10 -> 89
+9 -> 55
+8 -> 34
+7 -> 21
+6 -> 13
+5 -> 8
+4 -> 5
+3 -> 3
+2 -> 2
+1 -> 1
+0 -> 1
+()
\ No newline at end of file
index 5a889e1e0c5c1d4759a72bbdc1803c734619705e..92789e68739140e7d07147f31f809a239c881038 100644 (file)
@@ -24,4 +24,16 @@ rule Seed where
 
 main = transformation OneShotForward where
 --
-()
+11 -> 2, 1
+10 -> 1, 2
+9 -> 2, 1
+8 -> 1, 2
+7 -> 2, 1
+6 -> 1, 2
+5 -> 2, 1
+4 -> 1, 2
+3 -> 2, 1
+2 -> 1, 2
+1 -> 2, 1
+0 -> 1, 2
+()
\ No newline at end of file