LoopLocation.java

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

import java.util.Collection;
import java.util.LinkedHashSet;

import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.expression.BinaryExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.expression.ExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.expression.LHSExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.expression.UnaryExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.expression.VariableExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.expression.ExpressionIF.ExpressionKind;
import edu.udel.cis.vsl.tass.model.IF.location.AssignmentLocationIF;
import edu.udel.cis.vsl.tass.model.IF.location.InvocationLocationIF;
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.location.ReceiveLocationIF;
import edu.udel.cis.vsl.tass.model.IF.scope.LocalScopeIF;
import edu.udel.cis.vsl.tass.model.IF.statement.ReceiveStatementIF;
import edu.udel.cis.vsl.tass.model.IF.statement.StatementIF;
import edu.udel.cis.vsl.tass.model.IF.variable.VariableIF;

public class LoopLocation extends BinaryChoiceLocation implements
		LoopLocationIF {

	private Collection<VariableIF> writevars = null;

	private Collection<VariableIF> writerefs = null;

	private Collection<LocationIF> body = null;

	public LoopLocation(LocalScopeIF scope, ExpressionIF condition) {
		super(scope, condition);
	}

	@Override
	public Collection<LocationIF> body() {
		if (!isComplete()) {
			throw new RuntimeException(
					"Must complete model before calling body");
		}
		return body;
	}

	/**
	 * Experimental method: returns reference variables that are written to in
	 * the loop body.
	 */
	public Collection<VariableIF> writerefs() {
		if (!isComplete()) {
			throw new RuntimeException(
					"Must complete model before calling writerefs");
		}
		return writerefs;
	}

	/**
	 * Experimental method: returns non-reference variables that are written to
	 * in the loop body.
	 */
	public Collection<VariableIF> writevars() {
		if (!isComplete()) {
			throw new RuntimeException(
					"Must complete model before calling writevars");
		}
		return writevars;
	}

	private VariableIF baseArray(ExpressionIF arrayExpression)
			throws SyntaxException {
		if (arrayExpression.kind() == ExpressionKind.SUBSCRIPT)
			return baseArray(((BinaryExpressionIF) arrayExpression).left());
		if (arrayExpression.kind() == ExpressionKind.VARIABLE)
			return ((VariableExpressionIF) arrayExpression).variable();
		return null;
	}

	private void processLHS(LHSExpressionIF lhs) throws SyntaxException {
		if (lhs.kind() == ExpressionKind.VARIABLE) {
			writevars.add(((VariableExpressionIF) lhs).variable());
		} else if (lhs.kind() == ExpressionKind.SUBSCRIPT) {
			VariableIF variable = baseArray(lhs);

			if (variable != null)
				writerefs.add(variable);
		}
	}

	private void computeWrites() throws SyntaxException {
		writevars = new LinkedHashSet<VariableIF>();
		writerefs = new LinkedHashSet<VariableIF>();
		for (LocationIF location : body) {
			if (location.kind() == LocationKind.ASSIGNMENT) {
				processLHS(((AssignmentLocationIF) location).statement().lhs());
			} else if (location.kind() == LocationKind.INVOCATION) {
				LHSExpressionIF lhs = ((InvocationLocationIF) location)
						.statement().lhs();

				if (lhs != null)
					processLHS(lhs);
			} else if (location.kind() == LocationKind.RECEIVE) {
				ReceiveLocationIF receiveLocation = (ReceiveLocationIF) location;

				for (StatementIF statement : receiveLocation.statements()) {
					ReceiveStatementIF receiveStatement = (ReceiveStatementIF) statement;

					processLHS(receiveStatement.buffer());
					if (receiveStatement.tag().kind() == ExpressionKind.ANY) {
						processLHS((LHSExpressionIF) (((UnaryExpressionIF) receiveStatement
								.tag()).expression()));
					}
				}
			}
		}
	}

	private void dfs(LocationIF location) {
		if (body.contains(location))
			return;
		body.add(location);
		for (StatementIF statement : location.statements()) {
			if (!statement.equals(falseBranch))
				dfs(statement.targetLocation());
		}
	}

	/**
	 * To compute the body of the loop, find all nodes reachable from this node
	 * without passing through the false branch. Include this node in the body.
	 * Then check that for any edge e leading to a body node other than this
	 * node, the source location of e is in the body. Then check that for any
	 * edge e leading from a body node, the destination is either in the body or
	 * is the exit node.
	 */
	@Override
	public void complete() throws SyntaxException {
		LocationIF exitNode = falseBranch.targetLocation();
		body = new LinkedHashSet<LocationIF>();
		dfs(this);
		for (LocationIF location : body) {
			if (!this.equals(location)) {
				for (StatementIF statement : location.incomingStatements()) {
					LocationIF source = statement.sourceLocation();

					if (!body.contains(source)) {
						throw new SyntaxException(statement, "Statement from "
								+ source + " to " + location
								+ " enters body of loop " + this);
					}
				}
			}
			for (StatementIF statement : location.statements()) {
				LocationIF target = statement.targetLocation();

				if (!exitNode.equals(target) && !body.contains(target)) {
					throw new SyntaxException(statement, "Statement from "
							+ location + " to " + target + " escapes loop body");
				}
			}
		}
		computeWrites();
		super.complete();
	}
}