package org.simantics.scl.compiler.elaboration.expressions; import java.util.ArrayList; import java.util.List; import org.simantics.scl.compiler.elaboration.chr.CHRRule; import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; import org.simantics.scl.compiler.elaboration.chr.ast.CHRQueryTranslationMode; import org.simantics.scl.compiler.elaboration.chr.translation.CHRTranslation; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.expressions.block.BlockType; import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement; import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement; import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement; import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement; import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement; import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement; import org.simantics.scl.compiler.elaboration.expressions.block.Statement; import org.simantics.scl.compiler.elaboration.expressions.block.StatementGroup; import org.simantics.scl.compiler.errors.Locations; public class EBlock extends ASTExpression { public ArrayList statements = new ArrayList(); BlockType blockType = BlockType.Normal; public EBlock() { this.blockType = blockType; } public void setBlockType(BlockType blockType) { this.blockType = blockType; } public void addStatement(Statement statement) { statements.add(statement); } public ArrayList getStatements() { return statements; } public Statement getFirst() { return statements.get(0); } public Statement getLast() { return statements.get(statements.size()-1); } @Override public Expression resolve(TranslationContext context) { if(statements.isEmpty()) { context.getErrorLog().log(location, "Block should not be empty."); return new EError(location); } int i = statements.size()-1; Statement last = statements.get(i); if(!(last instanceof GuardStatement)) { context.getErrorLog().log(last.location, "Block should end with an expression"); return new EError(location); } Expression in = ((GuardStatement)last).value; while(--i >= 0) { Statement cur = statements.get(i); StatementGroup group = cur.getStatementGroup(); if(group == null) in = cur.toExpression(context, blockType, in); else { int endId = i+1; while(i>0 && statements.get(i-1).getStatementGroup() == group) --i; switch(group) { case LetFunction: in = extractLet(i, endId, in); break; case Rule: in = extractRules(i, endId, in); break; case CHR: { CHRRuleset ruleset = extractCHRRules(context, i, endId); long location = Locations.combine(ruleset.location, in.location); in = new ECHRRuleset(ruleset, in); in.location = location; break; } } } } return in.resolve(context); } private Expression extractRules(int begin, int end, Expression in) { return new EPreRuleset(statements.subList(begin, end).toArray(new RuleStatement[end-begin]), in); } private CHRRuleset extractCHRRules(TranslationContext context, int begin, int end) { CHRRuleset ruleset = new CHRRuleset(); ruleset.location = Locations.combine(statements.get(begin).location, statements.get(end-1).location); for(int i=begin;i)(List)statements.subList(begin, end), in); } public static Expression create(ArrayList statements) { EBlock block = new EBlock(); for(Expression statement : statements) block.addStatement(new GuardStatement(statement)); return block; } @Override public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) { location = loc; for(Statement statement : statements) statement.setLocationDeep(loc); } } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } @Override public int getSyntacticFunctionArity() { if(blockType != BlockType.Normal) return 0; Statement lastStatement = statements.get(statements.size()-1); if(!(lastStatement instanceof GuardStatement)) return 0; return ((GuardStatement)lastStatement).value.getSyntacticFunctionArity(); } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } }