(refs #7365) Fixed the bug in the test CHR11.scl
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRRuntimeRulesetCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;
2
3 import java.util.ArrayList;
4
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;
18
19 public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants {
20
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); 
26
27         ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<StoreInitialization>();
28         for(CHRConstraint constraint : ruleset.constraints)
29             generateFact(storeClassBuilder, ruleset, constraint, hashIndexInitializations);
30         
31         for(int i=ruleset.rules.size()-1;i>=0;--i)
32             generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i));
33
34         // Fields
35         for(int i=0;i<parameterTypeDescs.length;++i) {
36             TypeDesc typeDesc = parameterTypeDescs[i];
37             if(typeDesc.equals(TypeDesc.VOID))
38                 continue;
39             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.parameterName(i), typeDesc);
40         }
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);
51         
52         // Constructors
53
54         {
55             MethodBuilder mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, parameterTypeDescs);
56                     //TypeDesc.concat(ruleset.parameterTypeDescs, includeTypeDescs));
57             mb.loadThis();
58             mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
59             int p=0;
60             for(int i=0;i<parameterTypeDescs.length;++i) {
61                 TypeDesc typeDesc = parameterTypeDescs[i];
62                 if(typeDesc.equals(TypeDesc.VOID))
63                     continue;
64                 mb.loadThis();
65                 mb.loadLocal(mb.getParameter(p++));
66                 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
67             }
68             for(StoreInitialization ini : hashIndexInitializations) {
69                 mb.loadThis();
70                 mb.newObject(ini.className);
71                 mb.dup();
72                 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
73                 mb.storeField(ruleset.runtimeRulesetClassName, ini.fieldName, ini.fieldType);
74             }
75             TypeDesc[] runtimeRulesetTypeDescArray = new TypeDesc[] {TypeDesc.forClass(storeClassBuilder.getClassName())};
76             for(CHRRule rule : ruleset.rules) {
77                 mb.loadThis();
78                 mb.newObject(rule.containerClassName);
79                 mb.dup();
80                 mb.loadThis();
81                 mb.invokeConstructor(rule.containerClassName, runtimeRulesetTypeDescArray);
82                 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
83             }
84             mb.returnVoid();
85             mb.finish();
86         }
87         
88         // Registration
89         
90         for(IncludeStatement include : ruleset.includes) {
91             {
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);
97                 if(list != null)
98                     for(CHRConstraint constraint : list) {
99                         int minimumPriority = ruleset.getMinimumPriority(constraint);
100                         if(minimumPriority == Integer.MAX_VALUE)
101                             continue;
102                         mb.loadLocal(importedStore);
103                         mb.loadThis();
104                         mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
105                         mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
106                     }
107                 
108                 // update context id
109                 mb.loadLocal(importedStore);
110                 mb.loadLocal(contextVar);
111                 mb.invokeVirtual("org/simantics/scl/runtime/chr/CHRRuntimeRuleset", "register", TypeDesc.VOID, new TypeDesc[] {CHRContext});
112                 /*mb.loadLocal(contextVar);
113                 mb.loadLocal(contextVar);
114                 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
115                 mb.loadLocal(importedStore);
116                 mb.loadField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
117                 mb.invokeStatic("java/lang/Math", "max", FACT_ID_TYPE, new TypeDesc[] {FACT_ID_TYPE, FACT_ID_TYPE});
118                 mb.storeField(CHRContext_name, "currentId", FACT_ID_TYPE);*/
119                 
120                 mb.returnVoid();
121                 mb.finish();
122             }
123             
124             {
125                 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "unregister", TypeDesc.VOID,
126                         new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
127                 LocalVariable contextVar = mb.getParameter(0);
128                 LocalVariable importedStore = mb.getParameter(1);
129                 ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
130                 if(list != null)
131                     for(CHRConstraint constraint : list) {
132                         int minimumPriority = ruleset.getMinimumPriority(constraint);
133                         if(minimumPriority == Integer.MAX_VALUE)
134                             continue;
135                         mb.loadLocal(importedStore);
136                         mb.loadNull();
137                         mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
138                     }
139                 
140                 // store context id
141                 mb.loadLocal(importedStore);
142                 mb.loadLocal(contextVar);
143                 mb.invokeVirtual("org/simantics/scl/runtime/chr/CHRRuntimeRuleset", "unregister", TypeDesc.VOID, new TypeDesc[] {CHRContext});
144                 /*mb.loadLocal(importedStore);
145                 mb.loadLocal(contextVar);
146                 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
147                 mb.storeField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);*/
148                 
149                 mb.returnVoid();
150                 mb.finish();
151             }
152         }
153         
154         if(ruleset.initializer != null) {
155             MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "initialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
156             ruleset.rulesetObject.realizeMethod(mb,
157                     (i, target) -> {
158                         mb.loadThis();
159                         mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
160                         mb.store(target);
161                     },
162                     ruleset.initializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
163             mb.finish();
164         }
165         if(ruleset.deinitializer != null) {
166             MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "deinitialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
167             ruleset.rulesetObject.realizeMethod(mb,
168                     (i, target) -> {
169                         mb.loadThis();
170                         mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
171                         mb.store(target);
172                     },
173                     ruleset.deinitializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
174             mb.finish();
175         }
176
177         moduleBuilder.addClass(storeClassBuilder);
178     }
179
180     private static void generateFact(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
181         CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, ruleset, constraint);
182         generator.generate(hashIndexInitializations);
183     }
184
185     private static void generateFactContainer(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
186         CHRPriorityFactContainerCodeGenerator generator = new CHRPriorityFactContainerCodeGenerator(storeClassBuilder, ruleset, rule); 
187         generator.generate();
188         rule.containerClassName = generator.containerClassName;
189     }
190 }