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;
}
}