1 package org.simantics.scl.compiler.internal.codegen.chr;
3 import java.util.ArrayList;
5 import org.cojen.classfile.TypeDesc;
6 import org.objectweb.asm.Opcodes;
7 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
8 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
9 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
10 import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
13 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
14 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
15 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
16 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
17 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
19 public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants {
21 public static void generateRuntimeRuleset(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {
22 ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetClassName, CHRRuntimeRuleset_name);
23 if(ruleset.rulesetObject.parameters == null)
24 ruleset.rulesetObject.parameters = new BoundVar[0];
25 TypeDesc[] parameterTypeDescs = ruleset.rulesetObject.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.rulesetObject.parameters);
27 ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<StoreInitialization>();
28 for(CHRConstraint constraint : ruleset.constraints)
29 generateFact(storeClassBuilder, ruleset, constraint, hashIndexInitializations);
31 for(int i=ruleset.rules.size()-1;i>=0;--i)
32 generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i));
35 for(int i=0;i<parameterTypeDescs.length;++i) {
36 TypeDesc typeDesc = parameterTypeDescs[i];
37 if(typeDesc.equals(TypeDesc.VOID))
39 storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.parameterName(i), typeDesc);
41 for(StoreInitialization ini : hashIndexInitializations)
42 storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
43 for(CHRRule rule : ruleset.rules)
44 storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
45 if(ruleset.extensible)
46 for(CHRConstraint constraint : ruleset.constraints)
47 if(constraint.nextContainerFieldName != null)
48 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, constraint.nextContainerFieldName, CHRPriorityFactContainer);
49 if(ruleset.extensible)
50 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, "currentId", FACT_ID_TYPE);
55 MethodBuilder mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, parameterTypeDescs);
56 //TypeDesc.concat(ruleset.parameterTypeDescs, includeTypeDescs));
58 mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
60 for(int i=0;i<parameterTypeDescs.length;++i) {
61 TypeDesc typeDesc = parameterTypeDescs[i];
62 if(typeDesc.equals(TypeDesc.VOID))
65 mb.loadLocal(mb.getParameter(p++));
66 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
68 for(StoreInitialization ini : hashIndexInitializations) {
70 mb.newObject(ini.className);
72 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
73 mb.storeField(ruleset.runtimeRulesetClassName, ini.fieldName, ini.fieldType);
75 TypeDesc[] runtimeRulesetTypeDescArray = new TypeDesc[] {TypeDesc.forClass(storeClassBuilder.getClassName())};
76 for(CHRRule rule : ruleset.rules) {
78 mb.newObject(rule.containerClassName);
81 mb.invokeConstructor(rule.containerClassName, runtimeRulesetTypeDescArray);
82 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
90 for(IncludeStatement include : ruleset.includes) {
92 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "register", TypeDesc.VOID,
93 new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
94 LocalVariable contextVar = mb.getParameter(0);
95 LocalVariable importedStore = mb.getParameter(1);
96 ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
98 for(CHRConstraint constraint : list) {
99 int minimumPriority = ruleset.getMinimumPriority(constraint);
100 if(minimumPriority == Integer.MAX_VALUE)
102 mb.loadLocal(importedStore);
104 mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
105 mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
109 mb.loadLocal(contextVar);
110 mb.loadLocal(contextVar);
111 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
112 mb.loadLocal(importedStore);
113 mb.loadField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
114 mb.invokeStatic("java/lang/Math", "max", FACT_ID_TYPE, new TypeDesc[] {FACT_ID_TYPE, FACT_ID_TYPE});
115 mb.storeField(CHRContext_name, "currentId", FACT_ID_TYPE);
122 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "unregister", TypeDesc.VOID,
123 new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
124 LocalVariable contextVar = mb.getParameter(0);
125 LocalVariable importedStore = mb.getParameter(1);
126 ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
128 for(CHRConstraint constraint : list) {
129 int minimumPriority = ruleset.getMinimumPriority(constraint);
130 if(minimumPriority == Integer.MAX_VALUE)
132 mb.loadLocal(importedStore);
134 mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
138 mb.loadLocal(importedStore);
139 mb.loadLocal(contextVar);
140 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
141 mb.storeField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
148 if(ruleset.initializer != null) {
149 MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "initialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
150 ruleset.rulesetObject.realizeMethod(mb,
153 mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
156 ruleset.initializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
159 if(ruleset.deinitializer != null) {
160 MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "deinitialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
161 ruleset.rulesetObject.realizeMethod(mb,
164 mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
167 ruleset.deinitializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
171 moduleBuilder.addClass(storeClassBuilder);
174 private static void generateFact(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
175 CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, ruleset, constraint);
176 generator.generate(hashIndexInitializations);
179 private static void generateFactContainer(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
180 CHRPriorityFactContainerCodeGenerator generator = new CHRPriorityFactContainerCodeGenerator(storeClassBuilder, ruleset, rule);
181 generator.generate();
182 rule.containerClassName = generator.containerClassName;