|
|
@@ -7,6 +7,7 @@ FROM SYSTEM IMPORT TSIZE;
|
|
|
CONST
|
|
|
MaxTypes = 256;
|
|
|
MaxPend = 64;
|
|
|
+ MaxMods = 32;
|
|
|
ResDepth = 64;
|
|
|
|
|
|
(* descriptor forms *)
|
|
|
@@ -79,6 +80,15 @@ VAR
|
|
|
nProc : CARDINAL;
|
|
|
nextUid : CARDINAL;
|
|
|
dInt, dCard, dReal, dChar, dBool, dNil : TypeIndex;
|
|
|
+ globScope : ScopePtr; (* the global scope (module names live here) *)
|
|
|
+ curMod : INTEGER; (* current registry slot, -1 between units *)
|
|
|
+ curUnit : INTEGER; (* UnitProg/Def/Impl, -1 between units *)
|
|
|
+ nMods : CARDINAL;
|
|
|
+ modNames : ARRAY [0 .. MaxMods - 1] OF Name;
|
|
|
+ modScopes : ARRAY [0 .. MaxMods - 1] OF ScopePtr;
|
|
|
+ modKind : ARRAY [0 .. MaxMods - 1] OF INTEGER;
|
|
|
+ modImpl : ARRAY [0 .. MaxMods - 1] OF BOOLEAN;
|
|
|
+ haveProg : BOOLEAN;
|
|
|
|
|
|
(* ---------------- strings ---------------- *)
|
|
|
|
|
|
@@ -914,6 +924,20 @@ PROCEDURE EnterProc (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
RETURN TRUE
|
|
|
END EnterProc;
|
|
|
|
|
|
+PROCEDURE ResumeProc (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR node: SymPtr;
|
|
|
+ BEGIN
|
|
|
+ IF curUnit # UnitImpl THEN RETURN FALSE END;
|
|
|
+ node := TreeFind(curScope^.root, name);
|
|
|
+ IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
|
|
|
+ node^.plink := NIL; (* implementation re-enters formals *)
|
|
|
+ curProc := node;
|
|
|
+ curPTail := NIL;
|
|
|
+ PushProc(node);
|
|
|
+ PushScope;
|
|
|
+ RETURN TRUE
|
|
|
+ END ResumeProc;
|
|
|
+
|
|
|
PROCEDURE ReenterProc (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
VAR node: SymPtr;
|
|
|
BEGIN
|
|
|
@@ -1071,6 +1095,263 @@ PROCEDURE VarParamOk (actual, formal: TypeIndex): BOOLEAN;
|
|
|
RETURN FALSE
|
|
|
END VarParamOk;
|
|
|
|
|
|
+(* ---------------- modules / separate compilation (step 4.3) ---------------- *)
|
|
|
+
|
|
|
+PROCEDURE EnterIn (s: ScopePtr; name: ARRAY OF CHAR;
|
|
|
+ kind: INTEGER): BOOLEAN;
|
|
|
+ VAR node: SymPtr;
|
|
|
+ BEGIN
|
|
|
+ ALLOCATE(node, TSIZE(SymNode));
|
|
|
+ Assign(node^.name, name);
|
|
|
+ node^.kind := kind;
|
|
|
+ node^.typ := InvalidType;
|
|
|
+ node^.scope := s;
|
|
|
+ node^.left := NIL;
|
|
|
+ node^.right := NIL;
|
|
|
+ node^.rslt := InvalidType;
|
|
|
+ node^.plink := NIL;
|
|
|
+ node^.isVar := FALSE;
|
|
|
+ node^.fwd := FALSE;
|
|
|
+ node^.virt := FALSE;
|
|
|
+ node^.fdep := 0;
|
|
|
+ node^.uid := 0;
|
|
|
+ IF ~TreeInsert(s, node) THEN RETURN FALSE END;
|
|
|
+ RETURN TRUE
|
|
|
+ END EnterIn;
|
|
|
+
|
|
|
+PROCEDURE FindMod (name: ARRAY OF CHAR): INTEGER;
|
|
|
+ VAR i : CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ i := 0;
|
|
|
+ WHILE i < nMods DO
|
|
|
+ IF Equal(modNames[i], name) THEN RETURN VAL(INTEGER, i) END;
|
|
|
+ INC(i)
|
|
|
+ END;
|
|
|
+ RETURN -1
|
|
|
+ END FindMod;
|
|
|
+
|
|
|
+PROCEDURE NewMod (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
|
|
|
+ VAR idx : CARDINAL;
|
|
|
+ s : ScopePtr;
|
|
|
+ BEGIN
|
|
|
+ IF nMods >= MaxMods THEN RETURN FALSE END;
|
|
|
+ IF FindMod(name) # -1 THEN RETURN FALSE END;
|
|
|
+ idx := nMods;
|
|
|
+ Assign(modNames[idx], name);
|
|
|
+ s := NewScope(globScope, 1);
|
|
|
+ modScopes[idx] := s;
|
|
|
+ modKind[idx] := kind;
|
|
|
+ modImpl[idx] := FALSE;
|
|
|
+ INC(nMods);
|
|
|
+ (* the module name lives in the global scope *)
|
|
|
+ IF ~EnterIn(globScope, name, KindModule) THEN
|
|
|
+ DEC(nMods); RETURN FALSE
|
|
|
+ END;
|
|
|
+ curMod := VAL(INTEGER, idx);
|
|
|
+ curUnit := kind;
|
|
|
+ curScope := s;
|
|
|
+ RETURN TRUE
|
|
|
+ END NewMod;
|
|
|
+
|
|
|
+PROCEDURE BeginDef (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ RETURN NewMod(name, UnitDef)
|
|
|
+ END BeginDef;
|
|
|
+
|
|
|
+PROCEDURE BeginImpl (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR idx : INTEGER;
|
|
|
+ BEGIN
|
|
|
+ idx := FindMod(name);
|
|
|
+ IF idx = -1 THEN RETURN FALSE END;
|
|
|
+ IF (modKind[idx] # UnitDef) OR modImpl[idx] THEN RETURN FALSE END;
|
|
|
+ modImpl[idx] := TRUE;
|
|
|
+ curMod := idx;
|
|
|
+ curUnit := UnitImpl;
|
|
|
+ curScope := modScopes[idx];
|
|
|
+ RETURN TRUE
|
|
|
+ END BeginImpl;
|
|
|
+
|
|
|
+PROCEDURE BeginProg (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR ok : BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ ok := NewMod(name, UnitProg);
|
|
|
+ IF ok THEN haveProg := TRUE END;
|
|
|
+ RETURN ok
|
|
|
+ END BeginProg;
|
|
|
+
|
|
|
+PROCEDURE HaveProgram (): BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ RETURN haveProg
|
|
|
+ END HaveProgram;
|
|
|
+
|
|
|
+PROCEDURE EndUnit;
|
|
|
+ BEGIN
|
|
|
+ curScope := globScope;
|
|
|
+ curMod := -1;
|
|
|
+ curUnit := -1
|
|
|
+ END EndUnit;
|
|
|
+
|
|
|
+PROCEDURE CurUnit (): INTEGER;
|
|
|
+ BEGIN
|
|
|
+ RETURN curUnit
|
|
|
+ END CurUnit;
|
|
|
+
|
|
|
+PROCEDURE CurModule (VAR name: Name);
|
|
|
+ BEGIN
|
|
|
+ IF curMod < 0 THEN name[0] := 0C
|
|
|
+ ELSE Assign(name, modNames[curMod])
|
|
|
+ END
|
|
|
+ END CurModule;
|
|
|
+
|
|
|
+PROCEDURE ModKnown (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ RETURN FindMod(name) # -1
|
|
|
+ END ModKnown;
|
|
|
+
|
|
|
+PROCEDURE ModDefined (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR i : INTEGER;
|
|
|
+ BEGIN
|
|
|
+ i := FindMod(name);
|
|
|
+ RETURN (i # -1) & (modKind[i] # UnitProg)
|
|
|
+ END ModDefined;
|
|
|
+
|
|
|
+PROCEDURE ModImplemented (name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR i : INTEGER;
|
|
|
+ BEGIN
|
|
|
+ i := FindMod(name);
|
|
|
+ RETURN (i # -1) & modImpl[i]
|
|
|
+ END ModImplemented;
|
|
|
+
|
|
|
+PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
|
|
|
+ VAR node: SymPtr;
|
|
|
+ r : TypeIndex;
|
|
|
+ BEGIN
|
|
|
+ node := Find(name);
|
|
|
+ IF (node = NIL) OR (node^.kind # KindType) THEN
|
|
|
+ RETURN InvalidType
|
|
|
+ END;
|
|
|
+ r := node^.typ;
|
|
|
+ IF (r < 0) OR (r >= VAL(INTEGER, nTypes)) THEN
|
|
|
+ RETURN InvalidType
|
|
|
+ END;
|
|
|
+ IF (tform[r] = FAlias) & (tref[r] = InvalidType) THEN RETURN r END;
|
|
|
+ RETURN InvalidType
|
|
|
+ END OpaqueBase;
|
|
|
+
|
|
|
+PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
|
|
|
+ VAR i : INTEGER;
|
|
|
+ BEGIN
|
|
|
+ i := FindMod(mod);
|
|
|
+ IF i = -1 THEN RETURN NIL END;
|
|
|
+ RETURN TreeFind(modScopes[i]^.root, name)
|
|
|
+ END QualNode;
|
|
|
+
|
|
|
+PROCEDURE QualFind (mod, name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ RETURN QualNode(mod, name) # NIL
|
|
|
+ END QualFind;
|
|
|
+
|
|
|
+PROCEDURE QualKind (mod, name: ARRAY OF CHAR): INTEGER;
|
|
|
+ VAR n : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF n = NIL THEN RETURN -1 END;
|
|
|
+ RETURN n^.kind
|
|
|
+ END QualKind;
|
|
|
+
|
|
|
+PROCEDURE QualType (mod, name: ARRAY OF CHAR): TypeIndex;
|
|
|
+ VAR n : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF n = NIL THEN RETURN InvalidType END;
|
|
|
+ RETURN n^.typ
|
|
|
+ END QualType;
|
|
|
+
|
|
|
+PROCEDURE QualProcUid (mod, name: ARRAY OF CHAR): CARDINAL;
|
|
|
+ VAR n : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
|
|
|
+ RETURN n^.uid
|
|
|
+ END QualProcUid;
|
|
|
+
|
|
|
+PROCEDURE QualNthParam (n: SymPtr; i: CARDINAL): SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := n^.plink;
|
|
|
+ WHILE (i > 0) & (n # NIL) DO
|
|
|
+ n := n^.plink; DEC(i)
|
|
|
+ END;
|
|
|
+ RETURN n
|
|
|
+ END QualNthParam;
|
|
|
+
|
|
|
+PROCEDURE QualProcNPar (mod, name: ARRAY OF CHAR): CARDINAL;
|
|
|
+ VAR n, p : SymPtr;
|
|
|
+ c : CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
|
|
|
+ c := 0; p := n^.plink;
|
|
|
+ WHILE p # NIL DO INC(c); p := p^.plink END;
|
|
|
+ RETURN c
|
|
|
+ END QualProcNPar;
|
|
|
+
|
|
|
+PROCEDURE QualParamType (mod, name: ARRAY OF CHAR; i: CARDINAL):
|
|
|
+ TypeIndex;
|
|
|
+ VAR n, p : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF (n = NIL) OR (n^.kind # KindProc) THEN
|
|
|
+ RETURN InvalidType
|
|
|
+ END;
|
|
|
+ p := QualNthParam(n, i);
|
|
|
+ IF p = NIL THEN RETURN InvalidType END;
|
|
|
+ RETURN p^.typ
|
|
|
+ END QualParamType;
|
|
|
+
|
|
|
+PROCEDURE QualParamIsVar (mod, name: ARRAY OF CHAR; i: CARDINAL):
|
|
|
+ BOOLEAN;
|
|
|
+ VAR n, p : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN FALSE END;
|
|
|
+ p := QualNthParam(n, i);
|
|
|
+ IF p = NIL THEN RETURN FALSE END;
|
|
|
+ RETURN p^.isVar
|
|
|
+ END QualParamIsVar;
|
|
|
+
|
|
|
+PROCEDURE QualProcRes (mod, name: ARRAY OF CHAR): TypeIndex;
|
|
|
+ VAR n : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ n := QualNode(mod, name);
|
|
|
+ IF (n = NIL) OR (n^.kind # KindProc) THEN
|
|
|
+ RETURN InvalidType
|
|
|
+ END;
|
|
|
+ RETURN n^.rslt
|
|
|
+ END QualProcRes;
|
|
|
+
|
|
|
+PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+(* Clones mod's export into the current scope (qualified-access
|
|
|
+ flattening and FROM-import share this). *)
|
|
|
+ VAR src, node : SymPtr;
|
|
|
+ BEGIN
|
|
|
+ src := QualNode(mod, name);
|
|
|
+ IF src = NIL THEN RETURN FALSE END;
|
|
|
+ (* already visible (repeat L.x): nothing to do *)
|
|
|
+ IF TreeFind(curScope^.root, name) # NIL THEN RETURN TRUE END;
|
|
|
+ ALLOCATE(node, TSIZE(SymNode));
|
|
|
+ node^ := src^;
|
|
|
+ node^.left := NIL;
|
|
|
+ node^.right := NIL;
|
|
|
+ node^.scope := curScope;
|
|
|
+ IF ~TreeInsert(curScope, node) THEN RETURN FALSE END;
|
|
|
+ RETURN TRUE
|
|
|
+ END Materialize;
|
|
|
+
|
|
|
+PROCEDURE ImportFrom (mod, name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ BEGIN
|
|
|
+ RETURN Materialize(mod, name)
|
|
|
+ END ImportFrom;
|
|
|
+
|
|
|
(* ---------------- predicates (unchanged) ---------------- *)
|
|
|
|
|
|
PROCEDURE BaseSpanOk (b: TypeIndex): BOOLEAN;
|
|
|
@@ -1269,7 +1550,9 @@ PROCEDURE Init;
|
|
|
nPend := 0; nPendF := 0;
|
|
|
nTypes := 0; nProc := 0; nBounds := 0; nextUid := 0;
|
|
|
curProc := NIL; curPTail := NIL;
|
|
|
+ nMods := 0; curMod := -1; curUnit := -1; haveProg := FALSE;
|
|
|
curScope := NewScope(NIL, 0);
|
|
|
+ globScope := curScope;
|
|
|
dInt := NewDesc(FInt, InvalidType);
|
|
|
dCard := NewDesc(FInt, InvalidType);
|
|
|
dReal := NewDesc(FReal, InvalidType);
|