CommonExpressionNode.java

package edu.udel.cis.vsl.abc.ast.node.common.expression;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import edu.udel.cis.vsl.abc.ast.IF.DifferenceObject;
import edu.udel.cis.vsl.abc.ast.conversion.IF.Conversion;
import edu.udel.cis.vsl.abc.ast.node.IF.ASTNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ConstantNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ConstantNode.ConstantKind;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.OperatorNode;
import edu.udel.cis.vsl.abc.ast.node.common.CommonASTNode;
import edu.udel.cis.vsl.abc.ast.type.IF.Type;
import edu.udel.cis.vsl.abc.ast.value.IF.Value;
import edu.udel.cis.vsl.abc.token.IF.Source;

public abstract class CommonExpressionNode extends CommonASTNode
		implements
			ExpressionNode {

	private Type initialType;

	/**
	 * Has the constant value for this expression been computed? (It may be
	 * null.) If it has, the constant value is cached in field constantValue.
	 */
	private boolean constantComputed = false;

	/**
	 * If this expression has a constant value, the value may be cached here.
	 */
	private Value constantValue = null;

	protected ArrayList<Conversion> conversions = new ArrayList<Conversion>();

	public CommonExpressionNode(Source source,
			List<? extends ASTNode> arguments) {
		super(source, arguments.iterator());
	}

	public CommonExpressionNode(Source source) {
		super(source);
	}

	public CommonExpressionNode(Source source, ASTNode argument) {
		super(source, argument);
	}

	public CommonExpressionNode(Source source, ASTNode argument0,
			ASTNode argument1) {
		super(source, argument0, argument1);
	}

	public CommonExpressionNode(Source source, ASTNode argument0,
			ASTNode argument1, ASTNode argument2) {
		super(source, argument0, argument1, argument2);
	}

	public CommonExpressionNode(Source source, ASTNode argument0,
			ASTNode argument1, ASTNode argument2, ASTNode argument3) {
		super(source, argument0, argument1, argument2, argument3);
	}

	@Override
	public int getNumConversions() {
		return conversions.size();
	}

	@Override
	public Conversion getConversion(int index) {
		return conversions.get(index);
	}

	@Override
	public Type getInitialType() {
		return initialType;
	}

	@Override
	public void setInitialType(Type type) {
		this.initialType = type;
	}

	@Override
	public Type getConvertedType() {
		if (conversions.size() > 0)
			return conversions.get(conversions.size() - 1).getNewType();
		else
			return initialType;
	}

	public boolean constantComputed() {
		return constantComputed;
	}

	public Value getConstantValue() {
		return constantValue;
	}

	public void setConstantValue(Value value) {
		this.constantValue = value;
		this.constantComputed = true;
	}

	protected void printExtras(String prefix, PrintStream out) {
		int numConversions = getNumConversions();
		String typeDescriptor = (initialType == null
				? "UNKNOWN"
				: "" + initialType.toString());

		out.println();
		out.print(prefix + "initial type: " + typeDescriptor);
		if (numConversions > 0) {
			out.println();
			out.print(prefix + "conversions");
			for (int i = 0; i < numConversions; i++) {
				out.println();
				out.print(prefix + "| " + getConversion(i));
			}
		}
		if (constantValue != null) {
			out.println();
			out.print(prefix + "constant value: " + constantValue);
		}
	}

	@Override
	public Type getType() {
		return getConvertedType();
	}

	@Override
	public void addConversion(Conversion conversion) {
		Type lastType = getConvertedType();

		if (lastType == null)
			throw new RuntimeException(
					"Internal error: adding conversion before initial type defined");
		if (!lastType.equals(conversion.getOldType()))
			throw new IllegalArgumentException(
					"Old type of conversion is not last type:\n"
							+ conversion.getOldType() + "\n" + lastType);
		conversions.add(conversion);
	}

	@Override
	public void removeConversions() {
		conversions = new ArrayList<Conversion>();
	}

	@Override
	public NodeKind nodeKind() {
		return NodeKind.EXPRESSION;
	}

	@Override
	protected DifferenceObject diffWork(ASTNode that) {
		if (that instanceof ExpressionNode)
			if (this.expressionKind() == ((ExpressionNode) that)
					.expressionKind())
				return null;
		return new DifferenceObject(this, that);
	}

	@Override
	public boolean isLvalue() {
		ExpressionKind kind = expressionKind();

		switch (kind) {
			case CONSTANT :
				if (((ConstantNode) this).constantKind() == ConstantKind.STRING)
					return true;
				else
					return false;
			case COMPOUND_LITERAL :
			case ARROW :
			case DOT :
			case IDENTIFIER_EXPRESSION :
				return true;
			case OPERATOR : {
				OperatorNode operatorNode = (OperatorNode) this;

				switch (operatorNode.getOperator()) {
					case DEREFERENCE :
					case SUBSCRIPT :
						return true;
					default :
				}
			}
			default :
				return false;
		}
	}
}