package polyglot.ext.jl.ast; import polyglot.ast.*; import polyglot.types.*; import polyglot.visit.*; import polyglot.util.*; import java.util.*; /** * An <code>Assign</code> represents a Java assignment expression. */ public abstract class Assign_c extends Expr_c implements Assign { protected Expr left; protected Operator op; protected Expr right; public Assign_c(Position pos, Expr left, Operator op, Expr right) { super(pos); this.left = left; this.op = op; this.right = right; } /** Get the precedence of the expression. */ public Precedence precedence() { return Precedence.ASSIGN; } /** Get the left operand of the expression. */ public Expr left() { return this.left; } /** Set the left operand of the expression. */ public Assign left(Expr left) { Assign_c n = (Assign_c) copy(); n.left = left; return n; } /** Get the operator of the expression. */ public Operator operator() { return this.op; } /** Set the operator of the expression. */ public Assign operator(Operator op) { Assign_c n = (Assign_c) copy(); n.op = op; return n; } /** Get the right operand of the expression. */ public Expr right() { return this.right; } /** Set the right operand of the expression. */ public Assign right(Expr right) { Assign_c n = (Assign_c) copy(); n.right = right; return n; } /** Reconstruct the expression. */ protected Assign_c reconstruct(Expr left, Expr right) { if (left != this.left || right != this.right) { Assign_c n = (Assign_c) copy(); n.left = left; n.right = right; return n; } return this; } /** Visit the children of the expression. */ public Node visitChildren(NodeVisitor v) { Expr left = (Expr) visitChild(this.left, v); Expr right = (Expr) visitChild(this.right, v); return reconstruct(left, right); } /** Type check the expression. */ public Node typeCheck(TypeChecker tc) throws SemanticException { Type t = left.type(); Type s = right.type(); TypeSystem ts = tc.typeSystem(); if (! (left instanceof Variable)) { throw new SemanticException("Target of assignment must be a variable.", position()); } if (op == ASSIGN) { if (! ts.isImplicitCastValid(s, t) && ! ts.equals(s, t) && ! ts.numericConversionValid(t, right.constantValue())) { throw new SemanticException("Cannot assign " + s + " to " + t + ".", position()); } return type(t); } if (op == ADD_ASSIGN) { // t += s if (ts.equals(t, ts.String()) && ts.canCoerceToString(s, tc.context())) { return type(ts.String()); } if (t.isNumeric() && s.isNumeric()) { return type(ts.promote(t, s)); } throw new SemanticException("The " + op + " operator must have " + "numeric or String operands.", position()); } if (op == SUB_ASSIGN || op == MUL_ASSIGN || op == DIV_ASSIGN || op == MOD_ASSIGN) { if (t.isNumeric() && s.isNumeric()) { return type(ts.promote(t, s)); } throw new SemanticException("The " + op + " operator must have " + "numeric operands.", position()); } if (op == BIT_AND_ASSIGN || op == BIT_OR_ASSIGN || op == BIT_XOR_ASSIGN) { if (t.isBoolean() && s.isBoolean()) { return type(ts.Boolean()); } if (ts.isImplicitCastValid(t, ts.Long()) && ts.isImplicitCastValid(s, ts.Long())) { return type(ts.promote(t, s)); } throw new SemanticException("The " + op + " operator must have " + "integral or boolean operands.", position()); } if (op == SHL_ASSIGN || op == SHR_ASSIGN || op == USHR_ASSIGN) { if (ts.isImplicitCastValid(t, ts.Long()) && ts.isImplicitCastValid(s, ts.Long())) { // Only promote the left of a shift. return type(ts.promote(t)); } throw new SemanticException("The " + op + " operator must have " + "integral operands.", position()); } throw new InternalCompilerError("Unrecognized assignment operator " + op + "."); } public Type childExpectedType(Expr child, AscriptionVisitor av) { if (child == right) { TypeSystem ts = av.typeSystem(); // If the RHS is an integral constant, we can relax the expected // type to the type of the constant. if (ts.numericConversionValid(left.type(), child.constantValue())) { return child.type(); } else { return left.type(); } } return child.type(); } /** Get the throwsArithmeticException of the expression. */ public boolean throwsArithmeticException() { // conservatively assume that any division or mod may throw // ArithmeticException this is NOT true-- floats and doubles don't // throw any exceptions ever... return op == DIV_ASSIGN || op == MOD_ASSIGN; } public String toString() { return left + " " + op + " " + right; } /** Write the expression to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { printSubExpr(left, true, w, tr); w.write(" "); w.write(op.toString()); w.allowBreak(2, " "); printSubExpr(right, false, w, tr); } /** Dumps the AST. */ public void dump(CodeWriter w) { super.dump(w); w.allowBreak(4, " "); w.begin(0); w.write("(operator " + op + ")"); w.end(); } abstract public Term entry(); public List acceptCFG(CFGBuilder v, List succs) { if (operator() == ASSIGN) { acceptCFGAssign(v); } else { acceptCFGOpAssign(v); } return succs; } /** * ###@@@DOCO TODO */ protected abstract void acceptCFGAssign(CFGBuilder v); /** * ###@@@DOCO TODO */ protected abstract void acceptCFGOpAssign(CFGBuilder v); public List throwTypes(TypeSystem ts) { List l = new LinkedList(); if (throwsArithmeticException()) { l.add(ts.ArithmeticException()); } return l; } }