Location.java

package edu.udel.cis.vsl.tass.model.impl.location;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;

import edu.udel.cis.vsl.tass.model.IF.CollectiveAssertionIF;
import edu.udel.cis.vsl.tass.model.IF.FunctionIF;
import edu.udel.cis.vsl.tass.model.IF.ModelIF;
import edu.udel.cis.vsl.tass.model.IF.ProcessIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.expression.ExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.location.BranchLocationIF;
import edu.udel.cis.vsl.tass.model.IF.location.LocationIF;
import edu.udel.cis.vsl.tass.model.IF.location.LoopLocationIF;
import edu.udel.cis.vsl.tass.model.IF.scope.LocalScopeIF;
import edu.udel.cis.vsl.tass.model.IF.statement.StatementIF;
import edu.udel.cis.vsl.tass.model.impl.statement.Statement;
import edu.udel.cis.vsl.tass.util.Source;

/**
 * Implementation of LocationIF, the root of the location hierarchy. A location
 * represents a control point within a function body.
 * 
 * @author siegel
 */

public abstract class Location implements LocationIF {

	/**
	 * The unique ID number for this location. It is only unique within the
	 * enclosing process. Another process may have a location with the same id
	 * as this one.
	 */
	protected int id;

	protected FunctionIF function;

	protected LocalScopeIF scope;

	protected LocationKind kind;

	protected StatementIF firstStatement = null;

	protected StatementIF lastStatement = null;

	protected LinkedHashSet<StatementIF> incoming = new LinkedHashSet<StatementIF>();

	protected LinkedHashSet<StatementIF> outgoing = new LinkedHashSet<StatementIF>();

	protected Source sourceCode;

	protected Map<String, Object> annotationMap = new LinkedHashMap<String, Object>();

	protected boolean isLocal = false;

	protected LocationIF correspondingLocation = null;

	protected CollectiveAssertionIF collectiveAssertion = null;

	protected ExpressionIF collectiveExpression = null;

	private LocationIF openLocation = null;

	/**
	 * Locations can have labels. The label is used to help print and
	 * understand. May be null.
	 */
	protected String label = null;

	protected Location(LocalScopeIF scope, LocationKind kind) {
		assert scope != null;
		this.scope = scope;
		this.function = scope.function();
		this.id = function.locations().size();
		this.kind = kind;
	}

	@Override
	public FunctionIF function() {
		return function;
	}

	@Override
	public int id() {
		return id;
	}

	@Override
	public StatementIF firstStatement() {
		return firstStatement;
	}

	@Override
	public StatementIF lastStatement() {
		return lastStatement;
	}

	@Override
	public String label() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	@Override
	public boolean equals(Object object) {
		if (object instanceof Location) {
			Location that = (Location) object;

			return id == that.id && function.equals(that.function);
		}
		return false;
	}

	@Override
	public int hashCode() {
		return id + 1024 * function.hashCode();
	}

	@Override
	public String toString() {
		String result = "loc[" + id;

		if (label != null)
			result += "," + label;
		result += "]";
		return result;
	}

	public void addIncoming(StatementIF statement) {
		if (!incoming.add(statement)) {
			throw new IllegalArgumentException(
					"Attempt to add incoming statement that already exists: "
							+ statement);
		}
	}

	public void addOutgoing(StatementIF statement) {
		if (!outgoing.add(statement)) {
			throw new IllegalArgumentException(
					"Attempt to add outgoing statement that already exists: "
							+ statement);
		}
		if (firstStatement == null)
			firstStatement = statement;
		if (lastStatement != null)
			((Statement) lastStatement).setNext(statement);
		lastStatement = statement;
	}

	@Override
	public Collection<StatementIF> incomingStatements() {
		return incoming;
	}

	@Override
	public LocationKind kind() {
		return kind;
	}

	@Override
	public Collection<StatementIF> statements() {
		return outgoing;
	}

	@Override
	public Source getSource() {
		return sourceCode;
	}

	@Override
	public void setSource(Source sourceCode) {
		this.sourceCode = sourceCode;
	}

	@Override
	public boolean isBranch() {
		return this instanceof BranchLocationIF;
	}

	@Override
	public boolean isLoop() {
		return this instanceof LoopLocationIF;
	}

	@Override
	public Collection<String> annotationKeys() {
		return annotationMap.keySet();

	}

	@Override
	public Object getAnnotation(String key) {
		return annotationMap.get(key);
	}

	@Override
	public void putAnnotation(String key, Object annotation) {
		annotationMap.put(key, annotation);
	}

	@Override
	public ProcessIF process() {
		return function.process();
	}

	@Override
	public ModelIF model() {
		return function().model();
	}

	public void complete() throws SyntaxException {
		for (StatementIF statement : outgoing)
			((Statement) statement).complete();
		isLocal = true;
		for (StatementIF statement : outgoing) {
			if (!statement.isLocal()) {
				isLocal = false;
				break;
			}
		}
	}

	public boolean isComplete() {
		return model().isComplete();
	}

	/**
	 * How to print a location:
	 * 
	 * <pre>
	 *  location 17 is
	 *    kind : ASSIGNMENT
	 *    label: l2
	 *    annote1: sfsfs
	 *    annote2: dsfds
	 *    x[i] = j+(k/2); goto location 18
	 *  end location 17
	 * </pre>
	 * 
	 * choice statement:
	 * 
	 * <code>
	 *    when x == 7 goto location 18;
	 *    when x == 8 goto location 19;
	 * </code>
	 * */
	public void print(String prefix, PrintWriter out) {
		print(prefix, out, false);
	}

	public void print(String prefix, PrintWriter out, boolean withSource) {
		out.println(prefix + "begin location " + id);
		out.println(prefix + "| kind : " + kind + ";");
		if (label != null)
			out.println(prefix + "| label : " + label + ";");
		for (String key : annotationKeys()) {
			out.println(prefix + "| " + key + " : " + getAnnotation(key) + ";");
		}
		if (collectiveAssertion != null) {
			out.println(prefix + "| collective assertion: "
					+ collectiveAssertion.identifier() + ";");
		}
		if (collectiveExpression != null) {
			out.println(prefix + "| collective expression: "
					+ collectiveExpression + ";");
		}
		for (StatementIF statement : statements()) {
			LocationIF targetLocation = statement.targetLocation();
			String locationName = (targetLocation == null ? "<null>" : ""
					+ targetLocation.id());

			out.println(prefix + "| " + statement + " goto location "
					+ locationName + ";");
			if (withSource) {
				out.println(prefix + "| | " + statement.getSource());
			}
		}
		out.println(prefix + "end location " + id + ";");
		out.flush();
	}

	@Override
	public LocalScopeIF scope() {
		return scope;
	}

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

	public void setCorrespondingLocation(LocationIF location) {
		this.correspondingLocation = location;
	}

	@Override
	public LocationIF correspondingLocation() {
		return correspondingLocation;
	}

	public void setCollectiveAssertion(CollectiveAssertionIF assertion) {
		collectiveAssertion = assertion;
	}

	@Override
	public CollectiveAssertionIF collectiveAssertion() {
		return collectiveAssertion;
	}

	public void setCollectiveExpression(ExpressionIF expression) {
		collectiveExpression = expression;
	}

	@Override
	public ExpressionIF collectiveExpression() {
		return collectiveExpression;
	}

	@Override
	public LocationIF openLocation() {
		return openLocation;
	}

	@Override
	public void setOpenLocation(LocationIF openLocation) {
		this.openLocation = openLocation;
	}
}