From: Hannu Niemistö Date: Fri, 2 Jun 2017 13:39:28 +0000 (+0300) Subject: (refs #7250) Merging master, minor CHR bugfixes X-Git-Tag: v1.31.0~339^2~3 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=fad36d463b75c3a9944d875fc627c3533f6da74d;hp=d5c76b143c0000994bb76c40f0ea74354eb5ce8a (refs #7250) Merging master, minor CHR bugfixes Change-Id: I11c76beee0e73ff78370f72bbfb88fdbdf6c7616 --- diff --git a/bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java b/bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java index acf2bb18d..5843b89e3 100644 --- a/bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java +++ b/bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java @@ -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; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java index 1cf6d0de9..a8f3d2045 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java @@ -423,10 +423,9 @@ public class CommandSession { void finishBlock() { if(currentBlock != null) { checkInterrupted(); - LinkedList 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; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/exceptions/InternalCompilerError.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/exceptions/InternalCompilerError.java index ae3bdd87c..71b619301 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/exceptions/InternalCompilerError.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/exceptions/InternalCompilerError.java @@ -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; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/Names.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/Names.java index 1c4255b46..50729430d 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/Names.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/Names.java @@ -12,6 +12,7 @@ public class Names { public static final Name Builtin_equals = Name.create(Types.BUILTIN, "=="); public static final Name Builtin_fail = Name.create(Types.BUILTIN, "fail"); public static final Name Builtin_runProc = Name.create(Types.BUILTIN, "runProc"); + public static final Name Builtin_createCHRContext = Name.create(Types.BUILTIN, "createCHRContext"); public static final Name Data_XML_createElement = Name.create("Data/XML", "createElement"); public static final Type Data_XML_Element = Types.con("Data/XML", "Element"); public static final TCon Expressions_Context_Context = Types.con("Expressions/Context", "Context"); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java index cc883c0ea..5d258dd9e 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java @@ -189,7 +189,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); } @@ -205,7 +205,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); } @@ -217,7 +217,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); } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java index 652adf93e..4bf5d847e 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java @@ -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 importsAst = new ArrayList(); ArrayList dataTypesAst = new ArrayList(); ArrayList typeAliasesAst = new ArrayList(); @@ -53,6 +52,7 @@ public class DeclarationClassification { ArrayList effectsAst = new ArrayList(); ArrayList rulesAst = new ArrayList(); ArrayList mappingRelationsAst = new ArrayList(); + ArrayList rulesetsAst = new ArrayList(); THashMap valueDocumentation = new THashMap(); THashMap relationDocumentation = new THashMap(); @@ -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) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java index 7887ed717..359448e1d 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java @@ -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; @@ -48,6 +50,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; @@ -85,6 +88,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; @@ -212,7 +216,8 @@ public class Elaboration { public void addTypesToEnvironment( ArrayList dataTypesAst, ArrayList typeAliasesAst, - ArrayList effectsAst) { + ArrayList effectsAst, + ArrayList rulesetsAst) { for(DDataAst dataType : dataTypesAst) { dataType.parameterKinds = new Kind[dataType.parameters.length]; Kind constructorKind = Kinds.STAR; @@ -227,8 +232,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; } @@ -236,9 +240,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) { @@ -249,11 +251,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]; @@ -704,6 +719,18 @@ public class Elaboration { } } + public void processRulesets(ArrayList 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. diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/NamespaceOfModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/NamespaceOfModule.java index 77e6e96df..8621283b7 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/NamespaceOfModule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/NamespaceOfModule.java @@ -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 { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java index 643513d67..cd43b76e1 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java @@ -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)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); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java index d37b75089..dcef289f0 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java @@ -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}); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java index 48aefbdac..b30021c1c 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRule.java @@ -1,8 +1,10 @@ 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.PlanOp; -import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan; +import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan; import org.simantics.scl.compiler.elaboration.chr.planning.QueryPlanningContext; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; @@ -28,9 +30,15 @@ public class CHRRule extends Symbol { public Variable[] existentialVariables; // Analysis - public int firstPriorityExecuted; + //public int firstPriorityExecuted; public int lastPriorityExecuted; + // Plans + public ArrayList plans = new ArrayList(); + + // Code generation, move to CHRPriority + public String containerClassName; + public CHRRule(long location, CHRQuery head, CHRQuery body, Variable[] existentialVariables) { this.location = location; this.head = head; @@ -98,7 +106,7 @@ public class CHRRule extends Symbol { if(!head.createQueryPlan(context, new EVariable(activeFact), i)) return; body.createEnforcePlan(context, priority); - constraint.plans.add(new PrioritizedPlan(priority, activeFact, context.getPlanOps())); + addPlan(new CHRSearchPlan(constraint, activeFact, context.getPlanOps())); hasActiveLiteral = true; } @@ -111,10 +119,14 @@ public class CHRRule extends Symbol { /*System.out.println(this); for(PlanOp planOp : context.getPlanOps()) System.out.println(" " + planOp);*/ - initConstraint.plans.add(new PrioritizedPlan(priority, activeFact, context.getPlanOps())); + addPlan(new CHRSearchPlan(initConstraint, activeFact, context.getPlanOps())); } } + private void addPlan(CHRSearchPlan plan) { + plans.add(plan); + } + public String toString() { StringBuilder b = new StringBuilder(); ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java index bb5491ad1..bb00f0885 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java @@ -7,23 +7,30 @@ import org.simantics.scl.compiler.compilation.CompilationContext; 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; @@ -31,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; @@ -42,15 +51,22 @@ public class CHRRuleset extends Symbol { public ArrayList constraints = new ArrayList(); public ArrayList rules = new ArrayList(); + public ArrayList includes = new ArrayList(); + public THashMap constraintSourceMap = new THashMap(); + public THashMap activeConstraintGGInfo = new THashMap(); // contains also imported constraints + public THashMap> inverseActiveConstraintSourceMap = new THashMap>(); + + 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; @@ -58,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); @@ -68,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; @@ -81,26 +118,36 @@ public class CHRRuleset extends Symbol { } public void collectRefs(TObjectIntHashMap 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 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 vars) { + for(IncludeStatement include : includes) + include.value.collectFreeVariables(vars); for(CHRRule rule : rules) rule.collectFreeVariables(vars); } @@ -112,77 +159,167 @@ 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 list = inverseActiveConstraintSourceMap.get(include); + if(list == null) { + list = new ArrayList(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 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 effects) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRulesetObject.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRulesetObject.java index 73ba8ea1a..96e86aed1 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRulesetObject.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRulesetObject.java @@ -1,31 +1,83 @@ 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.CHRCodeGenerator; +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 parameterIndexMap; + public TypeDesc[] parameterTypeDescs; + public CHRRulesetObject(BoundVar target, CHRRuleset ruleset) { - super(ruleset.storeType); + super(ruleset.runtimeRulesetType); this.setTarget(target); this.ruleset = ruleset; } @Override public Constant liftClosure(BoundVar newTarget, BoundVar[] parameters) { - ruleset.this_ = newTarget; - ruleset.parameters = parameters; - return new JavaConstructor(ruleset.storeClassName, Types.PROC, ruleset.storeType, Types.getTypes(parameters)); + ruleset.rulesetObject = this; + this.this_ = newTarget; + this.parameters = parameters; + this.parameterIndexMap = new TObjectIntHashMap<>(parameters.length); + for(int i=0;i { + 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 index 000000000..dbe33d6eb --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/CHRConstraintGGInfo.java @@ -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; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/UsageAnalysis.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/UsageAnalysis.java index 3d5e0246b..a738c1f42 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/UsageAnalysis.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/analysis/UsageAnalysis.java @@ -12,13 +12,14 @@ import gnu.trove.map.hash.THashMap; public class UsageAnalysis { public static void analyzeUsage(CHRRuleset ruleset) { THashMap> 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> 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> 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) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PrioritizedPlan.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/CHRSearchPlan.java similarity index 59% rename from bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PrioritizedPlan.java rename to bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/CHRSearchPlan.java index f7a072e5d..f958e459b 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PrioritizedPlan.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/CHRSearchPlan.java @@ -2,17 +2,18 @@ package org.simantics.scl.compiler.elaboration.chr.plan; import java.util.List; +import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.elaboration.expressions.Variable; import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction; -public class PrioritizedPlan { - public int priority; +public class CHRSearchPlan { + public CHRConstraint constraint; public Variable activeFact; public List ops; public SSAFunction implementation; - public PrioritizedPlan(int priority, Variable activeFact, List ops) { - this.priority = priority; + public CHRSearchPlan(CHRConstraint constraint, Variable activeFact, List ops) { + this.constraint = constraint; this.activeFact = activeFact; this.ops = ops; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/ClaimOp.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/ClaimOp.java index ad6129aad..5b7f81664 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/ClaimOp.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/ClaimOp.java @@ -31,7 +31,7 @@ public class ClaimOp extends PlanOp { for(int i=0;i parameters = new ArrayList(expressions.length+1); - parameters.add(planContext.storeVar); + parameters.add(planContext.getStoreVar(constraint)); for(int i=0;i>i)&1)==1) parameters.add(expressions[i].toVal(context.environment, w)); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanContext.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanContext.java index aea2cbfdc..bc6b7da58 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanContext.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanContext.java @@ -2,8 +2,6 @@ package org.simantics.scl.compiler.elaboration.chr.plan; import java.util.ArrayList; -import javax.crypto.CipherInputStream; - import org.simantics.scl.compiler.compilation.CompilationContext; import org.simantics.scl.compiler.constants.IntegerConstant; import org.simantics.scl.compiler.constants.JavaComparisonOperation; @@ -12,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; @@ -24,21 +24,23 @@ 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 partnerFacts = new ArrayList(); public IVal currentId; - public PlanContext(CompilationContext context, CHRRuleset ruleset, IVal storeVar) { + 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; } public abstract void nextOp(CodeWriter w); public IVal generateNewId(long location, CodeWriter w) { if(currentId == null) - currentId = w.apply(location, ruleset.readCurrentId, storeVar); + currentId = w.apply(location, ruleset.readCurrentId, contextVar); IVal result = currentId; currentId = w.apply(location, IncreaseByOne.INSTANCE, currentId); return result; @@ -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; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanRealizer.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanRealizer.java index 0fbbcfba4..43fedf765 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanRealizer.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanRealizer.java @@ -11,8 +11,8 @@ public class PlanRealizer extends PlanContext { List ops; int id = 0; - public PlanRealizer(CompilationContext context, CHRRuleset ruleset, IVal storeVar, List ops) { - super(context, ruleset, storeVar); + public PlanRealizer(CompilationContext context, CHRRuleset ruleset, IVal storeVar, IVal contextVar, List ops) { + super(context, ruleset, storeVar, contextVar); this.ops = ops; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PostCommitOp.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PostCommitOp.java index af41f932b..5b3057dd9 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PostCommitOp.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PostCommitOp.java @@ -3,6 +3,7 @@ package org.simantics.scl.compiler.elaboration.chr.plan; import org.simantics.scl.compiler.compilation.CompilationContext; import org.simantics.scl.compiler.constants.IntegerConstant; import org.simantics.scl.compiler.constants.singletons.NullCheck; +import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.internal.codegen.continuations.ICont; import org.simantics.scl.compiler.internal.codegen.references.IVal; @@ -24,9 +25,9 @@ public class PostCommitOp extends PlanOp { @Override public void generateCode(CompilationContext context, PlanContext planContext, CodeWriter w) { if(planContext.currentId != null) { - w.apply(location, planContext.ruleset.writeCurrentId, planContext.storeVar, planContext.currentId); + w.apply(location, planContext.ruleset.writeCurrentId, planContext.contextVar, planContext.currentId); planContext.currentId = null; - w.apply(location, planContext.ruleset.activateProcedure, planContext.storeVar, new IntegerConstant(priority)); + w.apply(location, CHRRuleset.ACTIVATE, planContext.contextVar, new IntegerConstant(priority+planContext.ruleset.initialPriorityNumber)); } for(PartnerFact activeFact : planContext.partnerFacts) { if(activeFact.killAfterMatch) { @@ -35,7 +36,7 @@ public class PostCommitOp extends PlanOp { else { CodeWriter iterateAlive = w.createBlock(activeFact.constraint.factType); w.jump(iterateAlive.getContinuation(), w.apply(location, activeFact.nextFact, activeFact.factVar)); - iterateUntilLiveFactFound(iterateAlive, activeFact); + iterateUntilLiveFactFound(iterateAlive, activeFact); } break; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PreCommitOp.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PreCommitOp.java index 95e865be3..c4629f6d0 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PreCommitOp.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PreCommitOp.java @@ -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); } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java index 868d70a6f..c0f439288 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java @@ -16,9 +16,8 @@ import org.simantics.scl.compiler.constants.generic.ParameterStackItem; import org.simantics.scl.compiler.constants.generic.StackItem; import org.simantics.scl.compiler.elaboration.chr.CHRRelation; import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; -import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan; -import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerator; -import org.simantics.scl.compiler.internal.codegen.chr.CHRFactCodeGenerator; +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.IVal; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor; @@ -39,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,12 +55,10 @@ public class CHRConstraint extends Symbol implements CHRRelation { public Constant[] accessors; public Constant addProcedure; public Constant removeProcedure; - public Constant isAlive; - public TIntObjectHashMap indices; + public String nextContainerFieldName; - // Query plans - public ArrayList plans = new ArrayList(); + public TIntObjectHashMap indices; public static class IndexInfo { public final int indexMask; @@ -87,8 +84,8 @@ public class CHRConstraint extends Symbol implements CHRRelation { JavaTypeTranslator jtt = context.javaTypeTranslator; this.parentRuleset = parentRuleset; - this.factClassName = parentRuleset.storeClassName + "$" + name; - TCon factTypeConstructor = Types.con(parentRuleset.storeType.module, parentRuleset.storeType.name + "$" + 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); @@ -109,24 +106,29 @@ public class CHRConstraint extends Symbol implements CHRRelation { null); //this.constructor = new JavaConstructor(factClassName, Types.PROC, factType, constructorTypes); this.accessId = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, Types.INTEGER, new Type[] {factType}, - null, new FieldRef(factClassName, "id", CHRCodeGenerator.FACT_ID_TYPE), null); + null, new FieldRef(CHRCodeGenerationConstants.CHRFact_name, "id", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null); this.accessors = new Constant[parameterTypes.length]; for(int i=0;i(Math.min(10, 1 << parameterTypes.length)); 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 @@ -154,19 +156,19 @@ public class CHRConstraint extends Symbol implements CHRRelation { private IndexInfo createIndexInfo(CompilationContext context, int indexMask) { ArrayList keyTypeList = new ArrayList(parameterTypes.length+1); - keyTypeList.add(parentRuleset.storeType); + keyTypeList.add(parentRuleset.runtimeRulesetType); for(int i=0;i>i)&1)==1) keyTypeList.add(parameterTypes[i]); String indexName = nameOfIndex(indexMask, parameterTypes.length); Constant accessIndex; if(indexMask == 0) { - accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.storeType}, - null, new FieldRef(parentRuleset.storeClassName, name + "$" + indexName, factTypeDesc), null); + accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.runtimeRulesetType}, + null, new FieldRef(parentRuleset.runtimeRulesetClassName, name + "$" + indexName, factTypeDesc), null); } else { Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]); - accessIndex = new JavaMethod(true, parentRuleset.storeClassName, name + "$" + indexName, Types.PROC, factType, keyTypes); + accessIndex = new JavaMethod(true, parentRuleset.runtimeRulesetClassName, name + "$" + indexName, Types.PROC, factType, keyTypes); } return new IndexInfo( indexMask, @@ -177,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) { @@ -192,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; } @@ -205,22 +211,13 @@ public class CHRConstraint extends Symbol implements CHRRelation { public void setMayBeRemoved() { if(removeProcedure == null) { - removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType}, - new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)}, - new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.storeTypeDesc}), + removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.runtimeRulesetType, factType}, + new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.runtimeRulesetType)}, + new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.runtimeRulesetTypeDesc}), null); - isAlive = new JavaMethod(true, factClassName, "isAlive", Types.PROC, Types.BOOLEAN, factType); } } - public int getMinimumPriority() { - return plans.get(0).priority; - } - - public boolean isPassive() { - return plans.isEmpty(); - } - public TPred[] getTypeConstraints() { return TPred.EMPTY_ARRAY; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java index 203bd81d2..d9746bb04 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java @@ -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); + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TypeTranslationContext.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TypeTranslationContext.java index 927720611..1eea959fd 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TypeTranslationContext.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TypeTranslationContext.java @@ -126,4 +126,8 @@ public class TypeTranslationContext { errorLog.log(loc, "Expected a type with kind " + expectedKind + " but got " + provided + "."); } } + + public CompilationContext getCompilationContext() { + return compilationContext; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java index c5f30417e..157efb360 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java @@ -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 statements = new LinkedList(); + ArrayList statements = new ArrayList(); boolean monadic; public EBlock() { @@ -33,9 +33,17 @@ public class EBlock extends ASTExpression { this.monadic = monadic; } - public LinkedList getStatements() { + public ArrayList 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)(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 index 000000000..e8a5cb81b --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRRulesetConstructor.java @@ -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 allRefs, TIntHashSet refs) { + ruleset.collectRefs(allRefs, refs); + } + @Override + public void collectVars(TObjectIntHashMap 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 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 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 index 000000000..500c80573 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRRulesetConstructor.java @@ -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; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java index 8d54d5063..4cf513c54 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java @@ -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); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java index 62e21f204..ad32098ba 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java @@ -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); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java index 5d1d2eb95..ac61eb486 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java @@ -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 consumer) { } + + @Override + public CHRRuleset getRuleset(String name) throws AmbiguousNameException { + return null; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Environments.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Environments.java index df86c1130..3be214d2d 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Environments.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Environments.java @@ -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 getRuleset = new NamespaceValueAccessor() { + @Override + public CHRRuleset get(Namespace ns, String name) throws AmbiguousNameException { + return ns.getRuleset(name); + } + }; private static T getEnvironmentEntry(Environment environment, String localName, NamespaceValueAccessor accessor) throws AmbiguousNameException { Namespace namespace = environment.getLocalNamespace(); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Namespace.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Namespace.java index 9b4712c84..e5af69204 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Namespace.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/Namespace.java @@ -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 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/NamespaceImpl.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/NamespaceImpl.java index 0c97d308a..214749bcb 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/NamespaceImpl.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/environment/NamespaceImpl.java @@ -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 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(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 proc) { for(ModuleImport moduleImport : moduleImports) diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerationConstants.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerationConstants.java new file mode 100644 index 000000000..37f1202e3 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerationConstants.java @@ -0,0 +1,46 @@ +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 { + + public static final TypeDesc FACT_ID_TYPE = TypeDesc.INT; + + public static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex"; + public static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name); + + public static final String CHRFact_name = "org/simantics/scl/runtime/chr/CHRFact"; + public static final TypeDesc CHRFact = TypeDesc.forClass(CHRFact_name); + + public static final String CHRPriority_name = "org/simantics/scl/runtime/chr/CHRPriority"; + + public static final String CHRPriorityFactContainer_name = "org/simantics/scl/runtime/chr/CHRPriorityFactContainer"; + public static final TypeDesc CHRPriorityFactContainer = TypeDesc.forClass(CHRPriorityFactContainer_name); + + public static final String CHRContext_name = "org/simantics/scl/runtime/chr/CHRContext"; + public static final TypeDesc CHRContext = TypeDesc.forClass(CHRContext_name); + + public static final String CHRRuntimeRuleset_name = "org/simantics/scl/runtime/chr/CHRRuntimeRuleset"; + public static final TypeDesc CHRRuntimeRuleset = TypeDesc.forClass(CHRRuntimeRuleset_name); + + public static String priorityName(int priority) { + return "l" + priority; + } + + public static String fieldName(int id) { + return "c" + id; + } + + 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"; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java deleted file mode 100644 index 3a249c5de..000000000 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.simantics.scl.compiler.internal.codegen.chr; - -import java.util.ArrayList; - -import org.cojen.classfile.TypeDesc; -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.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.MethodBuilderBase; -import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder; - -public class CHRCodeGenerator { - - public static final TypeDesc FACT_ID_TYPE = TypeDesc.INT; - private static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue"; - private static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name); - private static final String QUEUE = "queue"; - - public static void generateStore(ModuleBuilder moduleBuilder, CHRRuleset ruleset) { - ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.storeClassName, "java/lang/Object"); - if(ruleset.parameters == null) - ruleset.parameters = new BoundVar[0]; - ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters); - - ArrayList hashIndexInitializations = new ArrayList<>(); - for(CHRConstraint constraint : ruleset.constraints) - generateFact(storeClassBuilder, constraint, hashIndexInitializations); - - // Fields - for(int i=0;i hashIndexInitializations) { - CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, constraint); - generator.generate(hashIndexInitializations); - } -} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java index 06725ec2b..865ab22e6 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java @@ -6,42 +6,27 @@ 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.plan.PrioritizedPlan; 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.references.BoundVar; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; -import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils; 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; -import gnu.trove.list.array.TIntArrayList; -import gnu.trove.set.hash.THashSet; - -public class CHRFactCodeGenerator { - private static final TypeDesc FACT_ID_TYPE = TypeDesc.INT; - private static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex"; - private static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name); - private static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue"; - private static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name); - private static final String Fact_name = "org/simantics/scl/runtime/chr/Fact"; - private static final TypeDesc Fact = TypeDesc.forClass(Fact_name); - private static final String QUEUE = "queue"; +public class CHRFactCodeGenerator implements CHRCodeGenerationConstants { private ModuleBuilder moduleBuilder; private JavaTypeTranslator jtt; - private CHRRuleset ruleset; private ClassBuilder storeClassBuilder; + private CHRRuleset ruleset; private CHRConstraint constraint; private String factClassName; private TypeDesc factTypeDesc; - private ClassBuilder factClassBuilder; + private ClassBuilder classBuilder; private TypeDesc storeTypeDesc; private TypeDesc[] storeTypeDescArray; @@ -49,10 +34,10 @@ public class CHRFactCodeGenerator { 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.ruleset = constraint.parentRuleset; this.moduleBuilder = storeClassBuilder.getModuleBuilder(); this.jtt = moduleBuilder.getJavaTypeTranslator(); @@ -61,7 +46,7 @@ public class CHRFactCodeGenerator { this.factClassName = storeClassBuilder.getClassName() + "$" + constraint.name; this.factTypeDesc = TypeDesc.forClass(factClassName); - this.factClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, "java/lang/Object", Fact_name); + this.classBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, CHRFact_name); this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes); this.supportsRemoval = constraint.mayBeRemoved(); @@ -77,16 +62,10 @@ public class CHRFactCodeGenerator { if(supportsRemoval) generateRemove(); - generateIsAlive(); - - for(int i=0;i usedParameters = new THashSet(); - - private void generateActivateI(int i) { - PrioritizedPlan plan = constraint.plans.get(i); - MethodBuilder mb = factClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate" + i, TypeDesc.BOOLEAN, storeTypeDescArray); - LocalVariable storeVar = mb.getParameter(0); - LocalVariable factVar = new LocalVariable(0, factTypeDesc); - mb.setLocalVariable(ruleset.this_, storeVar); - mb.setLocalVariable(plan.implementation.getParameters()[0], factVar); - - // Set closure parameters - usedParameters.clear(); - plan.implementation.forValRefs(valRef -> { - if(valRef.getBinding() instanceof BoundVar) - usedParameters.add((BoundVar)valRef.getBinding()); - }); - for(int j=0;j labels = new ArrayList