INTERFACEA Scope.T is a mapping that associates names with constants, variables, predicates, functions, procedures, interfaces, and modules (that is, with any of the things that a name can denote in Juno). When an abstract syntax tree (or JunoAST.T) is decorated by the type checker, each node of the AST that introduces a scope is labelled with a Scope.T that records the bindings of the names introduced at that scope level.JunoScope ;
Scopes are arranged in a tree structure that reflects their nesting in the program text; if a look-up on an identifier fails in a scope, the implementation continues by looking up the identifier in the parent scope, the parent's parent, and so on, until the lookup succeeds or finally fails on the root scope.
This interface also defines the type Entity
. In a scope, each name
(represented by an Atom.T) is bound to an Entity
. Entity
's represent
Juno local variables, procedure arguments, constants, globals, predicates,
functions, procedures, interface scopes, and module scopes.
Scopes are typically used in four different ways. There are root
scopes (which name modules), unit
scopes (which name top-level module
elements), code
scopes (which name predicate, function, and procedure
arguments), and proj
scopes (which name projected variables). The four
uses are distinguished by the types of their parent scopes and by the types
of Entity
's they contain. In summary:
Scope Type Parent Type Contains Contained Entity Type's ---------- ------------- -------------- ---------------------------- "Root" NIL Module names Mod "Unit" "Root" Block names Const, Var, Pred, Func, Proc "Code" "Unit" Argument names Arg "Proj" "Code"/"Proj" Local vars Temp
IMPORT JunoAST, StackTbl; FROM JunoCompileErr IMPORT Error; IMPORT Atom, Wr; TYPE T <: ROOT; PROCEDURE New(p: T; size: CARDINAL := 1): T;
Return a new scope with parent scopep
in which no names are bound. If p is NIL, the new scope is a root scope. Initially, the scope is created with sizesize
, but it will grow dynamically to accommodate any number of bindings.
PROCEDURE Parent(scp: T): T;
Return the parent ofscp
, or NIL ifscp
is a root scope.
PROCEDURE SetParent(scp, parent: T);
Set the parent scope ofscp
toparent
.
PROCEDURE Lookup(scp: T; id: Atom.T; localOnly := FALSE): Entity;
Return the entity associated with the name id in the scope scp.
Returns NIL if id is unbound. If localOnly is FALSE, then all
scopes on the path from scp to scp's root are searched in order;
otherwise only scp
is searched.
PROCEDURE LookupQId( scp: T; qid: JunoAST.QId; VAR (*OUT*) unit: Entity): Entity;
Ifqid
is unqualified, then setunit
to NIL and return the result of Lookup(scp, qid.id0). Otherwise, setunit
toLookup(scp, qid.id0)
. If that is a non-NIL
Mod
, then returnLookup(mod.public_scp, qid.id1)
; else returnNIL
.
PROCEDURE Names(scp: T): REF ARRAY OF Atom.T;
Return an array containing the names bound in scp
(not including names
bound in any of its ancestor scopes).
PROCEDURE LocalArgs(scp: T; kinds: SET OF ArgKind): JunoAST.IdList;
Return a list of identifiers corresponding to thoseArg
entities inscp
with akind
that is a member of the setkinds
.
EXCEPTION NameClash; NotFound; PROCEDURE Bind(scp: T; id: Atom.T; e: Entity) RAISES { NameClash };
Bindid
toe
inscp
. This creates a new binding inscp
; it never affectsscp
's ancestors. Bind raises the exceptionNameClash
ifid
is already bound to something inscp
.
PROCEDURE Rebind(scp: T; id: Atom.T; e: Entity);
Bindid
toe
inscp
. Ifid
is already bound inscp
this changes the binding. Otherwise, it creates a new binding. This procedure never affectsscp
's ancestors.
PROCEDURE Unbind(scp: T; id: Atom.T): Entity RAISES { NotFound };
Ifid
is bound inscp
, then return the entity it is bound to and remove the binding fromscp
. Otherwise, raiseNotFound
.
PROCEDURE Debug(scp: T; level: CARDINAL := 0);
Equivalent to Print(Stdio.stderr, scp, level, 2)
.
PROCEDURE Print(wr: Wr.T; scp: T; level, indent: CARDINAL := 0);
Print a description ofscp
towr
at logical indentation levelindent
. Nested scopes deeper thanlevel
are not shown. Hence, whenlevel = 0
, only the top-level entities ofscp
are shown.
PROCEDURE PrintEntity(wr: Wr.T; ent: Entity; level, indent: CARDINAL);
Print a description ofent
towr
at logical indentation levelindent
. Nested scopes deeper thanlevel
are not shown. Hence, ifent
is an entity with a scope field, the scope is elided.
TYPE (* Types introduced as classes for the purposes of sub-typing only. *) Entity <: ROOT; (* LocalValue | Value | Code | Unit *) (* LocalParam | Temp *) LocalValue = Entity BRANDED "JunoScope.LocalValue" OBJECT offset: INTEGER; (* offset in current frame from fp *) END; ArgKind = { Out, InOut, In }; (* Arg *) LocalParam = LocalValue BRANDED "JunoScope.LocalParam" OBJECT kind: ArgKind; (* kind of parameter *) END; (* Const | Var *) Value = Entity BRANDED "JunoScope.Value" OBJECT init: JunoAST.Expr; (* may be JunoAST.NilExpr for Var *) index: CARDINAL; (* index into JunoRT.value_tbl *) END; (* PredCode | ProcCode *) Code = Entity BRANDED "JunoScope.Code" OBJECT formals: T; (* pred/func/proc formal args *) tbl: StackTbl.T; (* local variable table *) index: CARDINAL; (* index into JunoRT.[ext_]code_tbl *) in_cnt: CARDINAL; (* # of IN parameters *) END; (* Pred | Func *) PredCode = Code BRANDED "JunoScope.PredCode" OBJECT body: JunoAST.Formula; (* predicate/function body *) normal_form: JunoAST.NormalForm; (* normal form of constraint *) END; (* Proc *) ProcCode = Code BRANDED "JunoScope.Proc" OBJECT out_cnt: CARDINAL; (* # of OUT parameters *) inout_cnt: CARDINAL; (* # of INOUT parameters *) body: JunoAST.Cmd; (* original body of the procedure *) external := FALSE (* Modula-3 external procedure? *) END; (* The "body" field is relevant iff the "external" field is "FALSE". *) (* Mod *) Unit = Entity BRANDED "JunoScope.Unit" OBJECT public_scp: T; (* scope for public declarations *) scp: T; (* scope for all declarations *) END; (* Clients should create instances of the following types. *) Temp <: LocalValue; (* projected local variable *) Arg <: LocalParam; (* proc/pred/func arg *) Const <: Value; (* top-level CONST *) Var <: Value; (* top-level VAR *) Pred <: PredCode; (* top-level PRED *) Func <: PredCode; (* top-level FUNC *) Proc <: ProcCode; (* top-level PROC *) Mod <: Unit; (* MODULE *) PROCEDURE NewPred(pred: JunoAST.PredDecl; mod: JunoAST.Id): Pred RAISES {Error};
Return a new, complete predicate entity forpred
in the module namedmod
. RaisesJunoCompile.Error
if two or more formals inproc
have the same name.
PROCEDURE NewFunc(func: JunoAST.FuncDecl; mod: JunoAST.Id): Func RAISES {Error};
Return a new, complete function entity forfunc
in the module namedmod
. RaisesJunoCompile.Error
if two or more formals inproc
have the same name.
PROCEDURE NewProc(proc: JunoAST.ProcDecl; mod: JunoAST.Id): Proc RAISES {Error};
Return a new, complete procedure entity forproc
in the module namedmod
. RaisesJunoCompile.Error
if two or more formals inproc
have the same name.
END JunoScope.