MFScopeManager.java
package edu.udel.cis.vsl.abc.front.fortran.astgen;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import edu.udel.cis.vsl.abc.ast.node.IF.IdentifierNode;
import edu.udel.cis.vsl.abc.ast.node.IF.NodeFactory;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.FunctionTypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypeNode.TypeNodeKind;
import edu.udel.cis.vsl.abc.ast.type.IF.StandardBasicType.BasicTypeKind;
import edu.udel.cis.vsl.abc.token.IF.Source;
public class MFScopeManager {
static int NUM_ATTR_ALL = 0;
static final int ATTR_FUNC_ELEMENTAL = NUM_ATTR_ALL++;
static final int ATTR_FUNC_IMPURE = NUM_ATTR_ALL++;
static final int ATTR_FUNC_MODULE = NUM_ATTR_ALL++;
static final int ATTR_FUNC_NON_RECURSIVE = NUM_ATTR_ALL++;
static final int ATTR_FUNC_PURE = NUM_ATTR_ALL++;
static final int ATTR_FUNC_RECURSIVE = NUM_ATTR_ALL++;
static final int ATTR_MODULE_PROTECTED = NUM_ATTR_ALL++;
static final int ATTR_PROC_INTRINSIC = NUM_ATTR_ALL++;
/* ==== All FUNC/MODULE/PROC attribute indices shall be placed above ==== */
final int NUM_ATTR_PROCEDURE = NUM_ATTR_ALL;
static final int ATTR_ARG_INTENT_IN = NUM_ATTR_ALL++;
static final int ATTR_ARG_INTENT_OUT = NUM_ATTR_ALL++;
static final int ATTR_ARG_OPTIONAL = NUM_ATTR_ALL++;
static final int ATTR_ARG_VALUE = NUM_ATTR_ALL++;
static final int ATTR_IDENT_PRIVATE = NUM_ATTR_ALL++;
static final int ATTR_IDENT_PUBLIC = NUM_ATTR_ALL++;
static final int ATTR_VAR_ALLOCATABLE = NUM_ATTR_ALL++;
static final int ATTR_VAR_CONTIGUOUS = NUM_ATTR_ALL++;
static final int ATTR_VAR_CODIMENSION = NUM_ATTR_ALL++;
static final int ATTR_VAR_DIMENSION = NUM_ATTR_ALL++;
static final int ATTR_VAR_EXTERNAL = NUM_ATTR_ALL++;
static final int ATTR_VAR_POINTER = NUM_ATTR_ALL++;
static final int ATTR_VAR_SAVE = NUM_ATTR_ALL++;
static final int ATTR_VAR_TARGET = NUM_ATTR_ALL++;
static final int ATTR_VAR_VOLATILE = NUM_ATTR_ALL++;
private static final int DEFAULT_IMPLICIT_INTEGER_START = 'I' - 'A';
private static final int DEFAULT_IMPLICIT_INTEGER_END = 'N' - 'A';
private static final int NUM_LETTERS = 26;
private NodeFactory nodeFactory = null;
private List<HashSet<String>> globalAttrIdentSets = new ArrayList<HashSet<String>>();
private MFScopeRecord gSRecord = new MFScopeRecord();
private MFScopeRecord cSRecord = gSRecord;
/**
* Constructs a {@code MFScopeManager} to store and analyze scope-based
* information.
*
* @param nodeFactory
* is a non-null instance used for creating implicit
* {@link TypeNode}s
*/
MFScopeManager(NodeFactory nodeFactory) {
assert nodeFactory != null;
this.nodeFactory = nodeFactory;
for (int i = 0; i < NUM_ATTR_PROCEDURE; i++) {
this.globalAttrIdentSets.add(new HashSet<String>());
}
}
private int indexOfScopedImplicitType(char c) {
return c - 'A';
}
/**
* Collects array type declaration information (i.e.,
* {@code arrayBaseType}), which is associated with {@code arrayIdent}.
*
* @param arrayIdent
* is a non-null and non-empty array variable
* identifier/name
* @param arrayBaseType
* is a non-null array element type
*/
void addDeclArray(String arrayIdent, TypeNode arrayBaseType) {
assert arrayIdent != null && !arrayIdent.isEmpty()
&& arrayBaseType != null;
this.cSRecord.varIdentToArrayBaseTypes.put(arrayIdent, arrayBaseType);
}
/**
* Collects parameter type declaration information, which is associated with
* {@code parIdent}.
*
* @param parIdent
* is a non-null and non-empty parameter
* identifier/name
* @param parDeclNode
* is a non-null {@link TypeNode}
*/
void addDeclParameter(String parIdent,
VariableDeclarationNode parDeclNode) {
assert parIdent != null && !parIdent.isEmpty() && parDeclNode != null;
this.cSRecord.parIdentToDecls.put(parIdent, parDeclNode);
}
/**
* Collects variable type declaration information, which is associated with
* {@code parIdent}.
*
* @param varIdent
* is a non-null and non-empty variable
* identifier/name
* @param varDeclNode
* is a non-null {@link TypeNode}
*/
void addDeclVariable(String varIdent, VariableDeclarationNode varDeclNode) {
assert varIdent != null && !varIdent.isEmpty() && varDeclNode != null;
this.cSRecord.varIdentToDecls.put(varIdent, varDeclNode);
}
/**
* Collects the given derived type identifier/name.
*
* @param derivedTypeIdent
* is a non-null and non-empty derived type
* identifier/name
*/
void addDerivedType(String derivedTypeIdent) {
assert derivedTypeIdent != null && !derivedTypeIdent.isEmpty();
this.cSRecord.derivedTypeIdents.add(derivedTypeIdent);
}
/**
* Collects the identifier/name requiring dereference operation for
* retrieving its value.
* <p>
* Note: Recorded variables either have {@code POINTER} attribute or are
* created/transformed by {@link MFASTBuilderWorker}
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* whose initial character shall be a letter in
* upper-case.
*/
void addPointerType(String varIdent) {
assert varIdent != null && !varIdent.isEmpty();
this.cSRecord.ptrIdents.add(varIdent);
}
/**
* Collects the given label identifier/name.
*
* @param lblIdent
* is a non-null and non-empty label identifier/name
*/
void addLabel(String lblIdent) {
assert lblIdent != null && !lblIdent.isEmpty();
this.cSRecord.labels.add(lblIdent);
}
/**
* Collects the given undeclared identifier/name
*
* @param ident
* is a non-null and non-empty undeclared identifier/name
*/
void addUndeclaredIdent(String ident) {
assert ident != null && !ident.isEmpty();
this.cSRecord.undeclIdents.add(ident);
}
/**
* Enters a program unit {@code Scope}.
*
* @param scope
* is a non-null lexical/static scope of a Fortran
* program unit.
* @param unitIdent
* is a non-null and non-empty identifier/name of the
* program unit associated with {@code scope}
* @param unitType
* is the type of the program unit associated with
* {@code scope}
*/
void enterProgramUnitScope(String unitIdent, FunctionTypeNode unitType) {
assert unitIdent != null && !unitIdent.isEmpty();
this.cSRecord = new MFScopeRecord(this.gSRecord, unitIdent, unitType);
}
/**
* Exits the current/innermost scope
* <p>
* All local variable (in the current scope) type, declaration, attribute
* records shall be cleaned up.
*/
void exitProgramUnitScope() {
assert this.cSRecord != null;
// Clean up the current scope record
this.cSRecord = cSRecord.parent();
}
/**
* Returns the array element type for a given array variable identifier/name
*
* @param arrayIdent
* is a non-null and non-empty array variable
* identifier/name
* @return {@link TypeNode}, which is the array element type declared for
* {@code varIdent}.
*/
TypeNode getArrayBaseTypeByIdent(String arrayIdent) {
// assert arrayIdent != null && !arrayIdent.isEmpty();
// is asserted in `hasArrayType`
assert this.hasArrayType(arrayIdent);
return this.cSRecord.varIdentToArrayBaseTypes.get(arrayIdent);
}
/**
* Returns the type declaration for a given variable identifier/name.
* <p>
* For a declared identifier, its {@link VariableDeclarationNode} is
* returned.
* <p>
* For an undeclared identifier, its {@link VariableDeclarationNode} is
* returned iff {@code IMPLICIT NONE} is not specified in the current
* program unit scope; else {@code null} shall be returned.
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* which starts with a letter in upper-case (or an
* underscore for identifiers imported from C/C++ code).
* @return a {@link VariableDeclarationNode}, which is the type declaration
* of the given variable identifier/name {@code varIdent}
*/
VariableDeclarationNode getDeclByVarIdent(String varIdent) {
// assert varIdent != null && !varIdent.isEmpty();
// is asserted in 'isDeclaredVar'
if (this.isDeclaredVar(varIdent)) {
return this.cSRecord.varIdentToDecls.get(varIdent);
} else {
return null;
}
}
/**
* Returns the type declaration for a given parameter identifier/name.
*
* <p>
* For any explicitly type-declared parameter , its
* {@link VariableDeclarationNode} is returned.
* <p>
* For any undeclared parameter, its {@link VariableDeclarationNode} is
* returned iff {@code IMPLICIT NONE} is NOT specified in the current
* program unit scope; else {@code null} shall be returned.
*
* @param parIdent
* is a non-null and non-empty parameter
* identifier/name, which starts with a letter in
* upper-case or a underscore symbol.
* @return a {@link VariableDeclarationNode}, which is the type declaration
* of the given parameter identifier/name {@code parIdent}
*/
VariableDeclarationNode getDeclByParIdent(String parIdent) {
if (this.isParameterVar(parIdent)) {
return this.cSRecord.parIdentToDecls.get(parIdent);
} else {
return null;
}
}
/**
* Returns the implicit type for a given variable identifier/name.
* <p>
* {@code null} shall be returned iff {@code IMPLICIT NONE} statement is
* specified; else a non-null {@link TypeNode} shall be returned.
* <p>
* The implicit type is determined by the initial character of
* {@code varIdent} and {@code IMPLICIT} statement used in the current unit
* scope.
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* which starts with a letter in upper-case (or an
* underscore for identifiers imported from C/C++ code).
* @param src
* is the {@link Source} associated with
* {@code varIdent}.
* @return {@link TypeNode}, which is possibly associated with
* {@code varIdent}.
*/
TypeNode getImplicitType(String varIdent, Source src) {
assert varIdent != null && !varIdent.isEmpty();
if (this.cSRecord.implicitNone)
return null;
int init = indexOfScopedImplicitType(varIdent.charAt(0));
TypeNode type = null;
assert init >= 0;
if (init < NUM_LETTERS) {
/*
* Try to get an implicit type for a regular Fortran variable name.
* The type is assigned according to rules specified by IMPLICIT
* statement in the current program unit scope.
*/
type = this.cSRecord.scopeImplicitTypes[init];
}
// type is null if any of following condition holds:
// 1. the varIdent does not start with a letter in upper-case
// 2. there is no specific implicit rules specified
if (type == null) {
// Case 1: varIdent may be an imported C/C++
// variable, which shall be declared explicitly.
// Case 2: default implicit type rules are used.
if (DEFAULT_IMPLICIT_INTEGER_START <= init && //
init <= DEFAULT_IMPLICIT_INTEGER_END) {
// if varIdent starts with any of: I,J,K,L,M,N
type = nodeFactory.newBasicTypeNode(src, BasicTypeKind.INT);
} else {
type = nodeFactory.newBasicTypeNode(src, BasicTypeKind.FLOAT);
}
} else {
type = type.copy();
}
return type;
}
/**
* Returns the type for a given parameter identifier/name.
* <p>
* For a parameter with its type declared, it is returned according to
* recorded parameter type declarations.
* <p>
* For a parameter with no type declared, its implicit type is returned iff
* {@code IMPLICIT NONE} is not specified in the current program unit scope;
* else {@code null} shall be returned.
*
* @param parIdent
* is a non-null and non-empty parameter
* identifier/name, which shall start with a letter in
* upper-case or a underscore symbol.
* @param src
* is the {@link Source} associated with
* {@code varIdent}.
* @return {@link TypeNode}, which is possibly associated with
* {@code parIdent}.
*/
TypeNode getTypeByParIdent(String parIdent, Source src) {
if (this.isParameterVar(parIdent)) {
return this.cSRecord.parIdentToDecls.get(parIdent).getTypeNode();
} else {
return this.getImplicitType(parIdent, src);
}
}
/**
* Returns the type for a given variable identifier/name.
* <p>
* For a declared identifier, its {@link TypeNode} is returned according to
* recorded type declarations.
* <p>
* For an undeclared identifier, an implicit type is returned iff
* {@code IMPLICIT NONE} is not specified in the current program unit scope;
* else {@code null} shall be returned.
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* which starts with a letter in upper-case (or an
* underscore for identifiers imported from C/C++ code).
* @param src
* is the {@link Source} associated with
* {@code varIdent}.
* @return {@link TypeNode}, which is possibly associated with
* {@code varIdent}.
*/
TypeNode getTypeByVarIdent(String varIdent, Source src) {
// assert varIdent != null && !varIdent.isEmpty();
// is asserted in 'isDeclaredVar'
if (this.isDeclaredVar(varIdent)) {
return this.cSRecord.varIdentToDecls.get(varIdent).getTypeNode();
} else {
return this.getImplicitType(varIdent, src);
}
}
/** @return the identifier/name of the current program unit. */
String getProgramUnitIdent() {
return this.cSRecord.name();
}
/** @return the type of the current program unit */
TypeNode getProgramUnitType() {
return this.cSRecord.scopeType;
}
/**
* @return a non-null set of all undeclared identifiers in the current
* program unit scope.
*/
Set<String> getUndeclaredIdents() {
assert this.cSRecord.undeclIdents != null;
return this.cSRecord.undeclIdents;
}
/**
* Returns {@code true} iff the given {@code arrayIdent} is declared as an
* array in the current scope unit.
*
* @param arrayIdent
* is a non-null and non-empty array variable
* identifier/name
* @return see above
*/
boolean hasArrayType(String arrayIdent) {
assert arrayIdent != null && !arrayIdent.isEmpty();
return this.cSRecord.varIdentToArrayBaseTypes.containsKey(arrayIdent);
}
/**
* Returns {@code true} iff a given identifier/name has a specific attribute
* associated; else {@code false} is returned.
*
* @param ident
* is a non-null and non-empty identifier/name
* @param kindAttr
* is a non-negative integer value representing a
* specific kind of attribute
* @return see above;
*/
boolean hasAttr(String ident, int kindAttr) {
assert ident != null && !ident.isEmpty() && kindAttr >= 0;
return this.cSRecord.scopedAttrIdentSets.get(kindAttr).contains(ident);
}
/**
* Returns {@code true} iff a given program unit identifier/name has a
* specific attribute associated; else {@code false} is returned.
*
* @param puIdent
* is a non-null and non-empty program unit
* identifier/name
* @param kindAttr
* is a non-negative integer value representing a
* specific kind of attribute
* @return
*/
boolean hasAttrForPrograumUnit(String puIdent, int kindAttr) {
assert puIdent != null && !puIdent.isEmpty() && kindAttr >= 0;
return this.gSRecord.scopedAttrIdentSets.get(kindAttr)
.contains(puIdent);
}
/**
* Returns {@code true} iff the given {@code lblIdent} is declared in the
* current program unit scope; else {@code false}.
*
* @param lblIdent
* is a non-null and non-empty label identifier/name
* @return see above
*/
boolean hasLabel(String lblIdent) {
assert lblIdent != null && !lblIdent.isEmpty();
// No global lables from Fortran source code.
return this.cSRecord.labels.contains(lblIdent);
}
/**
* Returns {@code true} iff the given {@code varIdent} is declared in the
* current program unit scope (which is NOT the global one).
*
* @param varIdent
* is a non-null and non-empty variable identifier/name
* @return see above
*/
boolean isDeclaredVar(String varIdent) {
assert varIdent != null && !varIdent.isEmpty();
return this.cSRecord.varIdentToDecls.containsKey(varIdent);
}
/**
* Returns {@code true} iff the given {@code derivedTypeIdent} is declared
* as a derived type; else {@code false}.
*
* @param derivedTypeIdent
* is a non-null and non-empty identifier/name
* @return see above
*/
boolean isDerivedType(String derivedTypeIdent) {
assert derivedTypeIdent != null && !derivedTypeIdent.isEmpty();
return this.cSRecord.derivedTypeIdents.contains(derivedTypeIdent) || //
this.gSRecord.derivedTypeIdents.contains(derivedTypeIdent);
}
/** @return {@code true} iff {@code IMPLICIT NONE} statement is specified */
boolean isImplicitNone() {
return this.cSRecord.implicitNone;
}
/**
* @return true iff the current scope is the global one; else (the current
* scope is associated with a Fortran program unit) false.
*/
boolean isInGlobalScope() {
return this.cSRecord == this.gSRecord;
}
/**
* Returns {@code true} iff the given {@code varIdent} is declared as a
* parameter of the current program unit.
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* whose initial character shall be a letter in
* upper-case or a underscore symbol
* @return see above
*/
boolean isParameterVar(String varIdent) {
assert varIdent != null && !varIdent.isEmpty();
assert '_' == varIdent.charAt(0)
|| ('A' <= varIdent.charAt(0) && varIdent.charAt(0) <= 'Z');
return this.cSRecord.parIdentToDecls.containsKey(varIdent);
}
/**
* Returns {@code true} iff the given {@code varIdent} is a pointer to a
* memory storage. The pointer is either a variable with {@code POINTER}
* attribute or one created/transformed by {@link MFASTBuilderWorker}
*
* @param varIdent
* is a non-null and non-empty variable identifier/name,
* whose initial character shall be a letter in
* upper-case.
* @return see above
*/
boolean isReference(String varIdent) {
assert varIdent != null && !varIdent.isEmpty();
return this.cSRecord.ptrIdents.contains(varIdent);
}
/**
* Set the a given attribute to a given identifier.
*
* @param ident
* is a non-null and non-empty identifier/name
* @param kindAttr
* is a non-negative integer value representing a
* specific kind of attribute
*/
void setAttrByIdent(String ident, int kindAttr) {
assert ident != null && !ident.isEmpty() && kindAttr >= 0;
this.cSRecord.scopedAttrIdentSets.get(kindAttr).add(ident);
if (kindAttr < this.NUM_ATTR_PROCEDURE) {
this.globalAttrIdentSets.get(kindAttr).add(ident);
}
}
/**
* Sets the record of the declaration scope for the given array variable
* {@code arrayIdent} from the current scope to the global scope.
*
* @param arrayIdent
* is a non-null and non-empty identifier/name of the
* array variable, which has been declared as an
* array.
*/
void setDeclArrayGlobal(String arrayIdent) {
assert this.hasArrayType(arrayIdent);
this.gSRecord.varIdentToArrayBaseTypes.put(arrayIdent, //
this.cSRecord.varIdentToArrayBaseTypes.get(arrayIdent));
this.cSRecord.varIdentToArrayBaseTypes.remove(arrayIdent);
}
/**
* Sets the record of the declaration scope for the given {@code ident} from
* the current scope to the global scope.
*
* @param ident
* is a non-null and non-empty identifier/name, which has
* had its type declared.
*/
void setDeclGlobal(String ident) {
assert this.isDeclaredVar(ident);
this.gSRecord.varIdentToDecls.put(ident, //
this.cSRecord.varIdentToDecls.get(ident));
this.cSRecord.varIdentToDecls.remove(ident);
}
/** Forbids implicit declaration when {@code IMPLICIT NONE} is specified. */
void setImplicitNone() {
this.cSRecord.implicitNone = true;
}
/**
* Sets implicit types for a specific range of initial characters based on
* given starting and ending characters, which is specified by Fortran
* {@code IMPLICIT} statement.
*
* @param charStart
* is the starting initial character in
* upper-case.
* @param charEnd
* is the ending initial character in upper-case;
* its integer value shall be greater than or
* equal to {@code charStart}
* @param newImplicitType
* is the implicit type shall be assigned to
* variables, which are implicitly declared.
*/
void setImplicitType(char charStart, char charEnd,
TypeNode newImplicitType) {
assert !this.cSRecord.implicitNone;
int start = indexOfScopedImplicitType(charStart);
int end = indexOfScopedImplicitType(charEnd);
// 'A' <= start <= end <= 'Z'-'A'
assert 0 <= start && start <= end && //
end <= indexOfScopedImplicitType('Z');
// Update scoped implicit type records
for (int i = start; i <= end; i++) {
this.cSRecord.scopeImplicitTypes[i] = newImplicitType;
}
// Update parameter list
for (VariableDeclarationNode parDeclNode : this.cSRecord.parIdentToDecls
.values()) {
char initParIdent = parDeclNode.getIdentifier().name().charAt(0);
if (charStart <= initParIdent && initParIdent <= charEnd) {
TypeNode parImplicitTypeNode = newImplicitType.copy();
// Scalar type is updated as pointer-to-scalar type.
if (newImplicitType.kind() == TypeNodeKind.BASIC) {
parImplicitTypeNode = nodeFactory.newPointerTypeNode(
parImplicitTypeNode.getSource(),
parImplicitTypeNode);
}
parDeclNode.setTypeNode(parImplicitTypeNode);
}
}
}
void updateParameterIdentfier(String oldParId, String newParId) {
Map<String, VariableDeclarationNode> parId2Decls = cSRecord.parIdentToDecls;
VariableDeclarationNode parDeclNode = parId2Decls.get(oldParId);
IdentifierNode oldParIdNode = parDeclNode.getIdentifier();
IdentifierNode newParIdNode = nodeFactory
.newIdentifierNode(oldParIdNode.getSource(), newParId);
this.cSRecord.outParIdents.add(newParId);
parId2Decls.remove(oldParId, parDeclNode);
oldParIdNode.remove();
parDeclNode.setIdentifier(newParIdNode);
parId2Decls.put(newParId, parDeclNode);
}
Set<String> getAllIntentOutParameterIdentifiers() {
return this.cSRecord.outParIdents;
}
/**
* Sets the feasible type of the current program unit.
*
* @param scopeType
* a non-null {@link TypeNode}
*/
void setProgramUnitType(TypeNode scopeType) {
assert scopeType != null;
// Currently a scope type of a prpgram unit shall be
// any of PROGRAM, SUBROUTINE, and FUNCTION, whose
// scope types shall be a {@link FunctionTypeNode}.
// If other types are possible, the following assertions
// shall be deleted or changed.
assert scopeType instanceof FunctionTypeNode;
this.cSRecord.scopeType = scopeType;
}
/**
* {@code MFScopeRecord} is mainly used for recording variable type,
* declaration, and attribute information; label identifers are also
* recorded.
* <p>
* The record can be created for either a global scope or a program unit
* scope.
* <p>
* A program unit is one of following:
* <ul>
* <li>A main program declared with {@code PROGRAM},
* <li>A function subprogram declared with {@code FUNCTION},
* <li>A subroutine subprogram declared with {@code SUBROUTINE},
* <li>A module declared with {@code MODULE},
* <li>A submodule declared with {@code SUBMODULE}, or
* <li>A data-block declared with {@code BLOCK DATA}.
* </ul>
*
* @author Wenhao Wu (wuwenhao@udel.edu)
*/
private class MFScopeRecord {
/** The unique name of global scope record is defined here. */
static final String SCOPE_GLOBAL = "";
private String name = null;
private MFScopeRecord parent = null;
boolean implicitNone = false;
TypeNode scopeType = null;
TypeNode[] scopeImplicitTypes = new TypeNode[NUM_LETTERS];
Set<String> derivedTypeIdents = new HashSet<>();
Set<String> ptrIdents = new HashSet<>();
Set<String> labels = new HashSet<>();
Set<String> undeclIdents = new HashSet<>();
Set<String> outParIdents = new HashSet<>();
Map<String, TypeNode> varIdentToArrayBaseTypes = new HashMap<>();
Map<String, VariableDeclarationNode> varIdentToDecls = new HashMap<>();
Map<String, VariableDeclarationNode> parIdentToDecls = new HashMap<>();
List<HashSet<String>> scopedAttrIdentSets = new ArrayList<HashSet<String>>();
/**
* Constructs global scope record.
* <ul>
* <li>The value returned by calling {@code parent()} is {@code null}.
* <li>The value returned by calling {@code name} is
* {@value #SCOPE_GLOBAL}
* </ul>
*/
MFScopeRecord() {
this.name = SCOPE_GLOBAL;
}
/**
* Constructs program unit scope record.
*
* @param parentRecord
* is the parent scope record
* @param scopeRecordName
* is the identifier/name of the associated
* program unit
* @param scopeType
* is the type of the associated program unit
*/
MFScopeRecord(MFScopeRecord parentRecord, String scopeRecordName,
TypeNode scopeType) {
assert parentRecord != null && scopeRecordName != null;
this.name = scopeRecordName;
this.parent = parentRecord;
this.scopeType = scopeType;
for (int i = 0; i < NUM_ATTR_ALL; i++) {
this.scopedAttrIdentSets.add(new HashSet<String>());
}
}
/** @return the name of the associated program unit */
String name() {
return this.name;
}
/** @return the parent scope record of {@code this} one. */
MFScopeRecord parent() {
return this.parent;
}
}
}