ASTBinaryExpression.java

package edu.udel.cis.vsl.tass.front.minimp.ast.expression;

import java.util.HashMap;
import java.util.Map;

import edu.udel.cis.vsl.tass.front.minimp.ast.type.ASTBoolType;
import edu.udel.cis.vsl.tass.front.minimp.ast.type.ASTIntegerType;
import edu.udel.cis.vsl.tass.front.minimp.ast.type.ASTPointerType;
import edu.udel.cis.vsl.tass.front.minimp.ast.type.ASTRealType;
import edu.udel.cis.vsl.tass.front.minimp.ast.type.ASTTypeIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;

public class ASTBinaryExpression extends ASTExpression {
	public static enum BinaryOperator {
		PLUS, SUB, MUL, DIV, MOD, OR, AND, EQ, NEQ, LT, LTE, GT, GTE;
		private static Map<String, BinaryOperator> STRING_TO_OPERATOR_MAP;

		static {
			STRING_TO_OPERATOR_MAP = new HashMap<String, BinaryOperator>();
			STRING_TO_OPERATOR_MAP.put("add", BinaryOperator.PLUS);
			STRING_TO_OPERATOR_MAP.put("and", BinaryOperator.AND);
			STRING_TO_OPERATOR_MAP.put("divide", BinaryOperator.DIV);
			STRING_TO_OPERATOR_MAP.put("equals", BinaryOperator.EQ);
			STRING_TO_OPERATOR_MAP.put("leq", BinaryOperator.LTE);
			STRING_TO_OPERATOR_MAP.put("less_than", BinaryOperator.LT);
			STRING_TO_OPERATOR_MAP.put("modulo", BinaryOperator.MOD);
			STRING_TO_OPERATOR_MAP.put("or", BinaryOperator.OR);
			STRING_TO_OPERATOR_MAP.put("multiply", BinaryOperator.MUL);
			STRING_TO_OPERATOR_MAP.put("subtract", BinaryOperator.SUB);

			STRING_TO_OPERATOR_MAP.put("+=", BinaryOperator.PLUS);
			STRING_TO_OPERATOR_MAP.put("-=", BinaryOperator.SUB);
			STRING_TO_OPERATOR_MAP.put("*=", BinaryOperator.MUL);
			STRING_TO_OPERATOR_MAP.put("/=", BinaryOperator.DIV);
			STRING_TO_OPERATOR_MAP.put("%=", BinaryOperator.MOD);
			STRING_TO_OPERATOR_MAP.put("&=", BinaryOperator.AND);
			STRING_TO_OPERATOR_MAP.put("|=", BinaryOperator.OR);
		}

		public static BinaryOperator stringToOperator(String anOperator) {
			return STRING_TO_OPERATOR_MAP.get(anOperator);
		}
	};

	private BinaryOperator exprOperator;
	private ASTExpressionIF left;
	private ASTExpressionIF right;

	private boolean isPointerOp = false;

	public ASTBinaryExpression(BinaryOperator op, ASTExpressionIF lhs,
			ASTExpressionIF rhs) throws SyntaxException {
		super(null);
		exprOperator = op;
		left = lhs;
		right = rhs;
		switch (op) {
		case PLUS:
			exprType = checkAdditiveType(lhs, lhs.getType(), rhs.getType());
			break;
		case SUB:
		case MUL:
		case DIV:
		case MOD:
			exprType = mixType(lhs.getType(), rhs.getType());
			break;
		default:
			exprType = new ASTBoolType();
		}

	}

	private ASTTypeIF mixType(ASTTypeIF left, ASTTypeIF right) {
		if (left instanceof ASTRealType || right instanceof ASTRealType) {
			return new ASTRealType();
		} else if (left != null) {
			return left;
		} else {
			return right;
		}
	}

	private ASTTypeIF checkAdditiveType(ASTExpressionIF lhs, ASTTypeIF left,
			ASTTypeIF right) throws SyntaxException {
		if (left instanceof ASTPointerType) {
			if (right instanceof ASTIntegerType) {
				this.isPointerOp = true;
				return left;
			} else {
				throw new SyntaxException(lhs, "Type inconsistency: " + left
						+ " and " + right);
			}
		} else if (right instanceof ASTPointerType) {
			if (left instanceof ASTIntegerType) {
				this.isPointerOp = true;
				return left;
			} else {
				throw new SyntaxException(lhs, "Type inconsistency: " + left
						+ " and " + right);
			}
		} else {
			return this.mixType(left, right);
		}
	}

	public BinaryOperator getOperator() {
		return exprOperator;
	}

	public ASTExpressionIF getLeft() {
		return left;
	}

	public ASTExpressionIF getRight() {
		return right;
	}

	public boolean isPointerOp() {
		return this.isPointerOp;
	}

	public String toString() {
		String op = new String();
		switch (this.exprOperator) {
		case PLUS:
			op = "+";
			break;
		case SUB:
			op = "-";
			break;
		case MUL:
			op = "*";
			break;
		case DIV:
			op = "/";
			break;
		case MOD:
			op = "%";
			break;
		case OR:
			op = "||";
			break;
		case AND:
			op = "&&";
			break;
		case EQ:
			op = "==";
			break;
		case NEQ:
			op = "!=";
			break;
		case LT:
			op = "<";
			break;
		case LTE:
			op = "<=";
			break;
		case GT:
			op = ">";
			break;
		case GTE:
			op = ">=";
			break;
		default:
			op = "?????? UNKNOWN BINARY OPERATOR ??????";
		}
		return this.left.toString() + op + this.right.toString();
	}
}