Scope.java

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

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Vector;

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.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.scope.ScopeIF;
import edu.udel.cis.vsl.tass.model.IF.variable.VariableIF;
import edu.udel.cis.vsl.tass.model.impl.Function;
import edu.udel.cis.vsl.tass.model.impl.variable.Variable;

/**
 * A lexical scope, which defines a scope for variables. Scopes form a tree. The
 * root scope is the single shared scope: the scope that is shared by all
 * processes; this includes all shared variables, including the input and output
 * variables. The children of the shared scope are the process scopes; there is
 * one for each process p. The process scope for p includes the global variables
 * for p. The children of the process scope for p are local scopes: there is one
 * such local scope for each function belonging to p. Each local scope can have
 * children, and so on, based on the nesting of blocks used to define that
 * function.
 * 
 * The formal parameters to a function are considerd to be local variables in
 * the outermost scope for the function, just like other local variables
 * declared in that scope.
 * 
 * The use of a binding expression (forall, exists, ...) also defines a scope,
 * called a bound scope.
 */
public class Scope implements ScopeIF {

	/** The kind of scope: SYSTEM, MODEL, PROCESS, LOCAL, or BOUND */
	private ScopeKind kind;

	/** The model this scope is associated to, or null if there is no such model */
	private ModelIF model;

	/**
	 * The parent scope, i.e., the scope immediatley containing this scope. May
	 * be null if this is the top-most scope for the function.
	 */
	private Scope parent;

	/**
	 * A human-readable description of this scope, used only for reporting
	 * issues to user.
	 */
	protected String name;

	/**
	 * The children scope of this scope, i.e., the scopes immediately contained
	 * withing this scope.
	 */
	private Vector<ScopeIF> children = new Vector<ScopeIF>();

	/** Vector of variables in this scope. */
	protected Vector<VariableIF> variables = new Vector<VariableIF>();

	/** A set duplicating variables, but giving faster look-up */
	protected Collection<VariableIF> variableSet = new LinkedHashSet<VariableIF>();

	/** Map from variable name to variable. */
	private Map<String, VariableIF> variableNameMap = new LinkedHashMap<String, VariableIF>();

	/** Vector of functions in this scope. */
	protected Vector<FunctionIF> functions = new Vector<FunctionIF>();

	/** A set duplicating functions, but giving faster look-up */
	protected Collection<FunctionIF> functionSet = new LinkedHashSet<FunctionIF>();

	/** Map from variable name to function. */
	private Map<String, FunctionIF> functionNameMap = new LinkedHashMap<String, FunctionIF>();

	/**
	 * Creates a new scope whose parent is the given scope. Parent may be null;
	 * this has to happen for at least one scope (typically, the single system
	 * scope). This also modifies the parent, by adding the new scope to the
	 * parent's children list. The new scope will initially have 0 children, 0
	 * variables, and 0 functions.
	 * 
	 * The name is null. It can be changed later.
	 */
	public Scope(ScopeIF parent, ScopeKind kind, ModelIF model) {
		this.parent = (Scope) parent;
		this.kind = kind;
		this.model = model;
		if (parent != null)
			((Scope) parent).addChild(this);
	}

	/**
	 * Creates a new scope whose parent is the given scope. Parent may be null;
	 * this has to happen for at least one scope (typically, the single system
	 * scope). This also modifies the parent, by adding the new scope to the
	 * parent's children list. The new scope will initially have 0 children, 0
	 * variables, and 0 functions.
	 * 
	 * The name of the scope is set to the given name. It can be changed later.
	 */
	public Scope(ScopeIF parent, ScopeKind kind, ModelIF model, String name) {
		this(parent, kind, model);
		this.name = name;
	}

	protected void addName(VariableIF variable) throws SyntaxException {
		String name = variable.name();
		VariableIF oldVariable = variableNameMap.get(name);

		if (oldVariable != null) {
			throw new SyntaxException(variable, "Variable with name " + name
					+ " already exists in this scope: " + oldVariable);
		}
		variableNameMap.put(name, variable);
	}

	@Override
	public Iterator<ScopeIF> children() {
		return children.iterator();
	}

	@Override
	public int numChildren() {
		return children.size();
	}

	private void addChild(ScopeIF child) {
		assert (!children.contains(child));
		children.add(child);
	}

	@Override
	public ScopeIF parent() {
		return parent;
	}

	@Override
	public VariableIF variableWithId(int id) {
		return variables.elementAt(id);
	}

	@Override
	public VariableIF variableWithName(String name) {
		return variableNameMap.get(name);
	}

	@Override
	public Collection<VariableIF> variables() {
		return variables;
	}

	public void addVariable(VariableIF variable) throws SyntaxException {
		addName(variable);
		((Variable) variable).setIdInScope(variables.size());
		variables.add(variable);
		variableSet.add(variable);
	}

	/**
	 * Completes the functions. Does nothing with variables or children scopes.
	 */
	public void complete() throws SyntaxException {
		for (FunctionIF function : functions)
			((Function) function).complete();
	}

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

	@Override
	public int numVariables() {
		return variables.size();
	}

	@Override
	public boolean containsVariable(VariableIF variable) {
		return variableSet.contains(variable);
	}

	@Override
	public boolean containsFunction(FunctionIF function) {
		return functionSet.contains(function);
	}

	@Override
	public FunctionIF functionWithId(int id) {
		return functions.elementAt(id);
	}

	@Override
	public FunctionIF functionWithName(String name) {
		return functionNameMap.get(name);
	}

	@Override
	public Collection<FunctionIF> functions() {
		return functionSet;
	}

	@Override
	public int numFunctions() {
		return functions.size();
	}

	protected void addName(FunctionIF function) throws SyntaxException {
		String name = function.name();
		FunctionIF oldFunction = functionNameMap.get(name);

		if (oldFunction != null) {
			throw new SyntaxException(function, "Function with name " + name
					+ " already exists in this scope: " + oldFunction);
		}
		functionNameMap.put(name, function);
	}

	public void addFunction(FunctionIF function) throws SyntaxException {
		addName(function);
		((Function) function).setIdInScope(functions.size());
		functions.add(function);
		functionSet.add(function);
	}

	@Override
	public String toString() {
		return name;
	}

	/**
	 * Performs search for variable with given name using lexical scoping: if
	 * variables is not found in this scope, search the parent scope, etc.
	 * Returns first occurence of variable with this name, searching in that
	 * order. If not found all the way up the scopes, returns null.
	 */
	public VariableIF getLexicalVariable(String name) {
		VariableIF result = variableWithName(name);

		if (result != null)
			return result;
		if (parent == null)
			return null;
		return parent.getLexicalVariable(name);
	}

	@Override
	public FunctionIF getLexicalFunction(String name) {
		FunctionIF result = functionWithName(name);

		if (result != null)
			return result;
		if (parent == null)
			return null;
		return parent.getLexicalFunction(name);
	}

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