package polyglot.ext.jl.ast;
import polyglot.ast.*;
import polyglot.types.*;
import polyglot.visit.*;
import polyglot.util.*;
import java.util.*;
/**
* A <code>Unary</code> represents a Java unary expression, an
* immutable pair of an expression and an operator.
*/
public class Unary_c extends Expr_c implements Unary
{
protected Unary.Operator op;
protected Expr expr;
public Unary_c(Position pos, Unary.Operator op, Expr expr) {
super(pos);
this.op = op;
this.expr = expr;
}
/** Get the precedence of the expression. */
public Precedence precedence() {
return Precedence.UNARY;
}
/** Get the sub-expression of the expression. */
public Expr expr() {
return this.expr;
}
/** Set the sub-expression of the expression. */
public Unary expr(Expr expr) { Unary_c n = (Unary_c) copy(); n.expr = expr;
return n; }
/** Get the operator. */
public Unary.Operator operator() {
return this.op;
}
/** Set the operator. */
public Unary operator(Unary.Operator op) {
Unary_c n = (Unary_c) copy();
n.op = op;
return n;
}
/** Reconstruct the expression. */
protected Unary_c reconstruct(Expr expr) {
if (expr != this.expr) {
Unary_c n = (Unary_c) copy();
n.expr = expr;
return n;
}
return this;
}
/** Visit the children of the expression. */
public Node visitChildren(NodeVisitor v) {
Expr expr = (Expr) visitChild(this.expr, v);
return reconstruct(expr);
}
/** Type check the expression. */
public Node typeCheck(TypeChecker tc) throws SemanticException {
TypeSystem ts = tc.typeSystem();
if (op == POST_INC || op == POST_DEC ||
op == PRE_INC || op == PRE_DEC) {
if (! expr.type().isNumeric()) {
throw new SemanticException("Operand of " + op +
" operator must be numeric.", expr.position());
}
if (! (expr instanceof Variable)) {
throw new SemanticException("Operand of " + op +
" operator must be a variable.", expr.position());
}
if (((Variable) expr).flags().isFinal()) {
throw new SemanticException("Operand of " + op +
" operator must be a non-final variable.",
expr.position());
}
return type(expr.type());
}
if (op == BIT_NOT) {
if (! ts.isImplicitCastValid(expr.type(), ts.Long())) {
throw new SemanticException("Operand of " + op +
" operator must be numeric.", expr.position());
}
return type(ts.promote(expr.type()));
}
if (op == NEG || op == POS) {
if (! expr.type().isNumeric()) {
throw new SemanticException("Operand of " + op +
" operator must be numeric.", expr.position());
}
return type(ts.promote(expr.type()));
}
if (op == NOT) {
if (! expr.type().isBoolean()) {
throw new SemanticException("Operand of " + op +
" operator must be boolean.", expr.position());
}
return type(expr.type());
}
return this;
}
public Type childExpectedType(Expr child, AscriptionVisitor av) {
TypeSystem ts = av.typeSystem();
try {
if (child == expr) {
if (op == POST_INC || op == POST_DEC ||
op == PRE_INC || op == PRE_DEC) {
if (ts.isImplicitCastValid(child.type(), av.toType())) {
return ts.promote(child.type());
}
else {
return av.toType();
}
}
else if (op == NEG || op == POS) {
if (ts.isImplicitCastValid(child.type(), av.toType())) {
return ts.promote(child.type());
}
else {
return av.toType();
}
}
else if (op == BIT_NOT) {
if (ts.isImplicitCastValid(child.type(), av.toType())) {
return ts.promote(child.type());
}
else {
return av.toType();
}
}
else if (op == NOT) {
return ts.Boolean();
}
}
}
catch (SemanticException e) {
}
return child.type();
}
/** Check exceptions thrown by the statement. */
public String toString() {
if (op == NEG && expr instanceof IntLit && ((IntLit) expr).boundary()) {
return op.toString() + ((IntLit) expr).positiveToString();
}
else if (op.isPrefix()) {
return op.toString() + expr.toString();
}
else {
return expr.toString() + op.toString();
}
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
if (op == NEG && expr instanceof IntLit && ((IntLit) expr).boundary()) {
w.write(op.toString());
w.write(((IntLit) expr).positiveToString());
}
else if (op.isPrefix()) {
w.write(op.toString());
printSubExpr(expr, false, w, tr);
}
else {
printSubExpr(expr, false, w, tr);
w.write(op.toString());
}
}
public Term entry() {
return expr.entry();
}
public List acceptCFG(CFGBuilder v, List succs) {
if (expr.type().isBoolean()) {
v.visitCFG(expr, FlowGraph.EDGE_KEY_TRUE, this,
FlowGraph.EDGE_KEY_FALSE, this);
}
else {
v.visitCFG(expr, this);
}
return succs;
}
public boolean isConstant() {
return expr.isConstant();
}
public Object constantValue() {
if (! isConstant()) {
return null;
}
Object v = expr.constantValue();
if (v instanceof Boolean) {
boolean vv = ((Boolean) v).booleanValue();
if (op == NOT) return Boolean.valueOf(!vv);
}
if (v instanceof Double) {
double vv = ((Double) v).doubleValue();
if (op == POS) return new Double(+vv);
if (op == NEG) return new Double(-vv);
}
if (v instanceof Float) {
float vv = ((Float) v).floatValue();
if (op == POS) return new Float(+vv);
if (op == NEG) return new Float(-vv);
}
if (v instanceof Long) {
long vv = ((Long) v).longValue();
if (op == BIT_NOT) return new Long(~vv);
if (op == POS) return new Long(+vv);
if (op == NEG) return new Long(-vv);
}
if (v instanceof Integer) {
int vv = ((Integer) v).intValue();
if (op == BIT_NOT) return new Integer(~vv);
if (op == POS) return new Integer(+vv);
if (op == NEG) return new Integer(-vv);
}
if (v instanceof Character) {
char vv = ((Character) v).charValue();
if (op == BIT_NOT) return new Integer(~vv);
if (op == POS) return new Integer(+vv);
if (op == NEG) return new Integer(-vv);
}
if (v instanceof Short) {
short vv = ((Short) v).shortValue();
if (op == BIT_NOT) return new Integer(~vv);
if (op == POS) return new Integer(+vv);
if (op == NEG) return new Integer(-vv);
}
if (v instanceof Byte) {
byte vv = ((Byte) v).byteValue();
if (op == BIT_NOT) return new Integer(~vv);
if (op == POS) return new Integer(+vv);
if (op == NEG) return new Integer(-vv);
}
// not a constant
return null;
}
}