LocalScope.java
package edu.udel.cis.vsl.tass.model.impl.scope;
import java.util.Collection;
import java.util.Vector;
import edu.udel.cis.vsl.tass.model.IF.FunctionIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.location.LocationIF;
import edu.udel.cis.vsl.tass.model.IF.scope.LocalScopeIF;
import edu.udel.cis.vsl.tass.model.IF.scope.ScopeIF;
import edu.udel.cis.vsl.tass.model.IF.type.TypeIF.TypeKind;
import edu.udel.cis.vsl.tass.model.IF.variable.FormalVariableIF;
import edu.udel.cis.vsl.tass.model.IF.variable.LocalVariableIF;
public class LocalScope extends Scope implements LocalScopeIF {
/**
* The scope ID, a unique ID number among all scopes belonging to the
* function. It is not necessarily set until the function is completed.
*/
private int id = -1;
private int depth;
private FunctionIF function;
private Collection<LocalVariableIF> properLocals = new Vector<LocalVariableIF>();
private Collection<LocationIF> locations = new Vector<LocationIF>();
/**
* The list of local scope ancestors of this scope (including this scope).
* The outermost scope is in index 0, and this scope is in the last position
* (ancestors.length -1). This is computed once, at creation, and stored
* here. The top-most scope is the first ancestor whose parent is null.
*/
private LocalScopeIF[] ancestors;
/**
* Constructor to be used for creating outermost scope. The parent must be a
* non-null scope. The depth and id number for the new scope will both be 0.
*
* @param parent
* @param function
*/
public LocalScope(ScopeIF parent, FunctionIF function) {
super(parent, ScopeKind.LOCAL, parent.model());
assert function != null;
this.depth = 0;
this.function = function;
int numFormals = function.numFormals();
for (int i = 0; i < numFormals; i++) {
variables.add(null);
}
this.id = 0;
name = "outermost local scope for function " + function + " of "
+ function.process();
ancestors = new LocalScopeIF[] { this };
}
/**
* Constructor to be used for creating any scope that is not the outermost
* scope. The function is the function of the given parent. Assigns an id
* number which is the current number of local scopes in the function.
*
* @parent the local scope that is to immediately contain the new local
* scope
*/
public LocalScope(LocalScopeIF parent) {
super(parent, ScopeKind.LOCAL, parent.model());
this.function = parent.function();
this.id = function.numScopes();
this.depth = parent.depth() + 1;
this.name = "internal local scope " + id + " for function " + function
+ " of " + function.process() + " with parent scope "
+ parent.localId();
{
LocalScopeIF[] parentAncestors = parent.localAncestors();
int numParentAncestors = parentAncestors.length;
ancestors = new LocalScopeIF[numParentAncestors + 1];
for (int i = 0; i < numParentAncestors; i++)
ancestors[i] = parentAncestors[i];
ancestors[numParentAncestors] = this;
}
}
@Override
public int localId() {
return id;
}
public void setLocalId(int id) {
this.id = id;
}
public void setFormal(FormalVariableIF formal) throws SyntaxException {
int index = formal.idInScope();
LocalVariableIF oldFormal = (LocalVariableIF) variables.get(index);
// this can be checked in factory when formal is created...
if (index < 0 || index >= function.numFormals())
throw new SyntaxException(formal, "Index " + index
+ " is out of range for function " + function
+ ", numFormals=" + function.numFormals());
if (oldFormal != null)
throw new SyntaxException(formal, "Formal " + index
+ " of function " + function + " already set: " + oldFormal);
addName(formal);
variables.set(index, formal);
variableSet.add(formal);
}
public void addProperLocalVariable(LocalVariableIF variable)
throws SyntaxException {
if (variable instanceof FormalVariableIF)
throw new SyntaxException(
"Cannot use addProperLocalVariable to add formal variable: "
+ variable);
addVariable(variable);
properLocals.add(variable);
}
public void complete() throws SyntaxException {
int numFormals = function.numFormals();
for (int i = 0; i < numFormals; i++) {
if (variables.get(i) == null)
throw new SyntaxException(function, "formal parameter " + i
+ " has not been defined");
}
for (LocalVariableIF variable : properLocals()) {
if (variable.type().kind() == TypeKind.ARRAY) {
if (variable.dimensionExpressions() == null) {
throw new SyntaxException(variable,
"Need to set dimensions of this array variable");
}
}
}
}
@Override
public int depth() {
return depth;
}
@Override
public FunctionIF function() {
return function;
}
@Override
public Collection<LocalVariableIF> properLocals() {
return properLocals;
}
/**
* The variables in this scope (including formals) are assigned ID numbers
* 0, 1, 2, ..., at completion time. This method returns the variable with
* the given ID.
*/
@Override
public LocalVariableIF variableWithId(int id) {
return (LocalVariableIF) super.variableWithId(id);
}
/**
* Returns the variable in this scope with the given name, or null if there
* isn't one.
*/
@Override
public LocalVariableIF variableWithName(String name) {
return (LocalVariableIF) super.variableWithName(name);
}
public void addLocation(LocationIF location) {
assert location.scope() == this;
locations.add(location);
}
@Override
public Collection<LocationIF> locations() {
return locations;
}
@Override
public LocalScopeIF[] localAncestors() {
return ancestors;
}
}