]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java
Refactoring CHR handling code
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EBlock.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
7 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
8 import org.simantics.scl.compiler.elaboration.chr.ast.CHRQueryTranslationMode;
9 import org.simantics.scl.compiler.elaboration.chr.translation.CHRTranslation;
10 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
11 import org.simantics.scl.compiler.elaboration.expressions.block.BlockType;
12 import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement;
13 import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement;
14 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
15 import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
16 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
17 import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement;
18 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
19 import org.simantics.scl.compiler.elaboration.expressions.block.StatementGroup;
20 import org.simantics.scl.compiler.errors.Locations;
21
22 public class EBlock extends ASTExpression {
23
24     public ArrayList<Statement> statements = new ArrayList<Statement>();
25     BlockType blockType = BlockType.Normal;
26     
27     public EBlock() {
28         this.blockType = blockType;
29     }
30     
31     public void setBlockType(BlockType blockType) {
32         this.blockType = blockType;
33     }
34
35     public void addStatement(Statement statement) {
36         statements.add(statement);
37     }
38     
39     public ArrayList<Statement> getStatements() {
40         return statements;
41     }
42     
43     public Statement getFirst() {
44         return statements.get(0);
45     }
46     
47     public Statement getLast() {
48         return statements.get(statements.size()-1);
49     }
50
51     @Override
52     public Expression resolve(TranslationContext context) {
53         if(statements.isEmpty()) {
54             context.getErrorLog().log(location, "Block should not be empty.");
55             return new EError(location);
56         }
57         int i = statements.size()-1;
58         Statement last = statements.get(i);
59         if(!(last instanceof GuardStatement)) {
60             context.getErrorLog().log(last.location, "Block should end with an expression");
61             return new EError(location);
62         }
63
64         Expression in = ((GuardStatement)last).value;
65         while(--i >= 0) {
66             Statement cur = statements.get(i);
67             StatementGroup group = cur.getStatementGroup();
68             if(group == null)
69                 in = cur.toExpression(context, blockType, in);
70             else {
71                 int endId = i+1;
72                 while(i>0 && statements.get(i-1).getStatementGroup() == group)
73                     --i;
74                 switch(group) {
75                 case LetFunction:
76                     in = extractLet(i, endId, in);
77                     break;
78                 case Rule:
79                     in = extractRules(i, endId, in);
80                     break;
81                 case CHR: {
82                     CHRRuleset ruleset = extractCHRRules(context, i, endId);
83                     long location = Locations.combine(ruleset.location, in.location);
84                     in = new ECHRRuleset(ruleset, in);
85                     in.location = location;
86                     break;
87                 }
88                 }
89             }
90         }
91         return in.resolve(context);
92     }
93
94     private Expression extractRules(int begin, int end, Expression in) {
95         return new EPreRuleset(statements.subList(begin, end).toArray(new RuleStatement[end-begin]), in);
96     }
97     
98     private CHRRuleset extractCHRRules(TranslationContext context, int begin, int end) {
99         CHRRuleset ruleset = new CHRRuleset();
100         ruleset.location = Locations.combine(statements.get(begin).location, statements.get(end-1).location);
101         for(int i=begin;i<end;++i) {
102             Statement statement = statements.get(i);
103             if(statement instanceof CHRStatement) {
104                 CHRStatement chrStatement = (CHRStatement)statement;
105                 ruleset.addRule(new CHRRule(chrStatement.location,
106                         chrStatement.head.translate(context, CHRQueryTranslationMode.RULE_HEAD),
107                         chrStatement.body.translate(context, CHRQueryTranslationMode.RULE_BODY)));
108             }
109             else if(statement instanceof ConstraintStatement)
110                 ruleset.addConstraint(CHRTranslation.convertConstraintStatement(context, (ConstraintStatement)statement));
111             else if(statement instanceof IncludeStatement)
112                 ruleset.includes.add((IncludeStatement)statement);
113             else
114                 context.getErrorLog().log(statement.location, "Invalid CHR statement.");
115         }
116         return ruleset;
117     }
118
119     public CHRRuleset extractCHRRules(TranslationContext context) {
120         return extractCHRRules(context, 0, statements.size());
121     }
122     
123     @SuppressWarnings("unchecked")
124     private Expression extractLet(int begin, int end, Expression in) {
125         return new EPreLet((List<LetStatement>)(List<?>)statements.subList(begin, end), in);
126     }
127
128     public static Expression create(ArrayList<Expression> statements) {
129         EBlock block = new EBlock();
130         for(Expression statement : statements)
131             block.addStatement(new GuardStatement(statement));
132         return block;
133     }
134
135     @Override
136     public void setLocationDeep(long loc) {
137         if(location == Locations.NO_LOCATION) {
138             location = loc;
139             for(Statement statement : statements)
140                 statement.setLocationDeep(loc);
141         }
142     }
143     
144     @Override
145     public Expression accept(ExpressionTransformer transformer) {
146         return transformer.transform(this);
147     }
148
149     @Override
150     public int getSyntacticFunctionArity() {
151         if(blockType != BlockType.Normal)
152             return 0;
153         Statement lastStatement = statements.get(statements.size()-1);
154         if(!(lastStatement instanceof GuardStatement))
155             return 0;
156         return ((GuardStatement)lastStatement).value.getSyntacticFunctionArity();
157     }
158     
159     @Override
160     public void accept(ExpressionVisitor visitor) {
161         visitor.visit(this);
162     }
163 }