CommonVariableDeclarationNode.java

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

import java.io.PrintStream;

import edu.udel.cis.vsl.abc.ast.IF.ASTException;
import edu.udel.cis.vsl.abc.ast.IF.DifferenceObject;
import edu.udel.cis.vsl.abc.ast.IF.DifferenceObject.DiffKind;
import edu.udel.cis.vsl.abc.ast.entity.IF.Variable;
import edu.udel.cis.vsl.abc.ast.node.IF.ASTNode;
import edu.udel.cis.vsl.abc.ast.node.IF.IdentifierNode;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.InitializerNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypeNode;
import edu.udel.cis.vsl.abc.token.IF.Source;

// child 0: identifier
// child 1: type
// child 2: initializer or null or absent
// child 3: constant alignment specifiers or null or absent
// child 4: type alignment specifiers or null or absent

public class CommonVariableDeclarationNode extends CommonOrdinaryDeclarationNode
		implements
			VariableDeclarationNode {

	private boolean autoStorage = false;

	private boolean registerStorage = false;

	private boolean threadLocalStorage = false;

	private boolean sharedStorage = false;

	private boolean isRefParameter = true;

	public CommonVariableDeclarationNode(Source source,
			IdentifierNode identifier, TypeNode type) {
		super(source, identifier, type);
	}

	/**
	 * Constructor for declarator-based declarations that are not function
	 * definitions (including function prototypes).
	 * 
	 * @param source
	 * @param identifier
	 * @param type
	 * @param initializer
	 */
	public CommonVariableDeclarationNode(Source source,
			IdentifierNode identifier, TypeNode type,
			InitializerNode initializer) {
		super(source, identifier, type);
		addChild(initializer);
	}

	@Override
	public Variable getEntity() {
		return (Variable) super.getEntity();
	}

	@Override
	public boolean hasAutoStorage() {
		return autoStorage;
	}

	@Override
	public void setAutoStorage(boolean value) {
		autoStorage = value;
	}

	@Override
	public boolean hasRegisterStorage() {
		return registerStorage;
	}

	@Override
	public void setRegisterStorage(boolean value) {
		registerStorage = value;
	}

	@Override
	public InitializerNode getInitializer() {
		if (this.numChildren() >= 3)
			return (InitializerNode) child(2);
		else
			return null;
	}

	@Override
	public void setInitializer(InitializerNode initializer) {
		setChild(2, initializer);
	}

	@Override
	public boolean hasThreadLocalStorage() {
		return threadLocalStorage;
	}

	@Override
	public void setThreadLocalStorage(boolean value) {
		threadLocalStorage = value;
	}

	@Override
	public boolean hasSharedStorage() {
		return sharedStorage;
	}

	@Override
	public void setSharedStorage(boolean value) {
		sharedStorage = value;
	}

	@SuppressWarnings("unchecked")
	@Override
	public SequenceNode<TypeNode> typeAlignmentSpecifiers() {
		if (numChildren() >= 5)
			return (SequenceNode<TypeNode>) child(4);
		else
			return null;
	}

	@Override
	public void setTypeAlignmentSpecifiers(SequenceNode<TypeNode> specifiers) {
		setChild(4, specifiers);
	}

	@SuppressWarnings("unchecked")
	@Override
	public SequenceNode<ExpressionNode> constantAlignmentSpecifiers() {
		if (numChildren() >= 4) {
			ASTNode result = child(3);

			return (SequenceNode<ExpressionNode>) result;
		} else {
			return null;
		}
	}

	@Override
	public void setConstantAlignmentSpecifiers(
			SequenceNode<ExpressionNode> specifiers) {
		setChild(3, specifiers);
	}

	protected void printKind(PrintStream out) {
		out.print("ObjectDeclaration");
	}

	@Override
	protected void printBody(PrintStream out) {
		boolean needSeparator = false;

		printKind(out);
		if (hasExternStorage()) {
			out.print("[");
			out.print("extern");
			needSeparator = true;
		}
		if (hasStaticStorage()) {
			out.print(needSeparator ? ", " : "[");
			out.print("static");
			needSeparator = true;
		}
		if (autoStorage) {
			out.print(needSeparator ? ", " : "[");
			out.print("auto");
			needSeparator = true;
		}
		if (registerStorage) {
			out.print(needSeparator ? ", " : "[");
			out.print("register");
			needSeparator = true;
		}
		if (threadLocalStorage) {
			out.print(needSeparator ? ", " : "[");
			out.print("threadLocal");
			needSeparator = true;
		}
		if (needSeparator)
			out.print("]");
	}

	@Override
	public VariableDeclarationNode copy() {
		InitializerNode initializer = getInitializer();
		CommonVariableDeclarationNode result;

		if (initializer == null)
			result = new CommonVariableDeclarationNode(getSource(),
					duplicate(getIdentifier()), duplicate(getTypeNode()));
		else
			result = new CommonVariableDeclarationNode(getSource(),
					duplicate(getIdentifier()), duplicate(getTypeNode()),
					duplicate(initializer));
		copyStorage(result);
		result.setAutoStorage(hasAutoStorage());
		result.setRegisterStorage(hasRegisterStorage());
		result.setThreadLocalStorage(hasThreadLocalStorage());
		result.setSharedStorage(hasSharedStorage());
		result.setConstantAlignmentSpecifiers(
				duplicate(constantAlignmentSpecifiers()));
		result.setTypeAlignmentSpecifiers(duplicate(typeAlignmentSpecifiers()));
		return result;
	}

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

	@Override
	public OrdinaryDeclarationKind ordinaryDeclarationKind() {
		return OrdinaryDeclarationKind.VARIABLE_DECLARATION;
	}

	@Override
	protected DifferenceObject diffWork(ASTNode that) {
		if (that instanceof VariableDeclarationNode) {
			VariableDeclarationNode thatVar = (VariableDeclarationNode) that;

			if (!(this.autoStorage == thatVar.hasAutoStorage()
					&& this.registerStorage == thatVar.hasRegisterStorage()
					&& this.threadLocalStorage == thatVar
							.hasThreadLocalStorage()))
				return new DifferenceObject(this, that, DiffKind.OTHER,
						"different variable declaration auto/register/thread-local specifier");
			else
				return null;
		}
		return new DifferenceObject(this, that);
	}

	@Override
	public boolean isRefParameter() {
		return isRefParameter;
	}

	@Override
	public void setIsRefParameter(boolean isRefParameter) {
		this.isRefParameter = isRefParameter;
	}

	@Override
	public ASTNode setChild(int index, ASTNode child) {
		if (index >= 5)
			throw new ASTException(
					"CommonVariableDeclarationNode has three children, but saw index "
							+ index);
		if (index == 2 && !(child == null || child instanceof InitializerNode))
			throw new ASTException(
					"Child of CommonVariableDeclarationNode at index " + index
							+ " must be an InitializerNode, but saw " + child
							+ " with type " + child.nodeKind());
		return super.setChild(index, child);
	}
}