CommonAST.java

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

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import edu.udel.cis.vsl.abc.ast.IF.AST;
import edu.udel.cis.vsl.abc.ast.IF.ASTException;
import edu.udel.cis.vsl.abc.ast.IF.ASTFactory;
import edu.udel.cis.vsl.abc.ast.IF.DifferenceObject;
import edu.udel.cis.vsl.abc.ast.entity.IF.Function;
import edu.udel.cis.vsl.abc.ast.entity.IF.OrdinaryEntity;
import edu.udel.cis.vsl.abc.ast.entity.IF.ProgramEntity;
import edu.udel.cis.vsl.abc.ast.node.IF.ASTNode;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.BlockItemNode;
import edu.udel.cis.vsl.abc.token.IF.SourceFile;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;

/**
 * Standard implementation of the {@link AST} interface.
 * 
 * @author siegel
 * 
 */
public class CommonAST implements AST {

	private ASTFactory astFactory;

	private SequenceNode<BlockItemNode> root;

	private int nodeCount;

	private ASTNode[] nodes;

	private Map<String, OrdinaryEntity> internalOrExternalEntityMap;

	private ArrayList<OrdinaryEntity> internalEntities;

	private ArrayList<OrdinaryEntity> externalEntities;

	private Collection<SourceFile> sourceFiles;

	private Function mainFunction = null;

	private boolean isWholeprogram = false;

	public CommonAST(ASTFactory astFactory, SequenceNode<BlockItemNode> root,
			boolean hasOmpPragma, Collection<SourceFile> sourceFiles)
			throws SyntaxException {
		this(astFactory, root, hasOmpPragma, sourceFiles, false);
	}

	public CommonAST(ASTFactory astFactory, SequenceNode<BlockItemNode> root,
			boolean hasOmpPragma, Collection<SourceFile> sourceFiles,
			boolean isWholeprogram) throws SyntaxException {
		this.root = root;
		this.astFactory = astFactory;
		this.sourceFiles = sourceFiles;
		this.isWholeprogram = isWholeprogram;
		clearEntities();
		initialize();
	}

	@Override
	public void clearEntities() {
		internalOrExternalEntityMap = new LinkedHashMap<String, OrdinaryEntity>();
		internalEntities = new ArrayList<OrdinaryEntity>();
		externalEntities = new ArrayList<OrdinaryEntity>();
	}

	@Override
	public ASTFactory getASTFactory() {
		return astFactory;
	}

	@Override
	public SequenceNode<BlockItemNode> getRootNode() {
		return root;
	}

	@Override
	public int getNumberOfNodes() {
		return nodeCount;
	}

	@Override
	public ASTNode getNode(int id) {
		return nodes[id];
	}

	@Override
	public void setMain(Function f) {
		mainFunction = f;
	}

	@Override
	public Function getMain() {
		return mainFunction;
	}

	@Override
	public void print(PrintStream out) {
		print("", out, root, true);
	}

	private void print(String prefix, PrintStream out, ASTNode node,
			boolean includeSource) {
		if (node == null) {
			out.println(prefix + "<absent>");
		} else {
			Iterable<ASTNode> children = node.children();
			int childCount = 0;

			node.print(prefix, out, includeSource);
			out.println();
			prefix += "| ";
			// out.println(prefix + node.getScope());
			for (ASTNode child : children) {
				if (child == null)
					out.println(prefix + childCount + " <absent>");
				else
					print(prefix, out, child, includeSource);
				childCount++;
			}
		}
	}

	@Override
	public void release() {
		nullifyOwners(root);
		externalEntities = null;
		internalEntities = null;
		internalOrExternalEntityMap = null;
		nodeCount = 0;
		nodes = null;
		root = null;
		astFactory = null;
	}

	private void nullifyOwners(ASTNode node) {
		if (node == null)
			return;
		else {
			Iterable<ASTNode> children = node.children();

			node.setOwner(null);
			node.setId(-1);
			for (ASTNode child : children)
				nullifyOwners(child);
		}
	}

	// supporting methods...

	private void initialize() throws SyntaxException {
		this.nodeCount = 0;
		setIDsAndOwner(root);
		this.nodes = new ASTNode[nodeCount];
		initializeNodeArray(root);
		// ScopeAnalyzer.setScopes(this);
	}

	private void setIDsAndOwner(ASTNode node) {
		Iterable<ASTNode> children;

		if (node == null)
			return;
		if (node.getOwner() != null) {
			throw new ASTException(
					"Node cannot be added to new AST until old AST is released:\n"
							+ node);
		}
		node.setId(nodeCount);
		node.setOwner(this);
		nodeCount++;
		children = node.children();
		for (ASTNode child : children) {
			setIDsAndOwner(child);
		}
	}

	private void initializeNodeArray(ASTNode node) {
		Iterable<ASTNode> children;

		if (node == null)
			return;
		this.nodes[node.id()] = node;
		children = node.children();
		for (ASTNode child : children) {
			initializeNodeArray(child);
		}
	}

	@Override
	public void add(OrdinaryEntity entity) {
		ProgramEntity.LinkageKind linkage = entity.getLinkage();

		if (linkage == ProgramEntity.LinkageKind.EXTERNAL)
			externalEntities.add(entity);
		else if (linkage == ProgramEntity.LinkageKind.INTERNAL)
			internalEntities.add(entity);
		else
			throw new IllegalArgumentException(
					"Can only add entities with internal or external linkage to translation unit: "
							+ entity);
		internalOrExternalEntityMap.put(entity.getName(), entity);
	}

	@Override
	public OrdinaryEntity getInternalOrExternalEntity(String name) {
		return internalOrExternalEntityMap.get(name);
	}

	@Override
	public Iterator<OrdinaryEntity> getInternalEntities() {
		return internalEntities.iterator();
	}

	@Override
	public Iterator<OrdinaryEntity> getExternalEntities() {
		return externalEntities.iterator();
	}

	@Override
	public void prettyPrint(PrintStream out, boolean ignoreStdLibs) {
		ASTPrettyPrinter.prettyPrint(this, out, ignoreStdLibs);
	}

	@Override
	public boolean equiv(AST that) {
		return diff(that) == null;
	}

	@Override
	public DifferenceObject diff(AST that) {
		return this.getRootNode().diff(that.getRootNode());
	}

	@Override
	public Collection<SourceFile> getSourceFiles() {
		return sourceFiles;
	}

	@Override
	public String toString() {
		String result = "AST[";
		boolean first = true;

		for (SourceFile sourceFile : sourceFiles) {
			if (first)
				first = false;
			else
				result += ",";
			result += sourceFile.getName();
		}
		result += "]";
		return result;
	}

	@Override
	public boolean isWholeProgram() {
		return this.isWholeprogram;
	}
}