]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRPriorityFactContainerCodeGenerator.java
(refs #7250) CHR rules modularization (first working version)
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRPriorityFactContainerCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;
2
3 import java.util.ArrayList;
4 import java.util.concurrent.atomic.AtomicReference;
5
6 import org.cojen.classfile.TypeDesc;
7 import org.objectweb.asm.Label;
8 import org.objectweb.asm.Opcodes;
9 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
10 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
11 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
12 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
13 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
14 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
15 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
16 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
17 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
18
19 import gnu.trove.map.hash.THashMap;
20 import gnu.trove.procedure.TObjectObjectProcedure;
21
22 public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationConstants {
23     ClassBuilder storeClassBuilder;
24     String containerClassName;
25     private TypeDesc containerTypeDesc;
26
27     private ClassBuilder classBuilder;
28     
29     private TypeDesc storeTypeDesc;
30     
31     private CHRRuleset ruleset;
32     private CHRRule rule;
33
34     public CHRPriorityFactContainerCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
35         this.storeClassBuilder = storeClassBuilder;
36         
37         this.containerClassName = storeClassBuilder.getClassName() + "$" + "CHRPriorityFactContainer" + rule.priority;
38         this.containerTypeDesc = TypeDesc.forClass(containerClassName);
39         this.classBuilder = new ClassBuilder(storeClassBuilder.getModuleBuilder(), Opcodes.ACC_PUBLIC, containerClassName, CHRPriorityFactContainer_name);
40         
41         this.storeTypeDesc = storeClassBuilder.getType();
42         
43         this.ruleset = ruleset;
44         this.rule = rule;
45     }
46     
47     public void generate() {
48         generateFields();
49         generateContructor();
50         
51         THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap = new THashMap<CHRConstraint, ArrayList<CHRSearchPlan>>(); 
52         for(CHRSearchPlan plan : rule.plans) {
53             ArrayList<CHRSearchPlan> list = planMap.get(plan.constraint);
54             if(list == null) {
55                 list = new ArrayList<CHRSearchPlan>(4);
56                 planMap.put(plan.constraint, list);
57             }
58             list.add(plan);
59         }
60         planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
61             @Override
62             public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
63                 for(int i=0;i<plans.size();++i)
64                     generateActivate(constraint, plans.get(i), i);
65                 return true;
66             }
67         });
68         generateActivate(planMap);
69         
70         classBuilder.getModuleBuilder().addClass(classBuilder);
71     }
72     
73     private void generateContructor() {
74         MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
75         mb.loadThis();
76         mb.loadConstant(rule.priority + ruleset.initialPriorityNumber);
77         mb.invokeSuperConstructor(new TypeDesc[] {TypeDesc.INT});
78         mb.loadThis();
79         mb.loadLocal(mb.getParameter(0));
80         mb.storeField(containerClassName, "parent", storeTypeDesc);
81         mb.returnVoid();
82         mb.finish();
83     }
84     
85     private void generateFields() {
86         classBuilder.addField(Opcodes.ACC_PUBLIC, "parent", storeTypeDesc);
87     }
88
89     // protected abstract void activate(CHRContext context, CHRFact fact);
90     private void generateActivate(THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap) {
91         // @Override
92         // public int activate(Object context, int priority) {
93         //     return -1;
94         // }
95
96         MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
97         Label finishLabel = mb.createLabel();
98
99         AtomicReference<Label> nextLabel = new AtomicReference<Label>();
100         planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
101             @Override
102             public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
103                 int nextPriority = ruleset.getAndUpdateNextPriority(constraint, rule.priority);
104                 
105                 Label next = nextLabel.get();
106                 if(next != null)
107                     mb.setLocation(next);
108                 mb.loadLocal(mb.getParameter(1));
109                 mb.instanceOf(constraint.factTypeDesc);
110                 next = mb.createLabel();
111                 nextLabel.set(next);
112                 mb.ifZeroComparisonBranch(next, "==");
113                 
114                 for(int id=0;id<plans.size();++id) {
115                     mb.loadThis();
116                     mb.loadLocal(mb.getParameter(0));
117                     mb.loadLocal(mb.getParameter(1));
118                     mb.checkCast(constraint.factTypeDesc);
119                     mb.invokeVirtual(classBuilder.getClassName(), "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
120                     mb.ifZeroComparisonBranch(finishLabel, "==");
121                 }
122                 
123                 // Add to priority queue
124                 if(nextPriority != Integer.MAX_VALUE) {
125                     mb.loadThis();
126                     mb.loadField(containerClassName, "parent", storeTypeDesc);
127                     mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(nextPriority), CHRPriorityFactContainer);
128                     mb.loadLocal(mb.getParameter(0));
129                     mb.loadLocal(mb.getParameter(1));
130                     mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
131                 }
132                 else if(constraint.nextContainerFieldName != null && !ruleset.constraintSourceMap.containsKey(constraint)) {
133                     mb.loadThis();
134                     mb.loadField(containerClassName, "parent", storeTypeDesc);
135                     mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
136                     LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
137                     mb.storeLocal(containerVar);
138                     
139                     mb.loadLocal(containerVar);
140                     mb.ifNullBranch(finishLabel, true);
141                     
142                     mb.loadLocal(containerVar);
143                     mb.loadLocal(mb.getParameter(0));
144                     mb.loadLocal(mb.getParameter(1));
145                     mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
146                 }
147                 
148                 mb.branch(finishLabel);
149                 return true;
150             }
151         });
152         {
153             Label next = nextLabel.get();
154             if(next != null)
155                 mb.setLocation(next);
156         }
157         
158         mb.setLocation(finishLabel);
159         mb.returnVoid();
160         mb.finish();
161     }
162     
163     // protected abstract void activate(CHRContext context, CHRFact fact);
164
165     private void generateActivate(CHRConstraint constraint, CHRSearchPlan plan, int id) {
166         MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
167         LocalVariable priorityVar = new LocalVariable(0, containerTypeDesc);
168         mb.loadLocal(priorityVar);
169         mb.loadField(containerClassName, "parent", storeTypeDesc);
170         LocalVariable parent = mb.createLocalVariable("parent", storeTypeDesc);
171         mb.storeLocal(parent);
172         ruleset.rulesetObject.realizeMethod(mb, (i, target) -> {
173             mb.loadLocal(parent);
174             mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(i), ruleset.rulesetObject.parameterTypeDescs[i]);
175             mb.store(target);
176         }, plan.implementation, parent, mb.getParameter(0), mb.getParameter(1));
177         mb.finish();
178     }
179 }