(refs #7250) Refactoring CHR implementation
[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.internal.codegen.references.BoundVar;
11 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
12 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
13 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
14 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
15
16 public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants {
17
18     public static void generateRuntimeRuleset(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {
19         ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetName, CHRRuntimeRuleset_name);
20         if(ruleset.parameters == null)
21             ruleset.parameters = new BoundVar[0];
22         ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters); 
23
24         ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<StoreInitialization>();
25         for(CHRConstraint constraint : ruleset.constraints)
26             generateFact(storeClassBuilder, constraint, hashIndexInitializations);
27         
28         for(int i=ruleset.rules.size()-1;i>=0;--i)
29             generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i));
30
31         // Fields
32         for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
33             TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
34             if(typeDesc.equals(TypeDesc.VOID))
35                 continue;
36             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.parameterName(i), typeDesc);
37         }
38         for(StoreInitialization ini : hashIndexInitializations)
39             storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
40         for(CHRRule rule : ruleset.rules)
41             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
42
43         // Constructors
44
45         {
46             MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);
47             mb.loadThis();
48             mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
49             for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
50                 TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
51                 if(typeDesc.equals(TypeDesc.VOID))
52                     continue;
53                 mb.loadThis();
54                 mb.loadLocal(mb.getParameter(i));
55                 mb.storeField(ruleset.runtimeRulesetName, CHRCodeGenerationConstants.parameterName(i), ruleset.parameterTypeDescs[i]);
56             }
57             for(StoreInitialization ini : hashIndexInitializations) {
58                 mb.loadThis();
59                 mb.newObject(ini.className);
60                 mb.dup();
61                 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
62                 mb.storeField(ruleset.runtimeRulesetName, ini.fieldName, ini.fieldType);
63             }
64             TypeDesc[] runtimeRulesetTypeDescArray = new TypeDesc[] {TypeDesc.forClass(storeClassBuilder.getClassName())};
65             for(CHRRule rule : ruleset.rules) {
66                 mb.loadThis();
67                 mb.newObject(rule.containerClassName);
68                 mb.dup();
69                 mb.loadThis();
70                 mb.invokeConstructor(rule.containerClassName, runtimeRulesetTypeDescArray);
71                 mb.storeField(ruleset.runtimeRulesetName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
72             }
73             mb.returnVoid();
74             mb.finish();
75         }
76
77         moduleBuilder.addClass(storeClassBuilder);
78     }
79
80     private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
81         CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, constraint);
82         generator.generate(hashIndexInitializations);
83     }
84
85     private static void generateFactContainer(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
86         CHRPriorityFactContainerCodeGenerator generator = new CHRPriorityFactContainerCodeGenerator(storeClassBuilder, ruleset, rule); 
87         generator.generate();
88         rule.containerClassName = generator.containerClassName;
89     }
90 }