InvocationStatement.java

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

import java.util.Collection;
import java.util.List;

import edu.udel.cis.vsl.tass.model.IF.FunctionIF;
import edu.udel.cis.vsl.tass.model.IF.ModelFactoryIF;
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.expression.LHSExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.location.InvocationLocationIF;
import edu.udel.cis.vsl.tass.model.IF.statement.InvocationStatementIF;
import edu.udel.cis.vsl.tass.model.IF.type.TypeIF;
import edu.udel.cis.vsl.tass.model.IF.variable.SharedVariableIF;
import edu.udel.cis.vsl.tass.model.IF.variable.VariableIF;

public class InvocationStatement extends Statement implements
		InvocationStatementIF {

	/** Left-hand side of assignment. May be null. */
	private LHSExpressionIF lhs;

	/** Function being called. */
	private FunctionIF callee;

	/** Sequence of actual argument expressions */
	ExpressionIF[] arguments;

	public InvocationStatement(ModelFactoryIF factory,
			InvocationLocationIF sourceLocation, LHSExpressionIF lhs,
			FunctionIF callee, List<ExpressionIF> argumentList,
			ExpressionIF guard) throws SyntaxException {
		super(factory, guard, sourceLocation, StatementKind.INVOCATION);

		int numFormals, numActuals, i;

		if (callee == null)
			throw new NullPointerException("Null callee");
		if (!process().equals(callee.process()))
			throw new SyntaxException(sourceLocation, "Function " + function()
					+ " in process " + process() + " cannot call function "
					+ callee + " in other process " + callee.process());
		this.callee = callee;
		numFormals = callee.numFormals();
		if (argumentList == null)
			throw new NullPointerException("Null argument list");
		numActuals = argumentList.size();
		if (callee.hasVariableArguments()) {
			if (numActuals < numFormals) {
				throw new SyntaxException(sourceLocation, "Expected at least "
						+ numFormals + " arguments but saw " + numActuals + ":"
						+ arguments);
			}
		} else {
			if (numActuals != numFormals) {
				throw new SyntaxException(sourceLocation, "Expected "
						+ numFormals + " arguments but saw " + numActuals + ":"
						+ arguments);
			}
		}
		arguments = new ExpressionIF[numActuals];
		i = 0;
		for (ExpressionIF argument : argumentList) {
			TypeIF actualType = argument.type();

			if (i < numFormals) {
				TypeIF formalType = callee.formal(i).type();

				if (!actualType.isSubtypeOf(formalType)) {
					throw new SyntaxException(argument, "Expected type "
							+ formalType + " but saw type " + actualType
							+ " in argument " + i + " of call to " + callee);
				}
			}
			factory.checkScope(argument, sourceLocation.scope());
			arguments[i] = argument;
			i++;
		}
		if (lhs != null) {
			if (!lhs.type().equals(callee.returnType())) {
				throw new SyntaxException(lhs,
						"Type mis-match: left-hand side has type " + lhs.type()
								+ " but function " + callee + " returns type "
								+ callee.returnType());
			}
			factory.checkScope(lhs, sourceLocation.scope());
		}
		this.lhs = lhs;
	}

	public InvocationStatement(ModelFactoryIF factory,
			InvocationLocationIF sourceLocation, LHSExpressionIF lhs,
			FunctionIF callee, List<ExpressionIF> argumentList)
			throws SyntaxException {
		this(factory, sourceLocation, lhs, callee, argumentList, factory
				.booleanLiteralExpression(true));
	}

	public ExpressionIF[] arguments() {
		return arguments;
	}

	public FunctionIF callee() {
		return callee;
	}

	public LHSExpressionIF lhs() {
		return lhs;
	}

	public String toString() {
		String result;
		int n = arguments.length;

		if (lhs != null) {
			result = lhs + " = ";
		} else {
			result = "";
		}
		result += callee + "(";
		for (int i = 0; i < n; i++) {
			if (i > 0)
				result += ",";
			result += arguments[i].toString();
		}
		result += ");";
		return result;
	}

	private boolean inSet(VariableIF variable,
			Collection<SharedVariableIF> shared) {
		return variable instanceof SharedVariableIF
				&& shared.contains((SharedVariableIF) variable);
	}

	public void complete() throws SyntaxException {
		Collection<SharedVariableIF> shared = process().model().scope()
				.properSharedVariables();

		super.complete();
		isLocal = true;
		if (lhs != null) {
			for (VariableIF variable : lhs.freeVariables()) {
				if (inSet(variable, shared)) {
					isLocal = false;
					return;
				}
			}
		}
		for (ExpressionIF expression : arguments) {
			for (VariableIF variable : expression.freeVariables()) {
				if (inSet(variable, shared)) {
					isLocal = false;
					return;
				}
			}
		}
	}
}