]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7250) CHR rules modularization (first working version) 85/585/5
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Thu, 1 Jun 2017 10:04:26 +0000 (13:04 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 11:17:33 +0000 (14:17 +0300)
This change adds a complete implementation of CHR modularization. New
top level declaration ruleset allows to define rulesets that can be
included into other rulesets (see CHR{5,6}.scl).

Change-Id: I3a188d788602fa27f863e16969f956d79c9684a9

69 files changed:
bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/exceptions/InternalCompilerError.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/NamespaceOfModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java
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/CHRRulesetObject.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/CHRConstraintGGInfo.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/UsageAnalysis.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/ClaimOp.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/IterateConstraintOp.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/chr/plan/PreCommitOp.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.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/elaboration/contexts/TypeTranslationContext.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/elaboration/expressions/ECHRRulesetConstructor.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRRulesetConstructor.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/block/IncludeStatement.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/block/StatementVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/printing/ExpressionToStringVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/EmptyNamespace.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Environments.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Namespace.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/NamespaceImpl.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerationConstants.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRPriorityFactContainerCodeGenerator.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRRuntimeRulesetCodeGenerator.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSABlock.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAClosure.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetFunctions.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/types/StandardTypeConstructor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/CodeBuilderUtils.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilderBase.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ModuleBuilder.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DModuleHeader.java [deleted file]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DRulesetAst.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.flex
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLPostLexer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/LazyModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/Module.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.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/SCLCompilerConfiguration.java
bundles/org.simantics.scl.runtime/scl/TestCHR.scl [deleted file]
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/info/SCLInfo.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.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/CHR5.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestCHRCodeGenerator.java

index acf2bb18d643ae4f40c1d3a6d1896d9782787f63..5843b89e32eae40bb25d84a9e28fee05b017a9ad 100644 (file)
@@ -885,4 +885,11 @@ public abstract class TypeDesc extends Descriptor {
             }
         }
     }
+    
+    public static TypeDesc[] concat(TypeDesc[] a, TypeDesc[] b) {
+        TypeDesc[] result = new TypeDesc[a.length + b.length];
+        System.arraycopy(a, 0, result, 0, a.length);
+        System.arraycopy(b, 0, result, a.length, b.length);
+        return result;
+    }
 }
index 1cf6d0de9c5f0786fe4df80072602e22670f514e..a8f3d2045efb105928e18c951d1322410bd13a0f 100644 (file)
@@ -423,10 +423,9 @@ public class CommandSession {
         void finishBlock() {
             if(currentBlock != null) {
                 checkInterrupted();
-                LinkedList<Statement> statements = currentBlock.getStatements();
                 currentBlock.location = Locations.combine(
-                        statements.getFirst().location,
-                        statements.getLast().location);
+                        currentBlock.getFirst().location,
+                        currentBlock.getLast().location);
                 execute(reader, currentBlock, handler);
                 currentBlock = null;
             }
index ae3bdd87ca368ed06cddf8c42f209ea339c63b1f..71b6193015b1b4aafb8d9e0cc226131a0f7f928b 100644 (file)
@@ -31,5 +31,10 @@ public class InternalCompilerError extends RuntimeException {
         super(cause);
         this.location = Locations.NO_LOCATION;
     }
+    
+    public InternalCompilerError(long location, Throwable cause) {
+        super(cause);
+        this.location = location;
+    }
    
 }
index 9c7c77470c55b57a91c7dc768d49ff3408e2c9ff..a8dca8c1133950ae64e397c4aca34fb033cc9083 100644 (file)
@@ -183,7 +183,7 @@ public class CodeGeneration {
     }
     
     public void optimizeSSA() {
-        if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION) {
+        if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_OPTIMIZATION && SCLCompilerConfiguration.debugFilter(module.getName())) {
             System.out.println("=== SSA before optimization ====================================");
             System.out.println(ssaModule);            
         }
@@ -199,7 +199,7 @@ public class CodeGeneration {
             if(phase == 0)
                 ssaModule.saveInlinableDefinitions();
         }
-        if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING) {
+        if(SCLCompilerConfiguration.SHOW_SSA_BEFORE_LAMBDA_LIFTING && SCLCompilerConfiguration.debugFilter(module.getName())) {
             System.out.println("=== SSA before lambda lifting ==================================");
             System.out.println(ssaModule);            
         }
@@ -211,7 +211,7 @@ public class CodeGeneration {
     }
     
     public void generateCode() {
-        if(SCLCompilerConfiguration.SHOW_FINAL_SSA) {
+        if(SCLCompilerConfiguration.SHOW_FINAL_SSA && SCLCompilerConfiguration.debugFilter(module.getName())) {
             System.out.println("=== Final SSA ==================================================");
             System.out.println(ssaModule);
         }
index 652adf93efc769cb30cce495d99a53ed665bd35b..4bf5d847e8d8d745cd62c294ec51e8d786dbf6c2 100644 (file)
@@ -23,9 +23,9 @@ import org.simantics.scl.compiler.internal.parsing.declarations.DFixityAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DImportJavaAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
-import org.simantics.scl.compiler.internal.parsing.declarations.DModuleHeader;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRulesetAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
@@ -39,7 +39,6 @@ import org.simantics.scl.compiler.module.ImportDeclaration;
 import gnu.trove.map.hash.THashMap;
 
 public class DeclarationClassification {
-    DModuleHeader moduleHeader;
     ArrayList<ImportDeclaration> importsAst = new ArrayList<ImportDeclaration>();
     ArrayList<DDataAst> dataTypesAst = new ArrayList<DDataAst>();
     ArrayList<DTypeAst> typeAliasesAst = new ArrayList<DTypeAst>();
@@ -53,6 +52,7 @@ public class DeclarationClassification {
     ArrayList<DEffectAst> effectsAst = new ArrayList<DEffectAst>();
     ArrayList<DRuleAst> rulesAst = new ArrayList<DRuleAst>();
     ArrayList<DMappingRelationAst> mappingRelationsAst = new ArrayList<DMappingRelationAst>();
+    ArrayList<DRulesetAst> rulesetsAst = new ArrayList<DRulesetAst>();
     
     THashMap<String, DDocumentationAst> valueDocumentation = new THashMap<String, DDocumentationAst>();
     THashMap<String, DDocumentationAst> relationDocumentation = new THashMap<String, DDocumentationAst>();
@@ -108,8 +108,8 @@ public class DeclarationClassification {
             handle((DMappingRelationAst)declaration);
         else if(declaration instanceof DRelationAst)
             handle((DRelationAst)declaration);
-        else if(declaration instanceof DModuleHeader)
-            handle((DModuleHeader)declaration);
+        else if(declaration instanceof DRulesetAst)
+            handle((DRulesetAst)declaration);
         else
             throw new InternalCompilerError("Unknown declaration " + declaration.getClass().getSimpleName());
     }
@@ -346,11 +346,19 @@ public class DeclarationClassification {
         }
     }
     
+    public void handle(DRulesetAst declaration) {
+        if(documentation != null) {
+            declaration.documentation = documentation;
+            documentation = null;
+        }
+        rulesetsAst.add(declaration);
+    }
+    
     public void handle(DDocumentationAst declaration) {
         if(documentation != null) {
             errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
         }
-        documentation = declaration;                
+        documentation = declaration;
     }
     
     public void handle(DAnnotationAst declaration) {
@@ -384,10 +392,6 @@ public class DeclarationClassification {
         mappingRelationsAst.add(declaration);
     }
     
-    public void handle(DModuleHeader declaration) {
-        moduleHeader = declaration;
-    }
-    
     public void addValueDocumentation(String valueName, DDocumentationAst documentation) {
         DDocumentationAst oldDoc = valueDocumentation.put(valueName, documentation);
         if(oldDoc != null) {
index 1cba44207ee7c124de787ceff3b7631421084c1b..6499ab4fe7d09fac0fd4f793fd4b3e7b2f6da80d 100644 (file)
@@ -6,6 +6,7 @@ import java.util.List;
 
 import org.cojen.classfile.TypeDesc;
 import org.simantics.scl.compiler.common.datatypes.Constructor;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.common.names.Name;
 import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.constants.JavaTypeInstanceConstructor;
@@ -31,6 +32,7 @@ import org.simantics.scl.compiler.elaboration.expressions.EGetConstraint;
 import org.simantics.scl.compiler.elaboration.expressions.EIntegerLiteral;
 import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EPreCHRRulesetConstructor;
 import org.simantics.scl.compiler.elaboration.expressions.EVar;
 import org.simantics.scl.compiler.elaboration.expressions.Expression;
 import org.simantics.scl.compiler.elaboration.expressions.Variable;
@@ -47,6 +49,7 @@ import org.simantics.scl.compiler.elaboration.modules.TypeAlias;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
 import org.simantics.scl.compiler.elaboration.modules.TypeClassInstance;
 import org.simantics.scl.compiler.elaboration.modules.TypeClassMethod;
+import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
 import org.simantics.scl.compiler.elaboration.query.Query;
 import org.simantics.scl.compiler.elaboration.query.pre.QPreGuard;
 import org.simantics.scl.compiler.elaboration.relations.ConcreteRelation;
@@ -84,6 +87,7 @@ import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRulesetAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
@@ -211,7 +215,8 @@ public class Elaboration {
     public void addTypesToEnvironment(
             ArrayList<DDataAst> dataTypesAst,
             ArrayList<DTypeAst> typeAliasesAst,
-            ArrayList<DEffectAst> effectsAst) {
+            ArrayList<DEffectAst> effectsAst,
+            ArrayList<DRulesetAst> rulesetsAst) {
         for(DDataAst dataType : dataTypesAst) {
             dataType.parameterKinds = new Kind[dataType.parameters.length];
             Kind constructorKind = Kinds.STAR;
@@ -226,8 +231,7 @@ public class Elaboration {
 
             NameExistenceChecks.checkIfTypeExists(errorLog,
                     dataType.location, importedEnvironment, dataType.name);
-            if(module.addTypeDescriptor(dataType.name, typeConstructor))
-                errorLog.log(dataType.location, "Type "+dataType.name+" has already been defined in this module.");
+            addTypeDescriptor(dataType.location, dataType.name, typeConstructor);
             dataType.typeConstructor = typeConstructor;
         }
         
@@ -235,9 +239,7 @@ public class Elaboration {
             TypeAlias alias = new TypeAlias(Types.con(moduleName, typeAlias.name), typeAlias.parameters.length);
             NameExistenceChecks.checkIfTypeExists(errorLog,
                     typeAlias.location, importedEnvironment, typeAlias.name);
-            if(module.addTypeDescriptor(typeAlias.name, alias)) {
-                errorLog.log(typeAlias.location, "Type alias "+typeAlias.name+" has already been defined in this module.");
-            }
+            addTypeDescriptor(typeAlias.location, typeAlias.name, alias);
         }
         
         for(DEffectAst effect : effectsAst) {
@@ -248,11 +250,24 @@ public class Elaboration {
                             TypeDesc.forClass(effect.threadLocalType)
                             ));
             if(module.addEffectConstructor(effect.name, effectConstructor))
-                errorLog.log(effect.location, "Type "+effect.name+" has already been defined in this module.");
-        }     
+                errorLog.log(effect.location, "Effect "+effect.name+" has already been defined in this module.");
+        }
+        for(DRulesetAst ruleset : rulesetsAst) {
+            ruleset.type = Types.con(moduleName, ruleset.name);
+            ruleset.className = compilationContext.namingPolicy.getDataTypeClassName(ruleset.name);
+            StandardTypeConstructor typeConstructor = new StandardTypeConstructor(ruleset.type, Kinds.STAR,
+                    TypeDesc.forClass(ruleset.className), ruleset.documentation == null ? null : ruleset.documentation.documentation);
+            typeConstructor.external = true;
+            addTypeDescriptor(ruleset.location, ruleset.name, typeConstructor);
+        }
         javaTypeTranslator = new JavaTypeTranslator(compilationContext.environment);
         compilationContext.javaTypeTranslator = javaTypeTranslator;
     }
+        
+    private void addTypeDescriptor(long location, String name, TypeDescriptor typeDescriptor) {
+        if(module.addTypeDescriptor(name, typeDescriptor))
+            errorLog.log(location, "Type "+name+" has already been defined in this module.");
+    }
     
     private static final int[] EMPTY_INT_ARRAY = new int[0];
     
@@ -702,6 +717,18 @@ public class Elaboration {
         }
     }
     
+    public void processRulesets(ArrayList<DRulesetAst> rulesetsAst) {
+        for(DRulesetAst ruleset : rulesetsAst) {
+            String constructorName = "create" + ruleset.name;
+            supplementedTypeAnnotations.add(new SupplementedValueType(ruleset.location, constructorName, Types.functionE(Types.PUNIT, Types.PROC, ruleset.type)));
+            try {
+                valueDefinitionsAst.add(new DValueAst(new EVar(constructorName), new EPreCHRRulesetConstructor(ruleset)));
+            } catch (NotPatternException e) {
+                throw new InternalCompilerError(ruleset.location, e);
+            }
+        }
+    }
+    
     /**
      * Convert a java class method into a {@link CallJava} instance.
      * Compilation errors are logged for failures in finding the named class or in accessing the method.
index 77e6e96df9a4390f4c7ef4ef70758f20b15d35f7..8621283b73dc5e12bb7a1c5473d36cc438518567 100644 (file)
@@ -3,6 +3,7 @@ package org.simantics.scl.compiler.compilation;
 import java.util.Arrays;
 import java.util.function.Consumer;
 
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
 import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
@@ -72,6 +73,14 @@ public class NamespaceOfModule implements Namespace {
         return base.getRelation(name);
     }
 
+    @Override
+    public CHRRuleset getRuleset(String name) throws AmbiguousNameException {
+        CHRRuleset ruleset = module.getRuleset(name);
+        if(ruleset != null)
+            return ruleset;
+        return base.getRuleset(name);
+    }
+    
     @Override
     public SCLEntityType getEntityType(String name)
             throws AmbiguousNameException {
index 643513d67720537450e8c98fbd411bdd781b000e..cd43b76e15dec63e81b6ca704238ee2f956aec4c 100644 (file)
@@ -44,6 +44,7 @@ public class SCLCompiler {
         try {
             SCLParserImpl parser = new SCLParserImpl(sourceReader);
             parser.setParserOptions(SCLParserOptions.MODULE_DEFAULT);
+            parser.setCompilationContext(compilationContext);
             if(!parser.isEmpty())
             for(DeclarationAst declaration : (ArrayList<DeclarationAst>)parser.parseModule())
                 declarations.handle(declaration);
@@ -70,7 +71,6 @@ public class SCLCompiler {
             String moduleName) {
         try {
             if(hasErrors()) return;
-            compilationContext.header = ModuleHeader.process(compilationContext.errorLog, declarations.moduleHeader);
             Elaboration elaboration = new Elaboration(compilationContext,
                     timer,
                     localEnvironmentFactory,
@@ -87,7 +87,8 @@ public class SCLCompiler {
             elaboration.addTypesToEnvironment(
                     declarations.dataTypesAst,
                     declarations.typeAliasesAst,
-                    declarations.effectsAst);
+                    declarations.effectsAst,
+                    declarations.rulesetsAst);
             if(hasErrors()) return;
             elaboration.processTypeAliases(declarations.typeAliasesAst);
             if(hasErrors()) return;
@@ -101,6 +102,8 @@ public class SCLCompiler {
             if(hasErrors()) return;
             elaboration.processJavaMethods(declarations.javaMethodDeclarations);
             if(hasErrors()) return;
+            elaboration.processRulesets(declarations.rulesetsAst);
+            if(hasErrors()) return;
             elaboration.addDataTypesToEnvironment();
             elaboration.addTypeClassesToEnvironment();
             elaboration.preprocessValueDefinitions(declarations.typeAnnotationsAst);
index d37b75089f9aab03a6a0eb908d425548fa78396a..dcef289f02763d9521532f30bc02bd7242714e52 100644 (file)
@@ -151,7 +151,7 @@ public abstract class FunctionValue extends Constant {
             
             // Constructor
             { 
-                MethodBuilderBase mb = classFile.addConstructor(Opcodes.ACC_PUBLIC, Constants.EMPTY_TYPEDESC_ARRAY);
+                MethodBuilderBase mb = classFile.addConstructorBase(Opcodes.ACC_PUBLIC, Constants.EMPTY_TYPEDESC_ARRAY);
                 mb.loadThis();
                 mb.loadConstant(arity);
                 mb.invokeConstructor(MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL), new TypeDesc[] {TypeDesc.INT});
index 9846ebd4807db5342ace21ceec9027b41ba4c5f5..b30021c1c514b1e9f7542973f8ec25c96560bfdc 100644 (file)
@@ -2,6 +2,7 @@ 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;
@@ -29,7 +30,7 @@ public class CHRRule extends Symbol {
     public Variable[] existentialVariables;
     
     // Analysis
-    public int firstPriorityExecuted;
+    //public int firstPriorityExecuted;
     public int lastPriorityExecuted;
     
     // Plans
@@ -124,7 +125,6 @@ public class CHRRule extends Symbol {
     
     private void addPlan(CHRSearchPlan plan) {
         plans.add(plan);
-        plan.constraint.minimumPriority = Math.min(plan.constraint.minimumPriority, priority);
     }
 
     public String toString() {
index 7b5ceec83705366eb944294bfc019d0c528e8488..d5f61965454e80006631d98d76621fc56ba94e50 100644 (file)
@@ -9,9 +9,11 @@ import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.constants.IntegerConstant;
 import org.simantics.scl.compiler.constants.JavaConstructor;
 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.SetFieldRef;
+import org.simantics.scl.compiler.elaboration.chr.analysis.CHRConstraintGGInfo;
 import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis;
 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
 import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer;
@@ -21,11 +23,14 @@ import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
 import org.simantics.scl.compiler.elaboration.expressions.Variable;
 import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerationConstants;
 import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator;
 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.writer.CodeWriter;
 import org.simantics.scl.compiler.internal.parsing.Symbol;
@@ -33,7 +38,9 @@ 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;
 import gnu.trove.set.hash.THashSet;
 import gnu.trove.set.hash.TIntHashSet;
@@ -44,11 +51,19 @@ public class CHRRuleset extends Symbol {
     
     public ArrayList<CHRConstraint> constraints = new ArrayList<CHRConstraint>();
     public ArrayList<CHRRule> rules = new ArrayList<CHRRule>();
+    public ArrayList<IncludeStatement> includes = new ArrayList<IncludeStatement>();
+    public THashMap<CHRConstraint, IncludeStatement> constraintSourceMap = new THashMap<CHRConstraint, IncludeStatement>();
+    public THashMap<CHRConstraint, CHRConstraintGGInfo> activeConstraintGGInfo = new THashMap<CHRConstraint, CHRConstraintGGInfo>(); // contains also imported constraints
+    public THashMap<IncludeStatement, ArrayList<CHRConstraint>> inverseActiveConstraintSourceMap = new THashMap<IncludeStatement, ArrayList<CHRConstraint>>();
+    
+    public boolean extensible;
     
     public CHRConstraint initConstraint;
     public int priorityCount;
     
-    public String runtimeRulesetName;
+    public int initialPriorityNumber = 0;
+    
+    public String runtimeRulesetClassName;
     public TCon runtimeRulesetType;
     public BoundVar runtimeRulesetVariable;
     public TypeDesc runtimeRulesetTypeDesc;
@@ -59,9 +74,9 @@ public class CHRRuleset extends Symbol {
     private CompilationContext cachedContext;
     
     // For code generation
-    public BoundVar this_;
-    public BoundVar[] parameters;
-    public TypeDesc[] parameterTypeDescs;
+    public CHRRulesetObject rulesetObject;
+    public SSAFunction initializer;
+    public SSAFunction deinitializer;
     
     public CHRRuleset() {
         initConstraint = new CHRConstraint(Locations.NO_LOCATION, INIT_CONSTRAINT, Type.EMPTY_ARRAY);
@@ -69,6 +84,27 @@ public class CHRRuleset extends Symbol {
     }
     
     public void resolve(TranslationContext context) {
+        boolean failedIncludes = false;
+        for(IncludeStatement include : includes) {
+            try {
+                include.ruleset = context.resolveRuleset(include.name.text);
+                if(include.ruleset == null) {
+                    failedIncludes = true;
+                    context.getErrorLog().log(include.name.location, "Couldn't resolve ruleset " + include.name + ".");
+                    continue;
+                }
+                include.value = include.value.resolve(context);
+                for(CHRConstraint constraint : include.ruleset.constraints) {
+                    context.newCHRConstraint(constraint.name, constraint);
+                    constraintSourceMap.put(constraint, include);
+                }
+            } catch (AmbiguousNameException e) {
+                failedIncludes = true;
+                context.getErrorLog().log(include.name.location, e.getMessage());
+            }
+        }
+        if(failedIncludes)
+            return;
         for(CHRConstraint constraint : constraints)
             context.newCHRConstraint(constraint.name, constraint);
         priorityCount = 0;
@@ -82,26 +118,36 @@ public class CHRRuleset extends Symbol {
     }
 
     public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
+        for(IncludeStatement include : includes)
+            include.value.collectRefs(allRefs, refs);
         for(CHRRule rule : rules)
             rule.collectRefs(allRefs, refs);
     }
 
     public void checkType(TypingContext context) {
+        for(IncludeStatement include : includes)
+            include.value = include.value.checkType(context, include.ruleset.runtimeRulesetType);
         for(CHRRule rule : rules)
             rule.checkType(context);
     }
 
     public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
+        for(IncludeStatement include : includes)
+            include.value.collectVars(allVars, vars);
         for(CHRRule rule : rules)
             rule.collectVars(allVars, vars);
     }
 
     public void forVariables(VariableProcedure procedure) {
+        for(IncludeStatement include : includes)
+            include.value.forVariables(procedure);
         for(CHRRule rule : rules)
             rule.forVariables(procedure);
     }
 
     public void collectFreeVariables(THashSet<Variable> vars) {
+        for(IncludeStatement include : includes)
+            include.value.collectFreeVariables(vars);
         for(CHRRule rule : rules)
             rule.collectFreeVariables(vars);
     }
@@ -113,31 +159,91 @@ public class CHRRuleset extends Symbol {
                 rule.setLocationDeep(loc);
         }
     }
+    
+    public int getMinimumPriority(CHRConstraint constraint) {
+        CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint);
+        if(info == null)
+            return Integer.MAX_VALUE;
+        else
+            return info.minimumPriority;
+    }
+    
+    public int getAndUpdateNextPriority(CHRConstraint constraint, int nextPriority) {
+        CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint);
+        if(info == null)
+            return Integer.MAX_VALUE;
+        else {
+            int result = info.nextPriority;
+            info.nextPriority = nextPriority;
+            return result;
+        }
+    }
 
     public void compile(SimplificationContext context) {
         initializeCodeGeneration(context.getCompilationContext());
+        if(extensible)
+            applyExtensibleDefaults();
         UsageAnalysis.analyzeUsage(this);
-        for(CHRRule rule : rules)
+        for(CHRRule rule : rules) {
             rule.compile(context.getCompilationContext(), initConstraint);
+            for(CHRSearchPlan plan : rule.plans) {
+                CHRConstraint constraint = plan.constraint;
+                if(!activeConstraintGGInfo.containsKey(constraint)) {
+                    activeConstraintGGInfo.put(constraint, new CHRConstraintGGInfo(rule.priority));
+                    IncludeStatement include = constraintSourceMap.get(constraint);
+                    if(include != null) {
+                        ArrayList<CHRConstraint> list = inverseActiveConstraintSourceMap.get(include);
+                        if(list == null) {
+                            list = new ArrayList<CHRConstraint>(4);
+                            inverseActiveConstraintSourceMap.put(include, list);
+                        }
+                        list.add(constraint);
+                    }
+                }
+            }
+        }
         // remove init constraint if it is not useful
-        if(initConstraint.minimumPriority == Integer.MAX_VALUE) {
+        if(getMinimumPriority(initConstraint) == Integer.MAX_VALUE) {
             constraints.remove(0);
             initConstraint = null;
         }
     }
 
+    private void applyExtensibleDefaults() {
+        for(CHRConstraint constraint : constraints) {
+            // FIXME Too much indexing!!!
+            int max = 1 << constraint.parameterTypes.length;
+            for(int i=0;i<max;++i)
+                constraint.getOrCreateIndex(cachedContext, i);
+            /*
+            constraint.getOrCreateIndex(cachedContext, 0);
+            if(constraint.parameterTypes.length > 0)
+                constraint.getOrCreateIndex(cachedContext, 1);*/
+        }
+    }
+
     public void simplify(SimplificationContext context) {
+        for(IncludeStatement include : includes)
+            include.value = include.value.simplify(context);
         for(CHRRule rule : rules)
             rule.simplify(context);
     }
     
+    public void setRulesetType(TCon type, String className) {
+        this.runtimeRulesetType = type;
+        this.runtimeRulesetClassName = className;
+    }
+    
     public void initializeCodeGeneration(CompilationContext context) {
         cachedContext = context; // FIXME remove
         
-        String suffix = context.namingPolicy.getFreshClosureClassNameSuffix();
-        runtimeRulesetType = Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix);
-        runtimeRulesetName = context.namingPolicy.getModuleClassName() + suffix;
-        runtimeRulesetTypeDesc = TypeDesc.forClass(runtimeRulesetName);
+        boolean createTypeDesc = false;
+        if(runtimeRulesetType == null) {
+            String suffix = context.namingPolicy.getFreshClosureClassNameSuffix();
+            setRulesetType(Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix), context.namingPolicy.getModuleClassName() + suffix);
+            createTypeDesc = true;
+        }
+        runtimeRulesetTypeDesc = TypeDesc.forClass(runtimeRulesetClassName);
         runtimeRulesetVariable = new BoundVar(runtimeRulesetType);
         for(CHRConstraint constraint : constraints)
             constraint.initializeCodeGeneration(context, this);
@@ -145,14 +251,18 @@ public class CHRRuleset extends Symbol {
                 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(context.module != null) // for unit testing
+        if(createTypeDesc && context.module != null) // for unit testing
             context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc));
     }
 
     public static final Constant ACTIVATE = new JavaMethod(true, CHRCodeGenerationConstants.CHRContext_name, "activate", Types.PROC, Types.UNIT, Types.CHRContext, Types.INTEGER);
     private static final Constant CREATE_CHR_CONTEXT = new JavaConstructor("org/simantics/scl/runtime/chr/CHRContext", Types.PROC, Types.CHRContext);
     
-    public void generateCode(CodeWriter w) {
+    public IVal generateCode(CodeWriter w) {
+        for(IncludeStatement include : includes) {
+            include.storeVar = include.value.toVal(cachedContext.environment, w);
+            initialPriorityNumber = Math.max(initialPriorityNumber, include.ruleset.initialPriorityNumber + include.ruleset.priorityCount);
+        }
         CHRRulesetObject object = new CHRRulesetObject(runtimeRulesetVariable, this);
         w.defineObject(object);
         for(CHRRule rule : rules) {
@@ -170,12 +280,45 @@ public class CHRRuleset extends Symbol {
                     methodWriter.return_(BooleanConstant.TRUE);
             }
         }
+        if(!includes.isEmpty()) {
+            {
+                CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext});
+                initializer = methodWriter.getFunction();
+                for(IncludeStatement include : includes) {
+                    methodWriter.apply(include.location,
+                            new JavaMethod(true, runtimeRulesetClassName, "register", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}),
+                            object.getTarget(), methodWriter.getParameters()[0], include.storeVar);
+                }
+                methodWriter.return_(NoRepConstant.UNIT);
+            }
+            {
+                CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext});
+                deinitializer = methodWriter.getFunction();
+                for(IncludeStatement include : includes) {
+                    methodWriter.apply(include.location,
+                            new JavaMethod(true, runtimeRulesetClassName, "unregister", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}),
+                            object.getTarget(), methodWriter.getParameters()[0], include.storeVar);
+                }
+                methodWriter.return_(NoRepConstant.UNIT);
+            }
+        }
         if(initConstraint != null) {
             IVal chrContext = w.apply(location, CREATE_CHR_CONTEXT);
+            if(initializer != null) {
+                w.apply(location,
+                        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);
             w.apply(location, initConstraint.addProcedure, runtimeRulesetVariable, chrContext, initFact);
             w.apply(location, ACTIVATE, chrContext, new IntegerConstant(Integer.MAX_VALUE));
+            if(deinitializer != null) {
+                w.apply(location,
+                        new JavaMethod(true, runtimeRulesetClassName, "deinitialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
+                        object.getTarget(), chrContext);
+            }
         }
+        return runtimeRulesetVariable;
     }
 
     public void collectEffects(THashSet<Type> effects) {
index a15e30e42638d6674a542478de4e3e8cd9aeaebb..96e86aed1df99760e52a6f6184665c0f50364238 100644 (file)
@@ -1,16 +1,31 @@
 package org.simantics.scl.compiler.elaboration.chr;
 
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.constants.JavaConstructor;
 import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator;
 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
 import org.simantics.scl.compiler.internal.codegen.ssa.SSAObject;
+import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
 import org.simantics.scl.compiler.types.Types;
 
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.procedure.TIntProcedure;
+import gnu.trove.set.hash.TIntHashSet;
+
 public class CHRRulesetObject extends SSAObject {
     CHRRuleset ruleset;
 
+    public BoundVar this_;
+    public BoundVar[] parameters;
+    public TObjectIntHashMap<BoundVar> parameterIndexMap; 
+    public TypeDesc[] parameterTypeDescs;
+    
     public CHRRulesetObject(BoundVar target, CHRRuleset ruleset) {
         super(ruleset.runtimeRulesetType);
         this.setTarget(target);
@@ -19,13 +34,50 @@ public class CHRRulesetObject extends SSAObject {
     
     @Override
     public Constant liftClosure(BoundVar newTarget, BoundVar[] parameters) {
-        ruleset.this_ = newTarget;
-        ruleset.parameters = parameters;
-        return new JavaConstructor(ruleset.runtimeRulesetName, Types.PROC, ruleset.runtimeRulesetType, Types.getTypes(parameters));
+        ruleset.rulesetObject = this;
+        this.this_ = newTarget;
+        this.parameters = parameters;
+        this.parameterIndexMap = new TObjectIntHashMap<>(parameters.length);
+        for(int i=0;i<parameters.length;++i)
+            this.parameterIndexMap.put(parameters[i], i);
+        return new JavaConstructor(ruleset.runtimeRulesetClassName, Types.PROC, ruleset.runtimeRulesetType, Types.getTypes(parameters));
     }
     
     @Override
     public void generateCode(ModuleBuilder moduleBuilder) {
         CHRRuntimeRulesetCodeGenerator.generateRuntimeRuleset(moduleBuilder, ruleset);
     }
+    
+    @FunctionalInterface
+    public interface ParameterDefiner {
+        public void defineParameter(int index, BoundVar var);
+    }
+    
+    public void realizeMethod(MethodBuilder mb, ParameterDefiner loader, SSAFunction function, LocalVariable this_, LocalVariable ... callParameters) {
+        mb.setLocalVariable(this.this_, this_);
+        BoundVar[] functionParameters = function.getParameters();
+        if(functionParameters.length != callParameters.length)
+            throw new InternalCompilerError();
+        for(int i=0;i<callParameters.length;++i)
+            mb.setLocalVariable(functionParameters[i], callParameters[i]);
+
+        // Set closure parameters
+        TIntHashSet usedParameterIndices = new TIntHashSet(parameters.length);
+        function.forValRefs(valRef -> {
+            Val binding = valRef.getBinding();
+            if(parameterIndexMap.containsKey(binding))
+                usedParameterIndices.add(parameterIndexMap.get((BoundVar)binding));
+        });
+        usedParameterIndices.forEach(new TIntProcedure() {
+            @Override
+            public boolean execute(int i) {
+                loader.defineParameter(i, parameters[i]);
+                return true;
+            }
+        });
+
+        // Generate code
+        function.markGenerateOnFly();
+        function.generateCodeWithAlreadyPreparedParameters(mb);
+    }
 }
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/CHRConstraintGGInfo.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/CHRConstraintGGInfo.java
new file mode 100644 (file)
index 0000000..dbe33d6
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.scl.compiler.elaboration.chr.analysis;
+
+public class CHRConstraintGGInfo {
+    public int minimumPriority;
+    public int nextPriority = Integer.MAX_VALUE;
+    
+    public CHRConstraintGGInfo(int minimumPriority) {
+        this.minimumPriority = minimumPriority;
+    }
+}
index 3d5e0246bfd0a44e62dee6312fd29e2f3a37384b..a738c1f42126ebc7d0f01788f2e48ce1129021f3 100644 (file)
@@ -12,13 +12,14 @@ import gnu.trove.map.hash.THashMap;
 public class UsageAnalysis {
     public static void analyzeUsage(CHRRuleset ruleset) {
         THashMap<CHRConstraint,ArrayList<CHRRule>> headConstraintMap = createHeadConstraintMap(ruleset);
-        calculateFirstPriorities(ruleset, headConstraintMap);
+        //calculateFirstPriorities(ruleset, headConstraintMap);
         calculateLastPriorities(ruleset, headConstraintMap);
-        for(CHRRule rule : ruleset.rules)
-            determinePassiveLiterals(rule);
+        if(!ruleset.extensible)
+            for(CHRRule rule : ruleset.rules)
+                determinePassiveLiterals(rule);
         //printPriorities(ruleset);
     }
-
+    /*
     private static void calculateFirstPriorities(CHRRuleset ruleset,
             THashMap<CHRConstraint, ArrayList<CHRRule>> headConstraintMap) {
         for(CHRRule rule : ruleset.rules)
@@ -39,15 +40,14 @@ public class UsageAnalysis {
                 int constraintPriority = constraint.firstPriorityAdded;
                 if(constraintPriority == Integer.MAX_VALUE)
                     return;
-                result = Math.max(result, constraint.firstPriorityAdded);
+                result = Math.max(result, constraintPriority);
             }
         rule.firstPriorityExecuted = result;
         for(CHRLiteral literal : rule.head.literals)
             if(literal.killAfterMatch && literal.relation instanceof CHRConstraint) {
                 CHRConstraint constraint = (CHRConstraint)literal.relation;
-                if(constraint.firstPriorityRemoved != Integer.MAX_VALUE)
-                    continue;
-                constraint.firstPriorityRemoved = result;
+                if(constraint.firstPriorityRemoved == Integer.MAX_VALUE)
+                    constraint.firstPriorityRemoved = result;
             }
         for(CHRLiteral literal : rule.body.literals)
             if(literal.relation instanceof CHRConstraint) {
@@ -60,15 +60,17 @@ public class UsageAnalysis {
                     continue;
                 for(CHRRule lowerPriorityRule : list)
                     if(lowerPriorityRule.priority < rule.priority)
+                        // We know here that previous call to lowerPriorityRule "failed",
+                        // because constraint.firstPriorityAdded was previously Integer.MAX_VALUE
                         calculateFirstPriority(headConstraintMap, lowerPriorityRule);
             }
     }
-
+    */
     private static void calculateLastPriorities(CHRRuleset ruleset,
             THashMap<CHRConstraint, ArrayList<CHRRule>> headConstraintMap) {
         for(CHRRule rule : ruleset.rules)
             rule.lastPriorityExecuted = Integer.MIN_VALUE;
-        for(CHRConstraint constraint : ruleset.constraints) {
+        for(CHRConstraint constraint : headConstraintMap.keySet()) {
             constraint.lastPriorityAdded = Integer.MIN_VALUE;
             constraint.lastPriorityRemoved = Integer.MIN_VALUE;
         }
@@ -85,9 +87,8 @@ public class UsageAnalysis {
         for(CHRLiteral literal : rule.head.literals)
             if(literal.killAfterMatch && literal.relation instanceof CHRConstraint) {
                 CHRConstraint constraint = (CHRConstraint)literal.relation;
-                if(constraint.lastPriorityRemoved != Integer.MIN_VALUE)
-                    continue;
-                constraint.lastPriorityRemoved = priority;
+                if(constraint.lastPriorityRemoved == Integer.MIN_VALUE)
+                    constraint.lastPriorityRemoved = priority;
             }
         for(CHRLiteral literal : rule.body.literals)
             if(literal.relation instanceof CHRConstraint) {
@@ -121,7 +122,7 @@ public class UsageAnalysis {
         return map;
     }
     
-    private static void printPriorities(CHRRuleset ruleset) {
+    /*private static void printPriorities(CHRRuleset ruleset) {
         System.out.println("-------------------------------");
         for(CHRConstraint constraint : ruleset.constraints) {
             System.out.print(" [" + constraint.firstPriorityAdded + ".." + constraint.lastPriorityAdded + "]");
@@ -135,7 +136,7 @@ public class UsageAnalysis {
             System.out.print(" [" + rule.firstPriorityExecuted + ".." + rule.lastPriorityExecuted + "] ");
             System.out.println(rule);
         }
-    }
+    }*/
 
     private static void determinePassiveLiterals(CHRRule rule) {
         for(CHRLiteral literal : rule.head.literals) {
index e4484a93370d62f32bc89c03ff33fe38699263f0..5b7f81664770503a81b70ed59ac29804f602ece7 100644 (file)
@@ -31,7 +31,7 @@ public class ClaimOp extends PlanOp {
         for(int i=0;i<parameters.length;++i)
             parameterVars[i+1] = parameters[i].toVal(context.environment, w);
         IVal newFact = w.apply(location, constraint.constructor, parameterVars);
-        w.apply(location, constraint.addProcedure, planContext.storeVar, planContext.contextVar, newFact);
+        w.apply(location, constraint.addProcedure, planContext.getStoreVar(constraint), planContext.contextVar, newFact);
         planContext.nextOp(w);
     }
 
index 7390286e5a5cff3e1c7f7b11a37760c6b8fbf5ea..95c341e9f369ecce5558f4ea0a1013da94a0c378 100644 (file)
@@ -55,7 +55,7 @@ public class IterateConstraintOp extends PlanOp {
         IVal fact = body.getParameters()[0];
 
         ArrayList<IVal> parameters = new ArrayList<IVal>(expressions.length+1);
-        parameters.add(planContext.storeVar);
+        parameters.add(planContext.getStoreVar(constraint));
         for(int i=0;i<expressions.length;++i)
             if(((boundMask>>i)&1)==1)
                 parameters.add(expressions[i].toVal(context.environment, w));
index 0ed3f8975d9bbaae4964d8f184453fdaa744b658..bc6b7da580e3b43a5e43bbf3b646fb1902ee01e7 100644 (file)
@@ -10,7 +10,9 @@ import org.simantics.scl.compiler.constants.singletons.JustConstant;
 import org.simantics.scl.compiler.constants.singletons.ListElement;
 import org.simantics.scl.compiler.constants.singletons.ListLength;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
+import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
 import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.elaboration.java.EqualsFunction;
 import org.simantics.scl.compiler.internal.codegen.continuations.Branch;
 import org.simantics.scl.compiler.internal.codegen.continuations.ICont;
@@ -22,15 +24,15 @@ import org.simantics.scl.compiler.types.Types;
 public abstract class PlanContext {
     public CompilationContext context;
     public CHRRuleset ruleset;
-    public IVal storeVar;
+    public IVal mainStoreVar;
     public IVal contextVar;
     public ArrayList<PartnerFact> partnerFacts = new ArrayList<PartnerFact>();
     public IVal currentId;
     
-    public PlanContext(CompilationContext context, CHRRuleset ruleset, IVal storeVar, IVal contextVar) {
+    public PlanContext(CompilationContext context, CHRRuleset ruleset, IVal mainStoreVar, IVal contextVar) {
         this.context = context;
         this.ruleset = ruleset;
-        this.storeVar = storeVar;
+        this.mainStoreVar = mainStoreVar;
         this.contextVar = contextVar;
     }
 
@@ -116,4 +118,12 @@ public abstract class PlanContext {
         
         w.continueAs(end);
     }
+
+    public IVal getStoreVar(CHRConstraint constraint) {
+        IncludeStatement includeStatement = ruleset.constraintSourceMap.get(constraint);
+        if(includeStatement != null)
+            return includeStatement.storeVar;
+        else
+            return mainStoreVar;
+    }
 }
index de00093cfcd9cc7c31d3576693062a3d62c0434a..5b3057dd9dc099da6d13121568f399fc912d4285 100644 (file)
@@ -27,7 +27,7 @@ public class PostCommitOp extends PlanOp {
         if(planContext.currentId != null) {
             w.apply(location, planContext.ruleset.writeCurrentId, planContext.contextVar, planContext.currentId);
             planContext.currentId = null;
-            w.apply(location, CHRRuleset.ACTIVATE, planContext.contextVar, new IntegerConstant(priority));
+            w.apply(location, CHRRuleset.ACTIVATE, planContext.contextVar, new IntegerConstant(priority+planContext.ruleset.initialPriorityNumber));
         }
         for(PartnerFact activeFact : planContext.partnerFacts) {
             if(activeFact.killAfterMatch) {
index 95e865be30afd94e1aceff39330bb5f8db642bbb..c4629f6d0c8e8c4f690163bbd544456dfe631e2b 100644 (file)
@@ -17,7 +17,7 @@ public class PreCommitOp extends PlanOp {
     public void generateCode(CompilationContext context, PlanContext planContext, CodeWriter w) {
         for(PartnerFact activeFact : planContext.partnerFacts) {
             if(activeFact.killAfterMatch)
-                w.apply(location, activeFact.constraint.removeProcedure, planContext.storeVar, activeFact.factVar);
+                w.apply(location, activeFact.constraint.removeProcedure, planContext.getStoreVar(activeFact.constraint), activeFact.factVar);
         }
         planContext.nextOp(w);
     }
index 8612fd766ade4410ad9b1706f887e2504e29273b..c0f43928877458cbb9a9241ad3e764481acd3ce5 100644 (file)
@@ -38,9 +38,9 @@ public class CHRConstraint extends Symbol implements CHRRelation {
     public boolean implicitlyDeclared;
 
     // Analysis
-    public int firstPriorityAdded;
+    //public int firstPriorityAdded;
     public int lastPriorityAdded;
-    public int firstPriorityRemoved;
+    //public int firstPriorityRemoved;
     public int lastPriorityRemoved;
     
     // Transient info
@@ -56,11 +56,9 @@ public class CHRConstraint extends Symbol implements CHRRelation {
     public Constant addProcedure;
     public Constant removeProcedure;
     
-    public TIntObjectHashMap<IndexInfo> indices;
+    public String nextContainerFieldName;
     
-    // Query plans
-    public int minimumPriority = Integer.MAX_VALUE;
-    public int nextPriority = Integer.MAX_VALUE; // used in code generation
+    public TIntObjectHashMap<IndexInfo> indices;
     
     public static class IndexInfo {
         public final int indexMask;
@@ -86,7 +84,7 @@ public class CHRConstraint extends Symbol implements CHRRelation {
         JavaTypeTranslator jtt = context.javaTypeTranslator;
         
         this.parentRuleset = parentRuleset;
-        this.factClassName = parentRuleset.runtimeRulesetName + "$" + name;
+        this.factClassName = parentRuleset.runtimeRulesetClassName + "$" + name;
         TCon factTypeConstructor = Types.con(parentRuleset.runtimeRulesetType.module, parentRuleset.runtimeRulesetType.name + "$" + name); 
         this.factType = Types.apply(factTypeConstructor, TVar.EMPTY_ARRAY);
         this.factTypeDesc = TypeDesc.forClass(factClassName);
@@ -126,6 +124,11 @@ public class CHRConstraint extends Symbol implements CHRRelation {
         
         if(context.module != null) // for unit testing
             context.module.addTypeDescriptor(factTypeConstructor.name, new StandardTypeConstructor(factTypeConstructor, TVar.EMPTY_ARRAY, factTypeDesc));
+        
+        // next container
+        if(parentRuleset.extensible) {
+            nextContainerFieldName = CHRCodeGenerationConstants.nextContainerName(name);
+        }
     }
 
     @Override
@@ -161,11 +164,11 @@ public class CHRConstraint extends Symbol implements CHRRelation {
         Constant accessIndex;
         if(indexMask == 0) {
             accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.runtimeRulesetType},
-                    null, new FieldRef(parentRuleset.runtimeRulesetName, name + "$" + indexName, factTypeDesc), null);
+                    null, new FieldRef(parentRuleset.runtimeRulesetClassName, name + "$" + indexName, factTypeDesc), null);
         }
         else {
             Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]);
-            accessIndex = new JavaMethod(true, parentRuleset.runtimeRulesetName, name + "$" + indexName, Types.PROC, factType, keyTypes);
+            accessIndex = new JavaMethod(true, parentRuleset.runtimeRulesetClassName, name + "$" + indexName, Types.PROC, factType, keyTypes);
         }
         return new IndexInfo(
                 indexMask,
@@ -176,13 +179,17 @@ public class CHRConstraint extends Symbol implements CHRRelation {
                 );
     }
     
-    public IVal fetchFromIndex(CompilationContext context, int boundMask) {
+    public IndexInfo getOrCreateIndex(CompilationContext context, int boundMask) {
         IndexInfo indexInfo = indices.get(boundMask);
         if(indexInfo == null) {
             indexInfo = createIndexInfo(context, boundMask);
             indices.put(boundMask, indexInfo);
         }
-        return indexInfo.firstFact;
+        return indexInfo;
+    }
+    
+    public IVal fetchFromIndex(CompilationContext context, int boundMask) {
+        return getOrCreateIndex(context, boundMask).firstFact;
     }
 
     public Constant nextElement(CompilationContext context, int boundMask) {
@@ -191,7 +198,7 @@ public class CHRConstraint extends Symbol implements CHRRelation {
             indexInfo = createIndexInfo(context, boundMask);
             indices.put(boundMask, indexInfo);
         }
-        return indexInfo.nextFact;
+        return getOrCreateIndex(context, boundMask).nextFact;
     }
 
     
index 203bd81d2d2bd925b9fd9ee969aa475db7b31331..d9746bb04c1d9a2524e82a03193c80a6773ee450 100644 (file)
@@ -8,6 +8,7 @@ import org.simantics.scl.compiler.common.names.Names;
 import org.simantics.scl.compiler.common.precedence.Associativity;
 import org.simantics.scl.compiler.common.precedence.Precedence;
 import org.simantics.scl.compiler.compilation.CompilationContext;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
 import org.simantics.scl.compiler.elaboration.expressions.Case;
 import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous;
@@ -521,4 +522,8 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     public SCLValue getValue(Name name) {
         return environment.getValue(name);
     }
+
+    public CHRRuleset resolveRuleset(String name) throws AmbiguousNameException {
+        return Environments.getRuleset(environment, name);
+    }
 }
index 927720611de5cab6816d5b517223bea54ff34995..1eea959fd249459273a9139008b86d29ac9a2d0c 100644 (file)
@@ -126,4 +126,8 @@ public class TypeTranslationContext {
             errorLog.log(loc, "Expected a type with kind " + expectedKind + " but got " + provided + ".");
         }
     }
+    
+    public CompilationContext getCompilationContext() {
+        return compilationContext;
+    }
 }
index c5f30417eed13983d839b211a1a8cf1f88aacc25..157efb360302cdf5767ce936f7c64454f9a5baa1 100644 (file)
@@ -1,7 +1,6 @@
 package org.simantics.scl.compiler.elaboration.expressions;
 
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
 
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
@@ -11,6 +10,7 @@ import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
 import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
@@ -19,7 +19,7 @@ import org.simantics.scl.compiler.errors.Locations;
 
 public class EBlock extends ASTExpression {
 
-    LinkedList<Statement> statements = new LinkedList<Statement>();
+    ArrayList<Statement> statements = new ArrayList<Statement>();
     boolean monadic;
     
     public EBlock() {
@@ -33,9 +33,17 @@ public class EBlock extends ASTExpression {
         this.monadic = monadic;
     }
     
-    public LinkedList<Statement> getStatements() {
+    public ArrayList<Statement> getStatements() {
         return statements;
     }
+    
+    public Statement getFirst() {
+        return statements.get(0);
+    }
+    
+    public Statement getLast() {
+        return statements.get(statements.size()-1);
+    }
 
     @Override
     public Expression resolve(TranslationContext context) {
@@ -66,7 +74,7 @@ public class EBlock extends ASTExpression {
                     in = extractRules(i, endId, in);
                     break;
                 case CHR:
-                    in = extractCHRRules(context, i, endId, in);
+                    in = new ECHRRuleset(extractCHRRules(context, i, endId), in);
                     break;
                 }
             }
@@ -78,7 +86,7 @@ public class EBlock extends ASTExpression {
         return new EPreRuleset(statements.subList(begin, end).toArray(new RuleStatement[end-begin]), in);
     }
     
-    private Expression extractCHRRules(TranslationContext context, int begin, int end, Expression in) {
+    private CHRRuleset extractCHRRules(TranslationContext context, int begin, int end) {
         CHRRuleset ruleset = new CHRRuleset();
         ruleset.location = Locations.combine(statements.get(begin).location, statements.get(end-1).location);
         for(int i=begin;i<end;++i) {
@@ -87,12 +95,18 @@ public class EBlock extends ASTExpression {
                 ruleset.rules.add(CHRTranslation.convertCHRStatement(context, (CHRStatement)statement));
             else if(statement instanceof ConstraintStatement)
                 ruleset.constraints.add(CHRTranslation.convertConstraintStatement(context, (ConstraintStatement)statement));
+            else if(statement instanceof IncludeStatement)
+                ruleset.includes.add((IncludeStatement)statement);
             else
-                throw new InternalCompilerError("Invalid CHR statement.");
+                context.getErrorLog().log(statement.location, "Invalid CHR statement.");
         }
-        return new ECHRRuleset(ruleset, in);
+        return ruleset;
     }
 
+    public CHRRuleset extractCHRRules(TranslationContext context) {
+        return extractCHRRules(context, 0, statements.size());
+    }
+    
     @SuppressWarnings("unchecked")
     private Expression extractLet(int begin, int end, Expression in) {
         return new EPreLet((List<LetStatement>)(List<?>)statements.subList(begin, end), in);
@@ -123,7 +137,7 @@ public class EBlock extends ASTExpression {
     public int getSyntacticFunctionArity() {
         if(monadic)
             return 0;
-        Statement lastStatement = statements.getLast();
+        Statement lastStatement = statements.get(statements.size()-1);
         if(!(lastStatement instanceof GuardStatement))
             return 0;
         return ((GuardStatement)lastStatement).value.getSyntacticFunctionArity();
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRRulesetConstructor.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRRulesetConstructor.java
new file mode 100644 (file)
index 0000000..e8a5cb8
--- /dev/null
@@ -0,0 +1,105 @@
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.codegen.references.IVal;
+import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
+import org.simantics.scl.compiler.internal.interpreted.IExpression;
+import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+public class ECHRRulesetConstructor extends Expression {
+    CHRRuleset ruleset;
+    
+    public ECHRRulesetConstructor(CHRRuleset ruleset) {
+        this.ruleset = ruleset;
+    }
+    
+    @Override
+    public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
+        ruleset.collectRefs(allRefs, refs);
+    }
+    @Override
+    public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
+        ruleset.collectVars(allVars, vars);
+    }
+    @Override
+    public void forVariables(VariableProcedure procedure) {
+        ruleset.forVariables(procedure);
+    }
+    @Override
+    protected void updateType() throws MatchException {
+        throw new InternalCompilerError("Type of ECHRRulesetConstructor should be already given.");
+    }
+    @Override
+    public IVal toVal(Environment env, CodeWriter w) {
+        return ruleset.generateCode(w);
+    }
+    @Override
+    public void collectFreeVariables(THashSet<Variable> vars) {
+        ruleset.collectFreeVariables(vars);
+    }
+    @Override
+    public Expression resolve(TranslationContext context) {
+        context.pushFrame();
+        context.pushCHRConstraintFrame();
+        ruleset.resolve(context);
+        context.popCHRConstraintFrame(ruleset.constraints);
+        context.popFrame();
+        return this;
+    }
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            this.location = loc;
+            ruleset.setLocationDeep(loc);
+        }
+    }
+    @Override
+    public Expression decorate(ExpressionDecorator decorator) {
+        return this;
+    }
+    @Override
+    public void collectEffects(THashSet<Type> effects) {
+        ruleset.collectEffects(effects);
+    }
+    @Override
+    public void accept(ExpressionVisitor visitor) {
+        visitor.visit(this);
+    }
+    
+    @Override
+    public Expression inferType(TypingContext context) {
+        ruleset.checkType(context);
+        return this;
+    }
+    
+    @Override
+    public Expression simplify(SimplificationContext context) {
+        ruleset.simplify(context);
+        ruleset.compile(context);
+        return this;
+    }
+    
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        return transformer.transform(this);
+    }
+    
+    @Override
+    public IExpression toIExpression(ExpressionInterpretationContext context) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRRulesetConstructor.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRRulesetConstructor.java
new file mode 100644 (file)
index 0000000..500c805
--- /dev/null
@@ -0,0 +1,41 @@
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRulesetAst;
+
+public class EPreCHRRulesetConstructor extends ASTExpression {
+    DRulesetAst rulesetAst;
+    
+    public EPreCHRRulesetConstructor(DRulesetAst rulesetAst) {
+        this.rulesetAst = rulesetAst;
+        this.location = rulesetAst.location;
+    }
+
+    @Override
+    public Expression resolve(TranslationContext context) {
+        CHRRuleset ruleset = rulesetAst.block.extractCHRRules(context);
+        ruleset.setLocationDeep(rulesetAst.location);
+        ruleset.setRulesetType(rulesetAst.type, rulesetAst.className);
+        ruleset.extensible = true;
+        context.getCompilationContext().module.addRuleset(rulesetAst.name, ruleset);
+        ECHRRulesetConstructor result = new ECHRRulesetConstructor(ruleset);
+        result.resolve(context);
+        result.setType(rulesetAst.type);
+        return result;
+    }
+
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            rulesetAst.block.setLocationDeep(loc);
+            location = loc;
+        }
+    }
+
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        return this;
+    }
+}
index 8d54d50633c7289c5311cfc03e4b7f2b48993e83..4cf513c542647b1ccc3c8e1dd7cc8f020447c66d 100644 (file)
@@ -10,6 +10,7 @@ public interface ExpressionTransformer {
     Expression transform(EBind expression);
     Expression transform(EBlock expression);
     Expression transform(ECHRRuleset expression);
+    Expression transform(ECHRRulesetConstructor expression);
     Expression transform(EConstant expression);
     Expression transform(ECoveringBranchPoint expression);
     Expression transform(EEnforce expression);
index 62e21f204b182b66a9446e3ed28aeea285eeb502..ad32098baadb7538d27c699c41d4dcf906df486a 100644 (file)
@@ -8,7 +8,8 @@ public interface ExpressionVisitor {
     void visit(EBinary expression);
     void visit(EBind expression);
     void visit(EBlock expression);
-    void visit(ECHRRuleset echrRuleset);
+    void visit(ECHRRuleset expression);
+    void visit(ECHRRulesetConstructor expression);
     void visit(EConstant expression);
     void visit(ECoveringBranchPoint expression);
     void visit(EEnforce expression);
index 5d1d2eb9544493172ee1cb24af7085734659998c..ac61eb4866844c1822abf0c7323f958df6b9cbaa 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.scl.compiler.elaboration.expressions;
 
 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.equation.EqBasic;
 import org.simantics.scl.compiler.elaboration.equation.EqGuard;
 import org.simantics.scl.compiler.elaboration.equation.Equation;
@@ -9,6 +10,7 @@ import org.simantics.scl.compiler.elaboration.equation.EquationVisitor;
 import org.simantics.scl.compiler.elaboration.expressions.accessor.ExpressionAccessor;
 import org.simantics.scl.compiler.elaboration.expressions.block.BindStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
@@ -118,9 +120,12 @@ EquationVisitor {
     }
 
     @Override
-    public Expression transform(ECHRRuleset expression) {
-        expression.in = expression.in.accept(this);
-        for(CHRRule rule : expression.ruleset.rules) {
+    public void visit(IncludeStatement statement) {
+        statement.value = statement.value.accept(this);
+    }
+    
+    public void transform(CHRRuleset ruleset) {
+        for(CHRRule rule : ruleset.rules) {
             for(CHRLiteral lit : rule.head.literals)
                 for(int i=0;i<lit.parameters.length;++i)
                     lit.parameters[i] = lit.parameters[i].accept(this);
@@ -128,6 +133,18 @@ EquationVisitor {
                 for(int i=0;i<lit.parameters.length;++i)
                     lit.parameters[i] = lit.parameters[i].accept(this);
         }
+    }
+    
+    @Override
+    public Expression transform(ECHRRuleset expression) {
+        expression.in = expression.in.accept(this);
+        transform(expression.ruleset);
+        return expression;
+    }
+    
+    @Override
+    public Expression transform(ECHRRulesetConstructor expression) {
+        transform(expression.ruleset);
         return expression;
     }
 
index ef247bf131279042292cad01a6889e0be700b378..be9be3109c75fe29a08fe119f88529a8788519aa 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.scl.compiler.elaboration.expressions;
 
 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.equation.EqBasic;
 import org.simantics.scl.compiler.elaboration.equation.EqGuard;
 import org.simantics.scl.compiler.elaboration.equation.Equation;
@@ -13,6 +14,7 @@ import org.simantics.scl.compiler.elaboration.expressions.accessor.IdAccessor;
 import org.simantics.scl.compiler.elaboration.expressions.accessor.StringAccessor;
 import org.simantics.scl.compiler.elaboration.expressions.block.BindStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
@@ -351,10 +353,9 @@ EquationVisitor, StatementVisitor {
         for(Equation equation : expression.equations)
             equation.accept(this);
     }
-
-    @Override
-    public void visit(ECHRRuleset ruleset) {
-        for(CHRRule rule : ruleset.ruleset.rules) {
+    
+    public void visit(CHRRuleset ruleset) {
+        for(CHRRule rule : ruleset.rules) {
             for(CHRLiteral literal : rule.head.literals)
                 for(Expression parameter : literal.parameters)
                     parameter.accept(this);
@@ -362,7 +363,17 @@ EquationVisitor, StatementVisitor {
                 for(Expression parameter : literal.parameters)
                     parameter.accept(this);
         }
-        ruleset.in.accept(this);
+    }
+
+    @Override
+    public void visit(ECHRRuleset expression) {
+        visit(expression.ruleset);
+        expression.in.accept(this);
+    }
+    
+    @Override
+    public void visit(ECHRRulesetConstructor expression) {
+        visit(expression.ruleset);
     }
 
     @Override
@@ -428,4 +439,8 @@ EquationVisitor, StatementVisitor {
         statement.body.accept(this);
     }
 
+    @Override
+    public void visit(IncludeStatement statement) {
+        statement.value.accept(this);
+    }
 }
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/block/IncludeStatement.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/block/IncludeStatement.java
new file mode 100644 (file)
index 0000000..52152b1
--- /dev/null
@@ -0,0 +1,72 @@
+package org.simantics.scl.compiler.elaboration.expressions.block;
+
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
+import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.codegen.references.IVal;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
+import org.simantics.scl.compiler.internal.parsing.Token;
+import org.simantics.scl.compiler.types.Type;
+
+public class IncludeStatement extends Statement implements ValRefBinder {
+    public Token name;
+    public Expression value;
+    
+    public CHRRuleset ruleset;
+    public IVal storeVar; 
+    
+    public IncludeStatement(Token name, Expression value) {
+        this.name = name;
+        this.value = value;
+    }
+    
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            location = loc;
+            value.setLocationDeep(loc);
+        }
+    }
+    
+    @Override
+    public StatementGroup getStatementGroup() {
+        return StatementGroup.CHR;
+    }
+
+    @Override
+    public Expression toExpression(EnvironmentalContext context, boolean monadic, Expression in) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resolvePattern(TranslationContext context) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean mayBeRecursive() {
+        return true;
+    }
+
+    @Override
+    public void accept(StatementVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public SSAFunction getParentFunction() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void replaceByApply(ValRef valRef, Val function, Type[] typeParameters, Val[] parameters2) {
+         throw new UnsupportedOperationException();
+    }
+
+}
\ No newline at end of file
index 5b0d2c0f30c4224ebbfdd66de5a4a7973f1a78b7..2d90774feff1345c144be9392015537ad86417e8 100644 (file)
@@ -5,4 +5,5 @@ public interface StatementVisitor {
     void visit(GuardStatement statement);
     void visit(LetStatement statement);
     void visit(RuleStatement statement);
+    void visit(IncludeStatement statement);
 }
index 59e7d8909f24967e71400ba86067053550e6f5e9..3f6da74cb9ffd9f7cf0daddd78f4dfe4bbc775ba 100644 (file)
@@ -15,6 +15,7 @@ import org.simantics.scl.compiler.elaboration.expressions.EBinary;
 import org.simantics.scl.compiler.elaboration.expressions.EBind;
 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
 import org.simantics.scl.compiler.elaboration.expressions.ECHRRuleset;
+import org.simantics.scl.compiler.elaboration.expressions.ECHRRulesetConstructor;
 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
 import org.simantics.scl.compiler.elaboration.expressions.ECoveringBranchPoint;
 import org.simantics.scl.compiler.elaboration.expressions.EEnforce;
@@ -520,13 +521,18 @@ public class ExpressionToStringVisitor implements ExpressionVisitor, QueryVisito
     }
 
     @Override
-    public void visit(EEquations eEquations) {
+    public void visit(EEquations expression) {
         b.append("eq");
     }
 
     @Override
-    public void visit(ECHRRuleset echrRuleset) {
-        b.append("CHRRuleset");
+    public void visit(ECHRRuleset expression) {
+        b.append("ECHRRuleset");
+    }
+    
+    @Override
+    public void visit(ECHRRulesetConstructor expression) {
+        b.append("ECHRRulesetConstructor");
     }
 
     public void visit(CHRRule rule) {
index f40221eb57cb79717ef93bc7a51f07fdeffc7de5..c5cd410f48b4aa5e0d346991dd3a0fc473a170d2 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.scl.compiler.environment;
 
 import java.util.function.Consumer;
 
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
 import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
@@ -73,4 +74,9 @@ public enum EmptyNamespace implements Namespace {
     @Override
     public void findTypesForPrefix(String prefix, NamespaceFilter filter, Consumer<TCon> consumer) {
     }
+
+    @Override
+    public CHRRuleset getRuleset(String name) throws AmbiguousNameException {
+        return null;
+    }
 }
index df86c1130e7930b0866a4d8f046d5e14edf3473a..3be214d2d6bd69f66aa4ae59347adeba2b5cb572 100644 (file)
@@ -7,6 +7,7 @@ import java.util.function.Consumer;
 
 import org.simantics.scl.compiler.common.names.Name;
 import org.simantics.scl.compiler.compilation.CompilationContext;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
@@ -107,6 +108,10 @@ public class Environments {
        return getEnvironmentEntry(environment, localName, getTypeClass);
     }
 
+    public static CHRRuleset getRuleset(Environment environment, String localName) throws AmbiguousNameException {
+        return getEnvironmentEntry(environment, localName, getRuleset);
+    }
+    
     /**
      * Get the Name object representing an SCL value defined in a given environment.
      * The name can be a local name or a fully scoped name with modules separated by periods. 
@@ -332,6 +337,13 @@ public class Environments {
                        return ns.getTypeClass(name);
                }               
        };
+       
+    private static final NamespaceValueAccessor<CHRRuleset> getRuleset = new NamespaceValueAccessor<CHRRuleset>() {
+        @Override
+        public CHRRuleset get(Namespace ns, String name) throws AmbiguousNameException {
+            return ns.getRuleset(name);
+        }
+    };
     
        private static <T> T getEnvironmentEntry(Environment environment, String localName, NamespaceValueAccessor<T> accessor) throws AmbiguousNameException {
         Namespace namespace = environment.getLocalNamespace();
index 9b4712c847bacd1ff049d86b0b0d31f1cd88fb1b..e5af69204006bb768891a9665b9c0aeb54af4380 100644 (file)
@@ -1,9 +1,8 @@
 package org.simantics.scl.compiler.environment;
 
-import java.util.List;
 import java.util.function.Consumer;
 
-import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
 import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
@@ -70,6 +69,8 @@ public interface Namespace {
      */
     EffectConstructor getEffectConstructor(String name) throws AmbiguousNameException;
     
+    CHRRuleset getRuleset(String name) throws AmbiguousNameException;
+    
     /**
      * Get a TypeClass for a given name. The same instance is returned on each call.
      * @param name  the name of a defined entity type
index 0c97d308ab680ed87ee6a2dbace1b971ea6e9d3c..214749bcb05b881c660325f29c2d53bd26e61553 100644 (file)
@@ -1,10 +1,9 @@
 package org.simantics.scl.compiler.environment;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.function.Consumer;
 
-import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
 import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
@@ -268,6 +267,33 @@ public class NamespaceImpl implements Namespace {
         return result;
     }
     
+    @Override
+    public CHRRuleset getRuleset(String name) throws AmbiguousNameException {
+        CHRRuleset result = null, temp;
+        Module resultModule = null;
+        ArrayList<String> conflictingModules = null;
+        for(ModuleImport moduleImport : moduleImports) {
+            Module module = moduleImport.module;
+            temp = module.getRuleset(name);
+            if(temp != null) {
+                if(result != null) {
+                    if(conflictingModules == null) {
+                        conflictingModules = new ArrayList<String>(2);
+                        conflictingModules.add(resultModule.getName());
+                    }
+                    conflictingModules.add(module.getName());
+                }   
+                else {
+                    result = temp;
+                    resultModule = module;
+                }
+            }
+        }
+        if(conflictingModules != null)
+            throw new AmbiguousNameException(conflictingModules, name);
+        return result;
+    }
+    
     @Override
     public void findValuesForPrefix(String prefix, NamespaceFilter filter, TObjectProcedure<SCLValue> proc) {
         for(ModuleImport moduleImport : moduleImports)
index 3f95fa5077c043c71ff1ba91663993fba84c828b..37f1202e3d54e239ed52535f84c20cce24224c5d 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.scl.compiler.internal.codegen.chr;
 
 import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 
 public interface CHRCodeGenerationConstants {
 
@@ -34,4 +35,12 @@ public interface CHRCodeGenerationConstants {
     public static String parameterName(int i) {
         return "p" + i;
     }
+
+    public static String includedName(IncludeStatement include) {
+        return "included" + include.name.text; 
+    }
+
+    public static String nextContainerName(String name) {
+        return name + "$nextContainer";
+    }
 }
index e68ed2baeb1e490b1b4618cf88e8c63930c6e3ab..865ab22e6c8e18ed31248bfef8bb17e700a083ac 100644 (file)
@@ -5,6 +5,7 @@ import java.util.ArrayList;
 import org.cojen.classfile.TypeDesc;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.Opcodes;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo;
 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
@@ -20,6 +21,7 @@ public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
     private JavaTypeTranslator jtt;
 
     private ClassBuilder storeClassBuilder;
+    private CHRRuleset ruleset;
     private CHRConstraint constraint;
 
     private String factClassName;
@@ -32,8 +34,9 @@ public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
     private TypeDesc[] parameterTypeDescs;
     private boolean supportsRemoval;
 
-    CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRConstraint constraint) {
+    CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint) {
         this.storeClassBuilder = storeClassBuilder;
+        this.ruleset = ruleset;
         this.constraint = constraint;
 
         this.moduleBuilder = storeClassBuilder.getModuleBuilder();
@@ -123,7 +126,7 @@ public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
                 continue;
             constructorParameters.add(typeDesc);
         }
-        MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
+        MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
         mb.loadThis();
         mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
         mb.loadThis();
@@ -205,13 +208,30 @@ public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
         }
         
         // Add fact to priority queue
-        if(constraint.minimumPriority != Integer.MAX_VALUE) {
+        int minimumPriority = ruleset.getMinimumPriority(constraint);
+        if(minimumPriority != Integer.MAX_VALUE) {
             mb.loadLocal(storeParameter);
-            mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(constraint.minimumPriority), CHRPriorityFactContainer);
+            mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
             mb.loadLocal(mb.getParameter(1));
             mb.loadThis();
             mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
         }
+        else if(constraint.nextContainerFieldName != null) {
+            mb.loadLocal(storeParameter);
+            mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
+            LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
+            mb.storeLocal(containerVar);
+            
+            mb.loadLocal(containerVar);
+            Label finishLabel = mb.createLabel();
+            mb.ifNullBranch(finishLabel, true);
+            
+            mb.loadLocal(containerVar);
+            mb.loadLocal(mb.getParameter(1));
+            mb.loadThis();
+            mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
+            mb.setLocation(finishLabel);
+        }
         mb.returnVoid();
         mb.finish();
     }
index 7ee11f05ec2370e876fa484ae5221319a8ff9b6e..496a33b36a049e7491111a423d21fad1df6c5025 100644 (file)
@@ -6,20 +6,18 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.cojen.classfile.TypeDesc;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.Opcodes;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
-import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
 
-import gnu.trove.impl.PrimeFinder;
 import gnu.trove.map.hash.THashMap;
 import gnu.trove.procedure.TObjectObjectProcedure;
-import gnu.trove.set.hash.THashSet;
 
 public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationConstants {
     ClassBuilder storeClassBuilder;
@@ -73,9 +71,9 @@ public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationC
     }
     
     private void generateContructor() {
-        MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
+        MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
         mb.loadThis();
-        mb.loadConstant(rule.priority);
+        mb.loadConstant(rule.priority + ruleset.initialPriorityNumber);
         mb.invokeSuperConstructor(new TypeDesc[] {TypeDesc.INT});
         mb.loadThis();
         mb.loadLocal(mb.getParameter(0));
@@ -102,8 +100,7 @@ public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationC
         planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
             @Override
             public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
-                int nextPriority = constraint.nextPriority;
-                constraint.nextPriority = rule.priority;
+                int nextPriority = ruleset.getAndUpdateNextPriority(constraint, rule.priority);
                 
                 Label next = nextLabel.get();
                 if(next != null)
@@ -132,6 +129,21 @@ public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationC
                     mb.loadLocal(mb.getParameter(1));
                     mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
                 }
+                else if(constraint.nextContainerFieldName != null && !ruleset.constraintSourceMap.containsKey(constraint)) {
+                    mb.loadThis();
+                    mb.loadField(containerClassName, "parent", storeTypeDesc);
+                    mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
+                    LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
+                    mb.storeLocal(containerVar);
+                    
+                    mb.loadLocal(containerVar);
+                    mb.ifNullBranch(finishLabel, true);
+                    
+                    mb.loadLocal(containerVar);
+                    mb.loadLocal(mb.getParameter(0));
+                    mb.loadLocal(mb.getParameter(1));
+                    mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
+                }
                 
                 mb.branch(finishLabel);
                 return true;
@@ -148,8 +160,6 @@ public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationC
         mb.finish();
     }
     
-    private THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();
-
     // protected abstract void activate(CHRContext context, CHRFact fact);
 
     private void generateActivate(CHRConstraint constraint, CHRSearchPlan plan, int id) {
@@ -159,31 +169,11 @@ public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationC
         mb.loadField(containerClassName, "parent", storeTypeDesc);
         LocalVariable parent = mb.createLocalVariable("parent", storeTypeDesc);
         mb.storeLocal(parent);
-        BoundVar[] implementationParameters = plan.implementation.getParameters();
-        mb.setLocalVariable(ruleset.this_, parent);
-        mb.setLocalVariable(implementationParameters[0], mb.getParameter(0));
-        mb.setLocalVariable(implementationParameters[1], mb.getParameter(1));
-
-        // Set closure parameters
-        usedParameters.clear();
-        plan.implementation.forValRefs(valRef -> {
-            if(valRef.getBinding() instanceof BoundVar)
-                usedParameters.add((BoundVar)valRef.getBinding());
-        });
-        for(int j=0;j<ruleset.parameters.length;++j) {
-            BoundVar parameter = ruleset.parameters[j];
-            if(!usedParameters.contains(parameter))
-                continue;
+        ruleset.rulesetObject.realizeMethod(mb, (i, target) -> {
             mb.loadLocal(parent);
-            mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(j), ruleset.parameterTypeDescs[j]);
-            mb.store(parameter);
-        }
-
-        // Generate code
-        //System.out.println("=== activate" + i + " ==========================================================");
-        //System.out.println(plan.implementation);
-        plan.implementation.markGenerateOnFly();
-        plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);
+            mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(i), ruleset.rulesetObject.parameterTypeDescs[i]);
+            mb.store(target);
+        }, plan.implementation, parent, mb.getParameter(0), mb.getParameter(1));
         mb.finish();
     }
 }
index 003086704522773d11ebaa0e43bf4b659e00c28d..9ff56eda4cc45eb27dcf29b00c0f9789816215c8 100644 (file)
@@ -7,30 +7,33 @@ import org.objectweb.asm.Opcodes;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
+import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
 
 public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants {
 
     public static void generateRuntimeRuleset(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {
-        ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetName, CHRRuntimeRuleset_name);
-        if(ruleset.parameters == null)
-            ruleset.parameters = new BoundVar[0];
-        ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters); 
+        ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetClassName, CHRRuntimeRuleset_name);
+        if(ruleset.rulesetObject.parameters == null)
+            ruleset.rulesetObject.parameters = new BoundVar[0];
+        TypeDesc[] parameterTypeDescs = ruleset.rulesetObject.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.rulesetObject.parameters); 
 
         ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<StoreInitialization>();
         for(CHRConstraint constraint : ruleset.constraints)
-            generateFact(storeClassBuilder, constraint, hashIndexInitializations);
+            generateFact(storeClassBuilder, ruleset, constraint, hashIndexInitializations);
         
         for(int i=ruleset.rules.size()-1;i>=0;--i)
             generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i));
 
         // Fields
-        for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
-            TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
+        for(int i=0;i<parameterTypeDescs.length;++i) {
+            TypeDesc typeDesc = parameterTypeDescs[i];
             if(typeDesc.equals(TypeDesc.VOID))
                 continue;
             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.parameterName(i), typeDesc);
@@ -39,27 +42,35 @@ public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstant
             storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
         for(CHRRule rule : ruleset.rules)
             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
-
+        if(ruleset.extensible)
+            for(CHRConstraint constraint : ruleset.constraints)
+                if(constraint.nextContainerFieldName != null)
+                    storeClassBuilder.addField(Opcodes.ACC_PUBLIC, constraint.nextContainerFieldName, CHRPriorityFactContainer);
+        if(ruleset.extensible)
+            storeClassBuilder.addField(Opcodes.ACC_PUBLIC, "currentId", FACT_ID_TYPE);
+        
         // Constructors
 
         {
-            MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);
+            MethodBuilder mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, parameterTypeDescs);
+                    //TypeDesc.concat(ruleset.parameterTypeDescs, includeTypeDescs));
             mb.loadThis();
             mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
-            for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
-                TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
+            int p=0;
+            for(int i=0;i<parameterTypeDescs.length;++i) {
+                TypeDesc typeDesc = parameterTypeDescs[i];
                 if(typeDesc.equals(TypeDesc.VOID))
                     continue;
                 mb.loadThis();
-                mb.loadLocal(mb.getParameter(i));
-                mb.storeField(ruleset.runtimeRulesetName, CHRCodeGenerationConstants.parameterName(i), ruleset.parameterTypeDescs[i]);
+                mb.loadLocal(mb.getParameter(p++));
+                mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
             }
             for(StoreInitialization ini : hashIndexInitializations) {
                 mb.loadThis();
                 mb.newObject(ini.className);
                 mb.dup();
                 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
-                mb.storeField(ruleset.runtimeRulesetName, ini.fieldName, ini.fieldType);
+                mb.storeField(ruleset.runtimeRulesetClassName, ini.fieldName, ini.fieldType);
             }
             TypeDesc[] runtimeRulesetTypeDescArray = new TypeDesc[] {TypeDesc.forClass(storeClassBuilder.getClassName())};
             for(CHRRule rule : ruleset.rules) {
@@ -68,17 +79,100 @@ public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstant
                 mb.dup();
                 mb.loadThis();
                 mb.invokeConstructor(rule.containerClassName, runtimeRulesetTypeDescArray);
-                mb.storeField(ruleset.runtimeRulesetName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
+                mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
             }
             mb.returnVoid();
             mb.finish();
         }
+        
+        // Registration
+        
+        for(IncludeStatement include : ruleset.includes) {
+            {
+                MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "register", TypeDesc.VOID,
+                        new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
+                LocalVariable contextVar = mb.getParameter(0);
+                LocalVariable importedStore = mb.getParameter(1);
+                ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
+                if(list != null)
+                    for(CHRConstraint constraint : list) {
+                        int minimumPriority = ruleset.getMinimumPriority(constraint);
+                        if(minimumPriority == Integer.MAX_VALUE)
+                            continue;
+                        mb.loadLocal(importedStore);
+                        mb.loadThis();
+                        mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
+                        mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
+                    }
+                
+                // update context id
+                mb.loadLocal(contextVar);
+                mb.loadLocal(contextVar);
+                mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
+                mb.loadLocal(importedStore);
+                mb.loadField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
+                mb.invokeStatic("java/lang/Math", "max", FACT_ID_TYPE, new TypeDesc[] {FACT_ID_TYPE, FACT_ID_TYPE});
+                mb.storeField(CHRContext_name, "currentId", FACT_ID_TYPE);
+                
+                mb.returnVoid();
+                mb.finish();
+            }
+            
+            {
+                MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "unregister", TypeDesc.VOID,
+                        new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
+                LocalVariable contextVar = mb.getParameter(0);
+                LocalVariable importedStore = mb.getParameter(1);
+                ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
+                if(list != null)
+                    for(CHRConstraint constraint : list) {
+                        int minimumPriority = ruleset.getMinimumPriority(constraint);
+                        if(minimumPriority == Integer.MAX_VALUE)
+                            continue;
+                        mb.loadLocal(importedStore);
+                        mb.loadNull();
+                        mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
+                    }
+                
+                // store context id
+                mb.loadLocal(importedStore);
+                mb.loadLocal(contextVar);
+                mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
+                mb.storeField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
+                
+                mb.returnVoid();
+                mb.finish();
+            }
+        }
+        
+        if(ruleset.initializer != null) {
+            MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "initialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
+            ruleset.rulesetObject.realizeMethod(mb,
+                    (i, target) -> {
+                        mb.loadThis();
+                        mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
+                        mb.store(target);
+                    },
+                    ruleset.initializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
+            mb.finish();
+        }
+        if(ruleset.deinitializer != null) {
+            MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "deinitialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
+            ruleset.rulesetObject.realizeMethod(mb,
+                    (i, target) -> {
+                        mb.loadThis();
+                        mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
+                        mb.store(target);
+                    },
+                    ruleset.deinitializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
+            mb.finish();
+        }
 
         moduleBuilder.addClass(storeClassBuilder);
     }
 
-    private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
-        CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, constraint);
+    private static void generateFact(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
+        CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, ruleset, constraint);
         generator.generate(hashIndexInitializations);
     }
 
index aaab03e1aae8c3e49686ec7d1960c4dc9dbf1b44..ba9d62d27ce730bffc2b99772321406736125e07 100644 (file)
@@ -530,7 +530,7 @@ public final class SSABlock extends Cont implements Printable, BoundVarBinder {
 
     public void markGenerateOnFly() {
         for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)
-            stat.markGenerateOnFly();        
+            stat.markGenerateOnFly();
     }
     
     public SSABlock copy(CopyContext context) {
index 17c695e518fdcd8b7b94566a6976d0e02645df50..57748b284b436c727109433613296de9e6910148 100644 (file)
@@ -19,7 +19,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
 import org.simantics.scl.compiler.types.TVar;
 import org.simantics.scl.compiler.types.Type;
 
-public abstract class SSAClosure implements Printable, BoundVarBinder{    
+public abstract class SSAClosure implements Printable, BoundVarBinder {
     Val target;
     
     ClosureBinder parent;
index b8b7def598175705f4beb2cb1f3b768688afe873..6d139a4d6fda4f1927ac84b9a99f550456503d49 100644 (file)
@@ -77,7 +77,7 @@ public class LetApply extends LetStatement implements ValRefBinder {
 
     @Override
     public void toString(PrintingContext context) {
-        if(determineGenerateOnFly())
+        if(/*target.getLabel() == null &&*/ determineGenerateOnFly())
             context.addInlineExpression(target, this);
         else
             toStringAux(context);
index cf46899f645b48b2b516c5a895c56b25cb566390..9f6fe9f01d8511bf86e6f49f740a9795e6f16531 100644 (file)
@@ -164,6 +164,7 @@ public class LetFunctions extends SSAStatement implements ClosureBinder {
                 BoundVar newVar = varMap.get(var);
                 if(newVar == null) {
                     newVar = new BoundVar(var.getType());
+                    newVar.setLabel(var.getLabel());
                     oldVarsList.add(var);
                     newVarsList.add(newVar);
                     varMap.put(var, newVar);
@@ -211,7 +212,7 @@ public class LetFunctions extends SSAStatement implements ClosureBinder {
             inVarsMap.put(closure, inVars);
             varMap.put(closure, map);
             
-            closure.parametrize(inVars);            
+            closure.parametrize(inVars);
             SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());
             context.addConstant(functionConstant);   
             oldTargets.put(closure, (BoundVar)closure.getTarget());
index bbcd370bbc19cef0401a155e44b9270b35ae9f88..6af3bd3101487d9efcfceb9573ad81d242c0f479 100644 (file)
@@ -9,7 +9,7 @@ import org.simantics.scl.compiler.types.kinds.Kind;
 
 public class StandardTypeConstructor extends TypeConstructor {
     private TypeDesc typeDesc; // null, if trivial data type (one constructor with one parameter)
-    public boolean external;
+    public boolean external; // this means that the class don't need to be generated
     
     public StandardTypeConstructor(TCon con, Kind kind) {
         super(con, kind);
index 0fe185e611df41ae90efad7e394b77119b0328f4..5316b861dc52e3e7a2e9b6424e0debf29ce96a13 100644 (file)
@@ -28,7 +28,8 @@ public class ClassBuilder {
         this.className = className;
         this.superClassName = superClassName;
         this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-        this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE 
+        this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE
+                  && SCLCompilerConfiguration.debugFilter(moduleBuilder.namingPolicy.getModuleName())
                 ? new TraceClassVisitor(classWriter, new PrintWriter(System.out))
                 : classWriter; 
         classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
@@ -96,9 +97,13 @@ public class ClassBuilder {
         methodVisitor.visitEnd();
     }
 
-    public MethodBuilderBase addConstructor(int access, TypeDesc[] params) {
+    public MethodBuilderBase addConstructorBase(int access, TypeDesc[] params) {
         return addMethodBase(access, "<init>", TypeDesc.VOID, params);
     }
+    
+    public MethodBuilder addConstructor(int access, TypeDesc[] params) {
+        return addMethod(access, "<init>", TypeDesc.VOID, params);
+    }
 
     public MethodBuilder addInitializer() {
         return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
index 81f7b117a82f61f7ade860cd1362d5b4a85559e3..71ce63e5c360d11eb7d5f76b2dd13d85e1838327 100644 (file)
@@ -27,7 +27,7 @@ public class CodeBuilderUtils {
                 classBuilder.addField(fieldModifiers, fieldNamePrefix+i, types[i]);
         
         // Create constructor        
-        MethodBuilderBase mb = classBuilder.addConstructor(
+        MethodBuilderBase mb = classBuilder.addConstructorBase(
                 types.length == 0 ? Opcodes.ACC_PRIVATE : Opcodes.ACC_PUBLIC, 
                 JavaTypeTranslator.filterVoid(types));
         mb.loadThis();
index 843659d6c12abe1f86fad86c0fda9b16e11e89f3..bd1a911a15f4ec4fe2342284baec23414da7a1a2 100644 (file)
@@ -25,6 +25,10 @@ public class MethodBuilderBase {
         }
         methodVisitor.visitCode();
     }
+    
+    public LocalVariable getThis(TypeDesc type) {
+        return new LocalVariable(0, type);
+    }
 
     public void loadConstant(boolean value) {
         if(value)
index 8db288a8976196486ec14ee0601ddbf4a14575b8..32d4283392bc093b9b083735488284bb73b71e95 100644 (file)
@@ -124,7 +124,7 @@ public class ModuleBuilder {
             
             // Create constructor
             {
-                MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
+                MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
                 mb.loadThis();
                 mb.loadConstant(remainingArity);
                 mb.invokeConstructor(MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL), new TypeDesc[] { TypeDesc.INT });
index 33a88ffba83dee70893e841c6cb516407ebca6fb..80acf17c571cb242e2db401233525006f118908d 100644 (file)
@@ -6,17 +6,18 @@ import org.simantics.scl.compiler.elaboration.expressions.EVar;
 import org.simantics.scl.compiler.elaboration.expressions.annotations.AnnotationUtils;
 import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
 import org.simantics.scl.compiler.errors.ErrorLog;
-import org.simantics.scl.compiler.internal.parsing.declarations.DModuleHeader;
 
 public class ModuleHeader {
     public String classLoader;
     public long classLoaderLocation;
     public String defaultLocalName;
-    public boolean fields;
     public List<EVar> export;
+    // Features
+    public boolean chr;
+    public boolean fields;
     
-    private void read(ErrorLog errorLog, DModuleHeader header) {
-        for(FieldAssignment assignment : header.fields)
+    private void read(ErrorLog errorLog, FieldAssignment[] fields) {
+        for(FieldAssignment assignment : fields)
             switch(assignment.name) {
             case "bundle":
                 if(assignment.value == null)
@@ -52,16 +53,21 @@ public class ModuleHeader {
                     errorLog.log(assignment.location, "No value expected for property fields.");
                 this.fields = true;
                 break;
+            case "chr":
+                if(assignment.value != null)
+                    errorLog.log(assignment.location, "No value expected for property chr.");
+                this.chr = true;
+                break;                
             default:
                 errorLog.logWarning(assignment.location, "Unknown module header field was skipped.");
             }
     }
     
-    public static ModuleHeader process(ErrorLog errorLog, DModuleHeader header) {
-        if(header == null)
+    public static ModuleHeader process(ErrorLog errorLog, FieldAssignment[] fields) {
+        if(fields == null)
             return null;
         ModuleHeader result = new ModuleHeader();
-        result.read(errorLog, header);
+        result.read(errorLog, fields);
         return result;
     }
 }
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DModuleHeader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DModuleHeader.java
deleted file mode 100644 (file)
index 25d14e2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.simantics.scl.compiler.internal.parsing.declarations;
-
-import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
-import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
-
-
-
-public class DModuleHeader extends DeclarationAst {
-    public final FieldAssignment[] fields;
-    
-    public DModuleHeader(FieldAssignment[] fields) {
-        this.fields = fields;
-    }
-
-    @Override
-    public void toString(int indentation, StringBuilder b) {
-        for(int i=0;i<indentation;++i) b.append("    ");
-        b.append("module {");
-        ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
-        boolean first = true;
-        for(FieldAssignment field : fields) {
-            if(first)
-                first = false;
-            else
-                b.append(',');
-            b.append('\n');
-            for(int i=0;i<=indentation;++i) b.append("    ");
-            b.append(field.name);
-            b.append(" = ");
-            field.value.accept(visitor);
-        }
-        b.append('\n');
-        for(int i=0;i<indentation;++i) b.append("    ");
-        b.append('}');
-    }
-}
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DRulesetAst.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/declarations/DRulesetAst.java
new file mode 100644 (file)
index 0000000..f23d272
--- /dev/null
@@ -0,0 +1,18 @@
+package org.simantics.scl.compiler.internal.parsing.declarations;
+
+import org.simantics.scl.compiler.elaboration.expressions.EBlock;
+import org.simantics.scl.compiler.types.TCon;
+
+public class DRulesetAst extends DeclarationAst {
+    public final String name;
+    public final EBlock block;
+    public DDocumentationAst documentation;
+    
+    public TCon type;
+    public String className;
+    
+    public DRulesetAst(String name, EBlock block) {
+        this.name = name;
+        this.block = block;
+    }
+}
index e673b294b94b5e8170e6960778a0176b1c37dcb9..0f45c2511b297a3e6575c7a953c6cd5e9f752c34 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.scl.compiler.internal.parsing.parser;
 
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.internal.parsing.Token;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
@@ -27,6 +28,7 @@ import gnu.trove.list.array.TIntArrayList;
     TIntArrayList stateStack = new TIntArrayList(2);
 
     StringBuffer string = new StringBuffer();
+    CompilationContext context;
     
     private Token sym(int id) {
         return new Token(id, yychar, yychar+yylength(), yytext());
@@ -34,6 +36,12 @@ import gnu.trove.list.array.TIntArrayList;
     private Token sym(int id, String text) {
         return new Token(id, yychar, yychar+yylength(), text);
     }
+    public void setCompilationContext(CompilationContext context) {
+        this.context = context;
+    }
+    public boolean supportCHR() {
+        return context.header == null ? false : context.header.chr;
+    }
 %}
 
 letter          = [a-zA-Z_]
@@ -84,12 +92,12 @@ char_literal    = "'" ([^'\\\ufffd] | "\\" [^\ufffd]) "'"
   else            { return sym(SCLTerminals.ELSE); }
   where           { return sym(SCLTerminals.WHERE); }
   when            { return sym(SCLTerminals.WHEN); }
-  ruleset         { return sym(SCLTerminals.RULESET); }
-  rule            { return sym(SCLTerminals.RULE); }
+  ruleset         { return sym(supportCHR() ? SCLTerminals.RULESET : SCLTerminals.ID); }
+  rule            { return sym(supportCHR() ? SCLTerminals.ID : SCLTerminals.RULE); }
   abstract{whitespace}rule { return sym(SCLTerminals.ABSTRACT_RULE); }
   extends         { return sym(SCLTerminals.EXTENDS); }
   mapping{whitespace}relation { return sym(SCLTerminals.MAPPING_RELATION); }
-  transformation  { return sym(SCLTerminals.TRANSFORMATION); }
+  transformation  { return sym(supportCHR() ? SCLTerminals.ID : SCLTerminals.TRANSFORMATION); }
   select{whitespace}first { return sym(SCLTerminals.SELECT_FIRST); }
   select{whitespace}distinct { return sym(SCLTerminals.SELECT_DISTINCT); }
   select          { return sym(SCLTerminals.SELECT); }
index 5aad5eefe96819eaad19fdf4b9c487743f6029bc..5944d12e1cf288e701348305082a2d101eb07591 100644 (file)
@@ -2,6 +2,7 @@
 
 package org.simantics.scl.compiler.internal.parsing.parser;
 
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.internal.parsing.Token;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
@@ -11,7 +12,7 @@ import gnu.trove.list.array.TIntArrayList;
 /**
  * This class is a scanner generated by 
  * <a href="http://www.jflex.de/">JFlex</a> 1.6.1
- * from the specification file <tt>C:/GamsGui/git/platform/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.flex</tt>
+ * from the specification file <tt>C:/Simugawa.git/git/platform/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.flex</tt>
  */
 public class SCLLexer {
 
@@ -589,6 +590,7 @@ public class SCLLexer {
     TIntArrayList stateStack = new TIntArrayList(2);
 
     StringBuffer string = new StringBuffer();
+    CompilationContext context;
     
     private Token sym(int id) {
         return new Token(id, yychar, yychar+yylength(), yytext());
@@ -596,6 +598,12 @@ public class SCLLexer {
     private Token sym(int id, String text) {
         return new Token(id, yychar, yychar+yylength(), text);
     }
+    public void setCompilationContext(CompilationContext context) {
+        this.context = context;
+    }
+    public boolean supportCHR() {
+        return context.header == null ? false : context.header.chr;
+    }
 
 
   /**
@@ -1196,7 +1204,7 @@ public class SCLLexer {
             }
           case 157: break;
           case 63: 
-            { return sym(SCLTerminals.RULE);
+            { return sym(supportCHR() ? SCLTerminals.ID : SCLTerminals.RULE);
             }
           case 158: break;
           case 64: 
@@ -1276,7 +1284,7 @@ public class SCLLexer {
             }
           case 177: break;
           case 83: 
-            { return sym(SCLTerminals.RULESET);
+            { return sym(supportCHR() ? SCLTerminals.RULESET : SCLTerminals.ID);
             }
           case 178: break;
           case 84: 
@@ -1316,7 +1324,7 @@ public class SCLLexer {
             }
           case 187: break;
           case 93: 
-            { return sym(SCLTerminals.TRANSFORMATION);
+            { return sym(supportCHR() ? SCLTerminals.ID : SCLTerminals.TRANSFORMATION);
             }
           case 188: break;
           case 94: 
index 08e6a4f2de709096da22ab086c24473ff059ec86..09fc79e0f531030b8ff2d1dfa720a00c22428dfb 100644 (file)
@@ -8,6 +8,7 @@ import java.util.List;
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.common.precedence.Associativity;
 import org.simantics.scl.compiler.common.precedence.Precedence;
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.constants.CharacterConstant;
 import org.simantics.scl.compiler.constants.StringConstant;
 import org.simantics.scl.compiler.elaboration.equation.EqBasic;
@@ -53,6 +54,7 @@ import org.simantics.scl.compiler.elaboration.expressions.block.BindStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
+import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement;
 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
@@ -73,6 +75,7 @@ import org.simantics.scl.compiler.elaboration.query.pre.QPreBinds;
 import org.simantics.scl.compiler.elaboration.query.pre.QPreEquals;
 import org.simantics.scl.compiler.elaboration.query.pre.QPreGuard;
 import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.header.ModuleHeader;
 import org.simantics.scl.compiler.internal.parsing.Symbol;
 import org.simantics.scl.compiler.internal.parsing.Token;
 import org.simantics.scl.compiler.internal.parsing.declarations.ConstructorAst;
@@ -86,9 +89,9 @@ import org.simantics.scl.compiler.internal.parsing.declarations.DFixityAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DImportJavaAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
-import org.simantics.scl.compiler.internal.parsing.declarations.DModuleHeader;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRulesetAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
@@ -113,9 +116,15 @@ public class SCLParserImpl extends SCLParser {
 
     private final SCLPostLexer lexer;
     private SCLParserOptions options;
+    private CompilationContext context;
 
     public SCLParserImpl(Reader reader) {
-        lexer = new SCLPostLexer(reader);
+        this.lexer = new SCLPostLexer(reader);
+    }
+    
+    public void setCompilationContext(CompilationContext context) {
+        this.context = context;
+        lexer.setCompilationContext(context);
     }
     
     public void setParserOptions(SCLParserOptions options) {
@@ -158,7 +167,7 @@ public class SCLParserImpl extends SCLParser {
         for(int i=0;i<length();i+=2) {
             DeclarationAst declaration = (DeclarationAst)get(i);
             if(declaration == null)
-                throw new NullPointerException();
+                continue;
             declarations.add(declaration);
         }
         return declarations;
@@ -169,7 +178,8 @@ public class SCLParserImpl extends SCLParser {
         FieldAssignment[] fields = new FieldAssignment[length()/2-1];
         for(int i=0;i<fields.length;++i)
             fields[i] = (FieldAssignment)get(2+i*2);
-        return new DModuleHeader(fields);
+        context.header = ModuleHeader.process(context.errorLog, fields);
+        return null;
     }
 
     @Override
@@ -1285,14 +1295,16 @@ public class SCLParserImpl extends SCLParser {
 
     @Override
     protected Object reduceRulesetDefinition() {
-        // TODO Auto-generated method stub
-        return null;
+        Token name = (Token)get(1);
+        EBlock block = (EBlock)get(3);
+        return new DRulesetAst(name.text, block);
     }
 
     @Override
     protected Object reduceLocalInclude() {
-        // TODO Auto-generated method stub
-        return null;
+        Token name = (Token)get(1);
+        Expression value = (Expression)get(2);
+        return new IncludeStatement(name, value);
     }
 
 }
index 9cc1ff27b16a288afb11f138b9d8755a84f642d0..a2253d8b7bc001cc7d0889a5ab69a0a5885e7922 100644 (file)
@@ -3,6 +3,7 @@ package org.simantics.scl.compiler.internal.parsing.parser;
 import java.io.IOException;
 import java.util.Arrays;
 
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.Token;
 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
@@ -16,6 +17,9 @@ import gnu.trove.set.hash.TIntHashSet;
  * @author Hannu Niemistö
  */
 public class SCLPostLexer {
+    
+    private static final int PATCH_SIZE = 16;
+    private static final int INITIAL_QUEUE_SIZE = 32;
         
     public static TIntHashSet INDENTABLE = new TIntHashSet();
     public static TIntHashSet NO_SEMICOLON_BEFORE = new TIntHashSet();
@@ -49,7 +53,7 @@ public class SCLPostLexer {
     }
     
     SCLLexer lexer;
-    Token[] queue = new Token[16];
+    Token[] queue = new Token[INITIAL_QUEUE_SIZE];
     int queuePos=0, queueSize=0;
     TIntArrayList indentations = new TIntArrayList();
     TIntArrayList indentationTokens = new TIntArrayList();
@@ -58,6 +62,12 @@ public class SCLPostLexer {
     boolean firstTokenOfLine = true;
     private SCLParserOptions options;
     private boolean isFirstToken = true;
+    private CompilationContext context;
+    
+    /**
+     * We are parsing a module header and therefore should process tokens one by one and not by patches.
+     */
+    private boolean isInsideModule = false; 
             
     {
         indentations.add(0);
@@ -71,6 +81,11 @@ public class SCLPostLexer {
     public SCLPostLexer(java.io.Reader in) {
         this(new SCLLexer(in));
     }
+    
+    public void setCompilationContext(CompilationContext context) {
+        lexer.setCompilationContext(context);
+        this.context = context;
+    }
 
     public Token nextToken() throws Exception {
         while(queuePos == queueSize)
@@ -98,8 +113,15 @@ public class SCLPostLexer {
         queuePos = 0;
         queueSize = 0;
         
-        for(int i=0;i<8;++i)
+        for(int i=0;i<PATCH_SIZE;++i) {
             handleToken(lexer.nextToken());
+            if(isInsideModule) {
+                if(context.header == null)
+                    break;
+                else
+                    isInsideModule = false;
+            }
+        }
     }
     
     private SCLSyntaxErrorException error(int start, int end, String description) {
@@ -156,6 +178,7 @@ public class SCLPostLexer {
                 isFirstToken = false;
                 if(symbol.id == SCLTerminals.ID && symbol.text.equals("module") && options != null && options.isModule) {
                     push(new Token(SCLTerminals.MODULE, symbol.location, symbol.text));
+                    isInsideModule = true;
                     return;
                 }
             }
index c6210ce49dcf99498b68e09946fb02593c06c308..73311e99ab9ab4a17f087d1f215b15de89286929 100644 (file)
@@ -9,6 +9,7 @@ import java.util.function.Consumer;
 
 import org.simantics.scl.compiler.common.names.Name;
 import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.Documentation;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
@@ -38,10 +39,11 @@ public class ConcreteModule implements Module {
     THashMap<TCon, ArrayList<TypeClassInstance>> typeClassInstances = new THashMap<TCon, ArrayList<TypeClassInstance>>();
     THashMap<String, SCLValue> values = new THashMap<String, SCLValue>();
     THashMap<String, List<Constant>> fieldAccessors = new THashMap<String, List<Constant>>();
-    THashMap<String, SCLRelation> relations = new THashMap<String, SCLRelation>();
-    THashMap<String, SCLEntityType> entityTypes = new THashMap<String, SCLEntityType>();
-    THashMap<String, TransformationRule> rules = new THashMap<String, TransformationRule>();
-    THashMap<String, MappingRelation> mappingRelations = new THashMap<String, MappingRelation>();
+    THashMap<String, SCLRelation> relations = new THashMap<String, SCLRelation>(2);
+    THashMap<String, SCLEntityType> entityTypes = new THashMap<String, SCLEntityType>(2);
+    THashMap<String, TransformationRule> rules = new THashMap<String, TransformationRule>(2);
+    THashMap<String, MappingRelation> mappingRelations = new THashMap<String, MappingRelation>(2);
+    THashMap<String, CHRRuleset> rulesets = new THashMap<String, CHRRuleset>(2);
     ArrayList<ImportDeclaration> dependencies = new ArrayList<ImportDeclaration>();
     THashMap<String, BranchPoint[]> branchPoints;
     CompilationError[] warnings = CompilationError.EMPTY_ARRAY;
@@ -191,6 +193,11 @@ public class ConcreteModule implements Module {
         return effectConstructors.get(name);
     }
 
+    @Override
+    public CHRRuleset getRuleset(String name) {
+        return rulesets.get(name);
+    }
+    
     public Collection<TypeClass> getTypeClasses() {
         return typeClasses.values();
     }
@@ -315,4 +322,8 @@ public class ConcreteModule implements Module {
         }
         list.add(accessor);
     }
+
+    public void addRuleset(String name, CHRRuleset ruleset) {
+        rulesets.put(name, ruleset);
+    }
 }
index a53a90b916e8bb8ca7bb6e210f91e13077e54a9d..61d2c29288992f63ddb6ab2209a9336f86e918d8 100644 (file)
@@ -5,6 +5,7 @@ import java.util.Collections;
 import java.util.List;
 
 import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.Documentation;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
@@ -146,4 +147,9 @@ public abstract class LazyModule implements Module {
     public CompilationError[] getWarnings() {
         return CompilationError.EMPTY_ARRAY;
     }
+    
+    @Override
+    public CHRRuleset getRuleset(String name) {
+        return null;
+    }
 }
index 51d39e103c96b53a7e44a13dd175ea0bf2ae349e..ee90b5e1a3f7f263406debf52453ea531f394d25 100644 (file)
@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.function.Consumer;
 
 import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.modules.Documentation;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
@@ -40,6 +41,7 @@ public interface Module {
     Collection<TypeClassInstance> getInstances(TCon typeClass);
     MappingRelation getMappingRelation(String name);
     TransformationRule getRule(String name);
+    CHRRuleset getRuleset(String name);
     Collection<TransformationRule> getRules();
     
     void findValuesForPrefix(String prefix, NamespaceFilter filter, TObjectProcedure<SCLValue> proc);
index 4ed45005b9659aa8fc42f1c6790e1c8f851abf64..5ae73c41240700f44662e1b70f6851487752b290 100644 (file)
@@ -117,7 +117,7 @@ public class RuntimeModule {
                 if(bytes == null)
                     throw new ClassNotFoundException(name);
             }
-            if(SCLCompilerConfiguration.SHOW_DECOMPILED_BYTECODE)
+            if(SCLCompilerConfiguration.SHOW_DECOMPILED_BYTECODE && SCLCompilerConfiguration.debugFilter(moduleName))
                 showDecompiledBytecode(internalName);
             return defineClass(name, bytes, 0, bytes.length);
         }
index 2b42bc7bab865c75d8873ba8150504eb6aa47cc6..a5b9a65417e79e095acc83149f49d40ffa47690d 100644 (file)
@@ -236,7 +236,7 @@ public class ExpressionEvaluator {
         ArrayList<Type> lvTypes = new ArrayList<Type>(); 
         if(expression instanceof EBlock) {
             EBlock block = (EBlock)expression;
-            if(localStorage != null && !(block.getStatements().getLast() instanceof GuardStatement)) {
+            if(localStorage != null && !(block.getLast() instanceof GuardStatement)) {
                 THashSet<String> localVariables = new THashSet<String>();
                 ListIterator<Statement> it = block.getStatements().listIterator();
                 while(it.hasNext()) {
@@ -264,7 +264,7 @@ public class ExpressionEvaluator {
                         localStorage.store(variableName, null, type);
                 }
             }
-            if(!(block.getStatements().getLast() instanceof GuardStatement))
+            if(!(block.getLast() instanceof GuardStatement))
                 block.addStatement(new GuardStatement(new EConstant(Builtins.TUPLE_CONSTRUCTORS[0])));
         }
         
index 57f7102cb7dbec38a03c0268a2d3333203ac3690..1331530dda6dfe5249fda811387f850d8022e6c4 100644 (file)
@@ -33,5 +33,9 @@ public interface SCLCompilerConfiguration {
     public static final boolean EVERY_DATALOG_STRATUM_IN_SEPARATE_METHOD = true;
     
     public static final boolean ALLOW_OVERLOADING = true;
+
+    public static boolean debugFilter(String name) {
+        return true;
+    }
     
 }
diff --git a/bundles/org.simantics.scl.runtime/scl/TestCHR.scl b/bundles/org.simantics.scl.runtime/scl/TestCHR.scl
deleted file mode 100644 (file)
index 7958317..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-import "StandardLibrary"
-
-topologicalSort :: Show a => [(a,a)] -> <Proc> [a]
-topologicalSort dependencies = MList.freeze answer
-  where
-    answer = MList.create ()
-    
-    (?x,?y) <- dependencies           =>  print "RULE 1, x=\(?x), y=\(?y)", Dep ?x ?y, InDegree ?x 0, InDegree ?y 1
-    InDegree ?x ?a                    =>  print "pre InDegree \(?x) \(?a)"    
-    -InDegree ?x ?a, -InDegree ?x ?b  =>  print "RULE 2, x=\(?x), a=\(?a), b=\(?b)", InDegree ?x (?a + ?b)
-    InDegree ?x ?a                    =>  print "InDegree \(?x) \(?a)"
-    InDegree ?x 0                     =>  print "RULE 3, x=\(?x)", AdjustInDegrees ?x, MList.add answer ?x
-    AdjustInDegrees ?x, Dep ?x ?y     =>  print "RULE 4, x=\(?x), y=\(?y)", InDegree ?y (-1)
-    
-main = topologicalSort [(2,4),(3,7),(7,2),(1,3)]
index 63b2338f4754ff825ab57c35d16957cc9360c21b..33b5fc7e998fa150536ffebca29295bd08cf9f3c 100644 (file)
@@ -3,6 +3,8 @@ package org.simantics.scl.ui.info;
 public class SCLInfo {
 
     public static String[] RESERVED_WORDS = new String[] {
+        "module",
+            
         "data",
         "type",
         "effect",
@@ -33,6 +35,7 @@ public class SCLInfo {
         "as",
         "forall",
         "rule",
+        "ruleset",
         "extends",
         "by",
         "select",
index de215c0920cb48d62db9615ab43e9636a3a119b0..fe18da61d1fdc215fe3c7a5f342cf96a47eaed96 100644 (file)
@@ -1,7 +1,5 @@
 package org.simantics.scl.compiler.tests;
 
-import org.junit.Test;
-
 public class ActiveTests extends TestBase {
     
     public ActiveTests() { super("scl"); }
@@ -20,6 +18,4 @@ public class ActiveTests extends TestBase {
     
     //@Test public void Bug6989() { test(); }
 
-    @Test public void CHR5() { test(); }
-    
 }
index f50056e8d230e37a8b309b908736607ae13667ee..1c0100425e72fa412154edf0addace0e204202c0 100644 (file)
@@ -26,6 +26,8 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void CHR2() { test(); }
     @Test public void CHR3() { test(); }
     @Test public void CHR4() { test(); }
+    @Test public void CHR5() { test(); }
+    @Test public void CHR6() { test(); }    
     @Test public void ClosureRecursion() { test(); }
     @Test public void Collaz() { test(); }
     @Test public void Compose() { test(); }
index e3c8b8c27d5292acec9abaadaa0fe45336ed8d2b..00ca32bec06f5b887afd13e5b3a7d1800a939ead 100644 (file)
@@ -1,16 +1,34 @@
+module {
+    export = [main],
+    chr
+}
+
 import "StandardLibrary"
 
-topologicalSort :: Show a => [(a,a)] -> <Proc> [a]
-topologicalSort dependencies = MList.freeze answer
-  where
-    answer = MList.create ()
+ruleset IntegerSet where
+    constraint Element Integer
+    // Set may not contain duplicates
+    Element ?x => print "added \(?x)"
+    -Element ?x, Element ?x => print "removed duplicate \(?x)"
     
-    (?x,?y) <- dependencies           =>  print "RULE 1, x=\(?x), y=\(?y)", Dep ?x ?y, InDegree ?x 0, InDegree ?y 1
-    -InDegree ?x ?a, -InDegree ?x ?b  =>  print "RULE 2, x=\(?x), a=\(?a), b=\(?b)", InDegree ?x (?a + ?b)
-    InDegree ?x ?a                    =>  print "InDegree \(?x) \(?a)"
-    InDegree ?x 0                     =>  print "RULE 3, x=\(?x)", AdjustInDegrees ?x, MList.add answer ?x
-    AdjustInDegrees ?x, Dep ?x ?y     =>  print "RULE 4, x=\(?x), y=\(?y)", InDegree ?y (-1)
+addSet :: IntegerSet -> Integer -> <Proc> ()
+addSet set newElement = ()
+  where
+    include IntegerSet set
+    True => Element newElement
     
-main = topologicalSort [(2,4),(3,7),(7,2),(1,3)]
+printSet :: IntegerSet -> <Proc> ()
+printSet set = ()
+  where
+    include IntegerSet set
+    Element ?x => print "printing \(?x)" 
+
+main = ()
+  where
+    set = createIntegerSet
+    addSet set 1
+    addSet set 2
+    addSet set 1
+    printSet set
 --
-[1, 3, 7, 2, 4]
\ No newline at end of file
+()
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl
new file mode 100644 (file)
index 0000000..c18a13a
--- /dev/null
@@ -0,0 +1,23 @@
+module {
+    export = [main],
+    chr
+}
+
+import "StandardLibrary"
+
+ruleset RS where
+    constraint X Integer
+    -X ?value, X ?value => True
+    X ?value => print "A \(?value)"
+    
+main :: ()
+main = ()
+  where
+    rs = createRS
+    include RS rs
+    X ?value => print "B \(?value)"
+    True     => X 1
+    True     => X 2
+    True     => X 1
+--
+()
index 5a04ed6f3724537db4f966d09d5a85428cff4e3e..2ec8ad5d6e128960f201e2b7fe65c8b86c19787d 100644 (file)
@@ -56,7 +56,7 @@ public class TestCHRCodeGenerator {
             MutableClassLoader classLoader = environment.getMutableClassLoader();
             classLoader.addClasses(moduleBuilder.getClasses());
             
-            String storeClassName = ruleset.runtimeRulesetName.replace('/', '.');
+            String storeClassName = ruleset.runtimeRulesetClassName.replace('/', '.');
             Class<?> storeClass = classLoader.loadClass(storeClassName);
             Class<?> factClass = classLoader.loadClass(storeClassName+"$ExampleFact");
             Constructor<?> factConstructor = factClass.getConstructor(int.class, int.class, int.class);