]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7250) Merging master, minor CHR bugfixes 90/590/1
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 13:39:28 +0000 (16:39 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Fri, 2 Jun 2017 14:34:55 +0000 (17:34 +0300)
Change-Id: I11c76beee0e73ff78370f72bbfb88fdbdf6c7616

1  2 
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.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/internal/codegen/ssa/SSAFunction.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java
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/ModuleRegressionTests.java

index a8dca8c1133950ae64e397c4aca34fb033cc9083,cc883c0eafc9ceefd03212975777a54377419beb..5d258dd9e2b819c9d2ea4576718c65522586c384
@@@ -17,6 -17,7 +17,7 @@@ import org.simantics.scl.compiler.const
  import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
  import org.simantics.scl.compiler.elaboration.expressions.Expression;
  import org.simantics.scl.compiler.elaboration.macros.StandardMacroRule;
+ import org.simantics.scl.compiler.elaboration.modules.DerivedProperty;
  import org.simantics.scl.compiler.elaboration.modules.InlineProperty;
  import org.simantics.scl.compiler.elaboration.modules.MethodImplementation;
  import org.simantics.scl.compiler.elaboration.modules.PrivateProperty;
@@@ -124,13 -125,18 +125,18 @@@ public class CodeGeneration 
                      decomposed.typeParameters, 
                      decomposed.returnType, 
                      decomposed.parameterTypes));*/
+             boolean isDerived = false;
              for(SCLValueProperty prop : value.getProperties()) {
                  if(prop instanceof InlineProperty) {
                      InlineProperty inlineProperty = (InlineProperty)prop;
                      constant.setInlineArity(inlineProperty.arity, inlineProperty.phaseMask);
                  }
                  else if(prop == PrivateProperty.INSTANCE)
-                     constant.setPrivate(true);
+                     constant.setPrivate(!isDerived);
+                 else if(prop == DerivedProperty.INSTANCE) {
+                     constant.setPrivate(false);
+                     isDerived = true;
+                 }
              }
          }
          // This is quite hackish optimization that can be possibly removed when
      }
      
      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);            
          }
              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);            
          }
      }
      
      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 6499ab4fe7d09fac0fd4f793fd4b3e7b2f6da80d,7887ed717f032b7d29aed50782a69e0f6b42c916..359448e1d65adf505e970e80e328ddb8d62cc079
@@@ -6,7 -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;
@@@ -32,7 -31,6 +32,7 @@@ import org.simantics.scl.compiler.elabo
  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;
@@@ -41,6 -39,7 +41,7 @@@ import org.simantics.scl.compiler.elabo
  import org.simantics.scl.compiler.elaboration.java.JavaMethodDeclaration;
  import org.simantics.scl.compiler.elaboration.macros.StandardMacroRule;
  import org.simantics.scl.compiler.elaboration.modules.DeprecatedProperty;
+ import org.simantics.scl.compiler.elaboration.modules.DerivedProperty;
  import org.simantics.scl.compiler.elaboration.modules.InlineProperty;
  import org.simantics.scl.compiler.elaboration.modules.MethodImplementation;
  import org.simantics.scl.compiler.elaboration.modules.PrivateProperty;
@@@ -49,7 -48,6 +50,7 @@@ import org.simantics.scl.compiler.elabo
  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;
@@@ -87,7 -85,6 +88,7 @@@ import org.simantics.scl.compiler.inter
  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;
@@@ -215,8 -212,7 +216,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;
  
              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;
          }
          
              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) {
                              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];
      
                      String fullName = instancePrefix + valueName;
                      long loc = valueDefs.getDefinition(valueName).get(0).location;
                      valueDefinitionsAst.addFrom(valueDefs, valueName, fullName);
+                     valueDefinitionsAst.setDerived(fullName);
                      /*valueDefinitionsAst.addAnnotation(fullName, new DAnnotationAst(new EVar("@private"), 
                              Collections.<Expression>emptyList()));*/
                      TypeClassMethod method = typeClass.methods.get(valueName);
          }
      }
      
 +    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.
              value.definitionLocation = location;
              if(module.addValue(value))
                  errorLog.log(location, "Value " + name + " is already defined.");
+             if(valueDefinitionsAst.isDerived(name))
+                 value.addProperty(DerivedProperty.INSTANCE);
          }
          for(DValueTypeAst valueTypeAst : typeAnnotationsAst)
              for(EVar name : valueTypeAst.names) {
index d5f61965454e80006631d98d76621fc56ba94e50,bb5491ad17111c79aa7fc30ee2742cd2ef782149..bb00f08850f8fa3cd6f21586a8b60a6e052ff640
@@@ -7,30 -7,23 +7,30 @@@ import org.simantics.scl.compiler.compi
  import org.simantics.scl.compiler.constants.BooleanConstant;
  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;
 -import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;
  import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
  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.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.CHRCodeGenerator;
 +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;
@@@ -38,9 -31,7 +38,9 @@@ import org.simantics.scl.compiler.types
  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;
@@@ -51,22 -42,15 +51,22 @@@ 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 storeClassName;
 -    public TCon storeType;
 -    public BoundVar storeVariable;
 -    public TypeDesc storeTypeDesc;
 -    public Constant activateProcedure;
 +    public int initialPriorityNumber = 0;
 +    
 +    public String runtimeRulesetClassName;
 +    public TCon runtimeRulesetType;
 +    public BoundVar runtimeRulesetVariable;
 +    public TypeDesc runtimeRulesetTypeDesc;
      public Constant readCurrentId;
      public Constant writeCurrentId;
      
@@@ -74,9 -58,9 +74,9 @@@
      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);
      }
      
      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;
      }
  
      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);
      }
                  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.plans.isEmpty()) {
 +        if(getMinimumPriority(initConstraint) == Integer.MAX_VALUE) {
              constraints.remove(0);
              initConstraint = null;
          }
 +    }
 +
 +    private void applyExtensibleDefaults() {
          for(CHRConstraint constraint : constraints) {
 -            constraint.plans.sort((PrioritizedPlan a, PrioritizedPlan b) -> {
 -                return Integer.compare(a.priority, b.priority);
 -            });
 -            /*System.out.println(constraint.name);
 -            for(PrioritizedPlan plan : constraint.plans) {
 -                System.out.println("  priority " + plan.priority);
 -                for(PlanOp op : plan.ops)
 -                    System.out.println("    " + op);
 -            }*/
 +            // FIXME Too much indexing!!!
 +            int max = 1 << constraint.parameterTypes.length;
 +            for(int i=0;i<max;++i)
 +                constraint.getOrCreateIndex(cachedContext, i);
++            constraint.setMayBeRemoved();
 +            /*
 +            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();
 -        storeType = Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix);
 -        storeClassName = context.namingPolicy.getModuleClassName() + suffix;
 -        storeTypeDesc = TypeDesc.forClass(storeClassName);
 -        storeVariable = new BoundVar(storeType); 
 +        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);
 -        activateProcedure = new JavaMethod(true, storeClassName, "activate", Types.PROC, Types.UNIT, storeType, Types.INTEGER);
 -        readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {storeType},
 -                null, new FieldRef(storeClassName, "currentId", CHRCodeGenerator.FACT_ID_TYPE), null);
 -        writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {storeType, Types.INTEGER},
 -                null, new SetFieldRef(storeClassName, "currentId", CHRCodeGenerator.FACT_ID_TYPE), null);
 -        if(context.module != null) // for unit testing
 -            context.module.addTypeDescriptor(storeType.name, new StandardTypeConstructor(storeType, TVar.EMPTY_ARRAY, storeTypeDesc));
 +        readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
 +                null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
 +        writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER},
 +                null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
 +        if(createTypeDesc && context.module != null) // for unit testing
 +            context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc));
      }
 +
 +    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) {
 -        CHRRulesetObject object = new CHRRulesetObject(storeVariable, this);
 +    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(CHRConstraint constraint : constraints) {
 -            //System.out.println(constraint);
 -            for(PrioritizedPlan plan : constraint.plans) {
 +        for(CHRRule rule : rules) {
 +            for(CHRSearchPlan plan : rule.plans) {
                  /*System.out.println("    plan " + plan.priority);
                  for(PlanOp planOp : plan.ops)
                      System.out.println("        " + planOp);*/
 -                PlanRealizer realizer = new PlanRealizer(cachedContext, this, storeVariable, plan.ops);
 -                CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {constraint.factType});
 +                CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {Types.CHRContext, plan.constraint.factType});
                  plan.implementation = methodWriter.getFunction();
 -                plan.activeFact.setVal(methodWriter.getParameters()[0]);
 +                IVal[] implementationParameters = methodWriter.getParameters();
 +                plan.activeFact.setVal(implementationParameters[1]);
 +                PlanRealizer realizer = new PlanRealizer(cachedContext, this, runtimeRulesetVariable, implementationParameters[0], plan.ops);
                  realizer.nextOp(methodWriter);
                  if(methodWriter.isUnfinished())
                      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, storeVariable, initFact);
 -            w.apply(location, activateProcedure, storeVariable, new IntegerConstant(Integer.MAX_VALUE));
 +            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 ab643f9a15b1669be060ae165c07a403cb3888c3,ab643f9a15b1669be060ae165c07a403cb3888c3..b9e8bfbb398e0803977e305533259eb0eb6d4982
@@@ -359,6 -359,6 +359,8 @@@ public final class SSAFunction extends 
      }
  
      public void mergeBlocks(SSAFunction function) {
++        if(this == function)
++            throw new InternalCompilerError();
          SSABlock block = function.firstBlock;
          while(block != null) {
              SSABlock next = block.next;
index 6d139a4d6fda4f1927ac84b9a99f550456503d49,b8b7def598175705f4beb2cb1f3b768688afe873..400cb6e4e373f78c480e8fc37c1da3dc203a47f2
@@@ -77,7 -77,7 +77,7 @@@ public class LetApply extends LetStatem
  
      @Override
      public void toString(PrintingContext context) {
 -        if(determineGenerateOnFly())
 +        if(/*target.getLabel() == null &&*/ determineGenerateOnFly())
              context.addInlineExpression(target, this);
          else
              toStringAux(context);
          tailBlock.setExit(headBlock.getExit());
          
          // Merge blocks        
--        thisFunction.mergeBlocks(function);           
++        thisFunction.mergeBlocks(function);
          
          headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(), 
                  parameters));
index 33b5fc7e998fa150536ffebca29295bd08cf9f3c,63b2338f4754ff825ab57c35d16957cc9360c21b..c37a9421f53bacb3f4c310381b160e7716d32727
@@@ -3,8 -3,6 +3,8 @@@ package org.simantics.scl.ui.info
  public class SCLInfo {
  
      public static String[] RESERVED_WORDS = new String[] {
 +        "module",
 +            
          "data",
          "type",
          "effect",
@@@ -35,7 -33,6 +35,8 @@@
          "as",
          "forall",
          "rule",
 +        "ruleset",
++        "constraint",
          "extends",
          "by",
          "select",
index 1c0100425e72fa412154edf0addace0e204202c0,5bd0c85d7b48c9ad8f03f925f9e401d0713c68d8..769a1bde952daaa9de2d5f25d4b1d6c1b6f866bf
@@@ -26,8 -26,6 +26,8 @@@ public class ModuleRegressionTests exte
      @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(); }
      @Test public void LocalDefinitions4() { test(); }
      @Test public void LocalDefinitions5() { test(); }
      @Test public void Logger() { test(); }
+     @Test public void LP() { test(); }
      @Test public void Macros1() { test(); }
      @Test public void Macros2() { test(); }
      @Test public void Macros4() { test(); }
      @Test public void SinConst1() { test(); }
      @Test public void Sort() { test(); }
      @Test public void Sort2() { test(); }
+     @Test public void SpecConstr1() { test(); }  
      @Test public void SSATypingBug() { test(); }
      @Test public void StreamFusion() { test(); }
      @Test public void StringEscape() { test(); }