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 scopepin 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 ifscpis a root scope.
PROCEDURE SetParent(scp, parent: T);
Set the parent scope ofscptoparent.
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;
Ifqidis unqualified, then setunitto NIL and return the result of Lookup(scp, qid.id0). Otherwise, setunittoLookup(scp, qid.id0). If that is a non-NILMod, 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 thoseArgentities inscpwith akindthat is a member of the setkinds.
EXCEPTION NameClash; NotFound;
PROCEDURE Bind(scp: T; id: Atom.T; e: Entity) RAISES { NameClash };
Bindidtoeinscp. This creates a new binding inscp; it never affectsscp's ancestors. Bind raises the exceptionNameClashifidis already bound to something inscp.
PROCEDURE Rebind(scp: T; id: Atom.T; e: Entity);
Bindidtoeinscp. Ifidis already bound inscpthis 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 };
Ifidis 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 ofscptowrat logical indentation levelindent. Nested scopes deeper thanlevelare not shown. Hence, whenlevel = 0, only the top-level entities ofscpare shown.
PROCEDURE PrintEntity(wr: Wr.T; ent: Entity; level, indent: CARDINAL);
Print a description ofenttowrat logical indentation levelindent. Nested scopes deeper thanlevelare not shown. Hence, ifentis 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 forpredin the module namedmod. RaisesJunoCompile.Errorif two or more formals inprochave the same name.
PROCEDURE NewFunc(func: JunoAST.FuncDecl; mod: JunoAST.Id): Func
RAISES {Error};
Return a new, complete function entity forfuncin the module namedmod. RaisesJunoCompile.Errorif two or more formals inprochave the same name.
PROCEDURE NewProc(proc: JunoAST.ProcDecl; mod: JunoAST.Id): Proc
RAISES {Error};
Return a new, complete procedure entity forprocin the module namedmod. RaisesJunoCompile.Errorif two or more formals inprochave the same name.
END JunoScope.