package org.simantics.scl.compiler.elaboration.expressions; import java.util.ArrayList; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.common.names.Names; import org.simantics.scl.compiler.common.precedence.Associativity; import org.simantics.scl.compiler.common.precedence.Precedence; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.errors.NotPatternException; import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; import org.simantics.scl.compiler.elaboration.modules.SCLValue; import org.simantics.scl.compiler.errors.Locations; public class EBinary extends ASTExpression { public static final int NEGATION_LEVEL = 6; public Expression left; public ArrayList rights = new ArrayList(); public EVar negation; public EBinary(Expression left, EVar negation) { this.left = left; this.negation = negation; } private EBinary(Expression left, EVar operator, Expression right) { this.left = left; rights.add(new EBinaryRightSide(operator, right)); } public static EBinary create(Expression left, EVar operator, Expression right) { if(left instanceof EBinary) { EBinary left_ = (EBinary)left; left_.rights.add(new EBinaryRightSide(operator, right)); return left_; } else return new EBinary(left, operator, right); } @Override public Expression resolve(TranslationContext context) { return parseOperators(context).resolve(context); } public Expression parseOperators(TranslationContext context) { ArrayList output = new ArrayList(); ArrayList ops = new ArrayList(); ArrayList opAsts = new ArrayList(); EVar negation = this.negation; output.add(left); for(EBinaryRightSide right : rights) { // Read op Expression op = context.resolveVariable(right.operator.location, right.operator.name); if(op == null) return new EError(location); Precedence opPrec = op.getPrecedence(); while(!ops.isEmpty()) { Expression oldOp = ops.get(ops.size()-1); Precedence oldOpPrecedence = oldOp.getPrecedence(); if(oldOpPrecedence.level < opPrec.level) break; if(oldOpPrecedence.level == opPrec.level) { if(opPrec.associativity == Associativity.RIGHT) break; if(opPrec.associativity == Associativity.NONASSOC) { context.getErrorLog().log(right.operator.location, "Operator " + right.operator.name + " is not associative."); return new EError(location); } } // Pop op ops.remove(ops.size()-1); Expression r = output.remove(output.size()-1); Expression l = output.remove(output.size()-1); output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); } if(negation != null && ops.isEmpty()) { if(opPrec.level <= NEGATION_LEVEL) { SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); if(neg == null) { context.getErrorLog().log(location, "Couldn't resolve variable neg."); return new EError(location); } output.set(0, unary(neg, negation, output.get(0))); negation = null; } } ops.add(op); opAsts.add(right.operator); // Read value output.add(right.right); } // Pop rest while(!ops.isEmpty()) { Expression oldOp = ops.remove(ops.size()-1); Expression r = output.remove(output.size()-1); Expression l = output.remove(output.size()-1); output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); } if(negation != null) { SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); if(neg == null) { context.getErrorLog().log(location, "Couldn't resolve variable neg."); return new EError(location); } output.set(0, unary(neg, negation, output.get(0))); } return output.get(0); //System.out.println("parseOperators: " + this); //return parse(context, left, rights.listIterator(), new Precedence(-1, Associativity.NONASSOC)); } /* private Expression parse(TranslationContext context, Expression lhs, ListIterator it, Precedence minPrec) { while(it.hasNext()) { EBinaryRightSide right = it.next(); SCLValue op = context.resolveValue(right.operator.name); if(op == null) { context.getErrorLog().log(right.operator, "Couldn't resolve variable " + right.operator.name + "."); return lhs; } Precedence opPrec = op.getPrecedence(); if(minPrec.level > opPrec.level) break; Expression rhs = right.right; while(it.hasNext()) { EVar var = it.next().operator; SCLValue nextOp = context.resolveValue(var.name); if(nextOp == null) { context.getErrorLog().log(var, "Couldn't resolve variable " + var.name + "."); return lhs; } it.previous(); Precedence nextPrec = nextOp.getPrecedence(); int precDiff = opPrec.level - nextPrec.level; if(precDiff == 0) { if(opPrec.associativity == Associativity.LEFT) break; else if(opPrec.associativity == Associativity.NONASSOC) { context.getErrorLog().log(it.next().operator, "Nonassociative operator."); return lhs; } } else if(precDiff > 0) break; rhs = parse(context, rhs, it, nextPrec); } lhs = binary(lhs, op, right.operator, rhs); } return lhs; } */ private Expression binary(Expression lhs, Expression op, EVar opAst, Expression rhs) { return new EApply(Locations.combine(lhs.location, rhs.location), op, lhs, rhs); } private Expression unary(SCLValue operator, EVar opAst, Expression expression) { EConstant op = new EConstant(opAst.location, operator); return new EApply(expression.location /*wrong*/, op, expression); } @Override public EVar getPatternHead() throws NotPatternException { if(rights.size() == 1) return rights.get(0).operator; else throw new NotPatternException(this); } @Override public LhsType getLhsType() throws NotPatternException { if(rights.size() == 1) return new FunctionDefinitionLhs(rights.get(0).operator.name); else throw new InternalCompilerError(); } @Override public void getParameters(TranslationContext context, ArrayList parameters) { parseOperators(context).getParameters(context, parameters); } public static Expression negate(EVar op, Expression expression) { if(expression instanceof EBinary) { ((EBinary)expression).negation = op; return expression; } /*else if(expression instanceof EIntegerLiteral) { EIntegerLiteral literal = (EIntegerLiteral)expression; literal.value = -literal.value; return expression; }*/ else return new EBinary(expression, op); } @Override public int getFunctionDefinitionPatternArity() throws NotPatternException { return 2; } @Override public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) { location = loc; left.setLocationDeep(loc); if(negation != null) negation.setLocationDeep(loc); for(EBinaryRightSide right : rights) right.setLocationDeep(loc); } } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } }