-- RTTSupportImpl.mesa
-- Last Modified On March 15, 1983 4:03 pm by Paul Rovner

DIRECTORY
AMTypes USING[Error],
AtomsPrivate USING[UnsafeMakeAtom],
BrandXSymbolDefs USING[SymbolTableBase, SymbolIndex, SymbolContextIndex, nullHandle,
StandardSymbolContextIndex, contextLevelZero, PreDefinedSEI],
BrandYSymbolDefs USING[SymbolTableBase, SymbolIndex, SymbolContextIndex, nullHandle,
StandardSymbolContextIndex, contextLevelZero, PreDefinedSEI],
ConvertUnsafe USING[ToRope],
FileSegment USING[Pages],
RCMap USING[Index],
NewRCMapOps USING[Acquire],
Rope USING[ROPE],
RTBasic USING[TypeIndex],
RTOS USING[UnRavelUSUs],
RTMiniModel USING[], -- EXPORTS only
RTSymbolDefs USING[SymbolTableHandle, nullHandle, SymbolTableBase, SymbolIndex,
SymbolRecordIndex, SymbolNameIndex, nullBase,
SymbolConstructorIndex, nullSymbolIndex, SymbolIdIndex,
symbolIndexForANY],
RTSymbolOps USING[EnumerateCtxIseis, PeelAllButLast, SEUnderType, SETagIDP, NullISEI,
SubStringForHash, IsSequence, NullStb, NullSth, ISEName],
RTSymbols USING[Outer, AcquireSTBFromMDI, AcquireSTB, ReleaseSTB],
RTSymbolsPrivate USING[AcquireSTHFromSTX, GetSTHForModule],
RTTypesBasic USING[Type, nullType, unspecType, listOfRefAnyType, refAnyType, anyType],
RTTypesBasicPrivate USING[PTypeDesc, TypeStructure, UniqueTypeFinger, SymbolAccess,
MapStiStd, STDesc, MakeNewType, MapTiTd, GetLastTypeIndex,
FindCanonicalPTD, Enter, FindPTD, SymbolTableIndex, FindSTI],
Space USING[Handle, GetHandle, WindowOrigin, GetWindow, GetAttributes,
PageFromLongPointer],
Strings USING[SubString, EqualSubStrings, SubStringDescriptor, AppendSubString],
TimeStamp USING[Null, Stamp],
TypeStrings USING[Create],
UnsafeStorage USING[NewUZone];


RTTSupportImpl: PROGRAM
IMPORTS AMTypes, AtomsPrivate, ConvertUnsafe, NewRCMapOps, RTOS, RTSymbolOps,
RTSymbols, RTSymbolsPrivate, RTTypesBasicPrivate, Space, Strings,
TypeStrings, UnsafeStorage
EXPORTS RTSymbolOps, RTSymbols

= BEGIN OPEN bx: BrandXSymbolDefs, by: BrandYSymbolDefs,
XRCMapOps: NewRCMapOps, YRCMapOps: NewRCMapOps,
XTypeStrings: TypeStrings, YTypeStrings: TypeStrings,
Rope, RTSymbolDefs, RTSymbolOps, RTSymbols, RTSymbolsPrivate, RTBasic,
RTTypesBasic, RTTypesBasicPrivate;


standardXSTH: SymbolTableHandle ← [x[bx.nullHandle]];
standardYSTH: SymbolTableHandle ← [y[by.nullHandle]];

typeStringZone: UNCOUNTED ZONE = UnsafeStorage.NewUZone[];

-- *****************************
-- S U P P O R T F O R T H E D E B U G G E R

AcquireType: PUBLIC PROC[stb: SymbolTableBase,
seIndex: SymbolIndex,
canonicalize: BOOLFALSE,
rcmi: RCMap.Index ← LAST[RCMap.Index]]
RETURNS[type: Type] = {inner: PROC =
{ ptd: PTypeDesc;
utf: UniqueTypeFinger;
ustb: SymbolTableBase;
usei: SymbolIndex;
csei: SymbolConstructorIndex = SEUnderType[stb, seIndex];
isConsType: BOOL = NOT SETagIDP[stb, seIndex];

MakePredefinedType: PROC[preType: Type] =
INLINE{utf: UniqueTypeFinger;
ustb: SymbolTableBase;
usei: SymbolIndex;
std: STDesc;

[utf, ustb, usei] ← ComputeUTF[stb, seIndex];
std ← STDescFromSTB[ustb];
IF stb # ustb THEN ReleaseSTB[ustb];
IF rcmi = LAST[RCMap.Index]
THEN {rcmi ← WITH stb SELECT FROM
t: SymbolTableBase.x =>
XRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.x].e
! ANY => GOTO rcMapAcquisitionError],
t: SymbolTableBase.y =>
YRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.y].e
! ANY => GOTO rcMapAcquisitionError],
ENDCASE => ERROR;
EXITS rcMapAcquisitionError =>
ERROR AMTypes.Error[reason: notImplemented,
msg: "RCMaps for this type"]};
[] ← MakeNewType
[utf, std, usei,
WITH stb SELECT FROM
t: SymbolTableBase.x =>
XTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.x].e,
typeStringZone],
t: SymbolTableBase.y =>
YTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.y].e,
typeStringZone],
ENDCASE => ERROR,
rcmi, FALSE, preType]};

IF NullISEI[LOOPHOLE[seIndex]] THEN ERROR;
IF csei = symbolIndexForANY THEN
{IF MapTiTd[unspecType] = NIL THEN MakePredefinedType[unspecType];
type ← unspecType;
RETURN};

IF isConsType THEN
{ isListOfRefAny: BOOLFALSE;
isRefAny: BOOLFALSE;
isAny: BOOLFALSE;

WITH stb SELECT FROM
t: SymbolTableBase.x =>
WITH ser: t.e.seb[NARROW[csei, SymbolConstructorIndex.x].e] SELECT FROM
-- long => WITH rse: t.e.seb[t.e.UnderType[ser.rangeType]] SELECT FROM
-- ref => IF rse.counted
-- THEN IF rse.list
-- THEN NULL
--someday figure out whether this is a LORA
-- ELSE IF t.e.seb[t.e.UnderType[rse.refType]].typeTag = any
-- THEN isRefAny ← TRUE;
-- ENDCASE;
any => isAny ← TRUE;
ENDCASE;
t: SymbolTableBase.y =>
WITH ser: t.e.seb[NARROW[csei, SymbolConstructorIndex.y].e] SELECT FROM
-- long => WITH rse: t.e.seb[t.e.UnderType[ser.rangeType]] SELECT FROM
-- ref => IF rse.counted
-- THEN IF rse.list
-- THEN NULL
--someday figure out whether this is a LORA
-- ELSE IF t.e.seb[t.e.UnderType[rse.refType]].typeTag = any
-- THEN isRefAny ← TRUE;
-- ENDCASE;
any => isAny ← TRUE;
ENDCASE;
ENDCASE => ERROR;

IF isListOfRefAny THEN
{IF MapTiTd[listOfRefAnyType] = NIL THEN MakePredefinedType[listOfRefAnyType];
type ← listOfRefAnyType;
RETURN};

IF isRefAny THEN
{IF MapTiTd[refAnyType] = NIL THEN MakePredefinedType[refAnyType];
type ← refAnyType;
RETURN};

IF isAny THEN
{IF MapTiTd[anyType] = NIL THEN MakePredefinedType[anyType];
type ← anyType;
RETURN}};
IF canonicalize
THEN {ts: TypeStructure;
[ptd, ts, utf] ← FindCanonicalType[stb, csei]; -- ts new storage only if ptd = NIL
IF ptd # NIL
THEN {type ← ptd.equivalentType; RETURN}
ELSE {std: STDesc = STDescFromSTB[stb];
IF rcmi = LAST[RCMap.Index]
THEN
{rcmi ← WITH stb SELECT FROM
t: SymbolTableBase.x =>
XRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.x].e
! ANY => GOTO rcMapAcquisitionError],
t: SymbolTableBase.y =>
YRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.y].e
! ANY => GOTO rcMapAcquisitionError],
ENDCASE => ERROR;
EXITS rcMapAcquisitionError =>
ERROR AMTypes.Error[reason: notImplemented,
msg: "RCMaps for this type"]};
type ← MakeNewType[utf, std, LOOPHOLE[csei, SymbolIndex],
ts, rcmi, TRUE];
RETURN}}
ELSE { IF NOT isConsType
THEN seIndex ← LOOPHOLE[PeelAllButLast[stb, LOOPHOLE[seIndex,
SymbolIdIndex]],
SymbolIndex];
[ptd, utf, ustb, usei] ← FindUTF[stb, seIndex];
IF ptd # NIL
THEN {IF stb # ustb THEN ReleaseSTB[ustb];
type ← ptd.myType;
RETURN}
ELSE {std: STDesc = STDescFromSTB[ustb];
IF stb # ustb THEN ReleaseSTB[ustb];
IF rcmi = LAST[RCMap.Index]
THEN {rcmi ←
WITH stb SELECT FROM
t: SymbolTableBase.x =>
XRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.x].e
! ANY => GOTO rcMapAcquisitionError],
t: SymbolTableBase.y =>
YRCMapOps.Acquire
[t.e, NARROW[csei, SymbolConstructorIndex.y].e
! ANY => GOTO rcMapAcquisitionError],
ENDCASE => ERROR;
EXITS rcMapAcquisitionError =>
ERROR AMTypes.Error[reason: notImplemented,
msg: "RCMaps for this type"]};
type ← MakeNewType
[utf, std, usei,
WITH stb SELECT FROM
t: SymbolTableBase.x =>
XTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.x].e,
typeStringZone],
t: SymbolTableBase.y =>
YTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.y].e,
typeStringZone],
ENDCASE => ERROR,
rcmi];
RETURN}}};
Enter[inner ! ANY => GOTO unwind];
EXITS unwind => ERROR};

AcquireSequenceType: PUBLIC PROC[stb: SymbolTableBase,
sei: SymbolIndex, -- of sequence part
recordSTB: SymbolTableBase,
recordSEIndex: SymbolRecordIndex]
RETURNS[type: Type] = {inner: PROC =
{ ptd: PTypeDesc;
utf: UniqueTypeFinger;
ustb: SymbolTableBase;
usei: SymbolIndex;
csei: SymbolConstructorIndex = SEUnderType[stb, sei];

IF NOT IsSequence[stb, sei] THEN ERROR;

IF SETagIDP[stb, sei]
THEN sei ← LOOPHOLE[PeelAllButLast[stb, LOOPHOLE[sei, SymbolIdIndex]], SymbolIndex];

[ptd, utf, ustb, usei] ← FindUTF[stb, sei];
IF ptd # NIL
THEN {IF stb # ustb THEN ReleaseSTB[ustb];
type ← ptd.myType}
ELSE {rcmi: RCMap.Index;
std: STDesc = STDescFromSTB[ustb];
{rcmi ← WITH recordSTB SELECT FROM
t: SymbolTableBase.x =>
XRCMapOps.Acquire
[t.e, NARROW[recordSEIndex, SymbolRecordIndex.x].e
! ANY => GOTO rcMapAcquisitionError],
t: SymbolTableBase.y =>
YRCMapOps.Acquire
[t.e, NARROW[recordSEIndex, SymbolRecordIndex.y].e
! ANY => GOTO rcMapAcquisitionError],
ENDCASE => ERROR;
EXITS rcMapAcquisitionError =>
ERROR AMTypes.Error[reason: notImplemented,
msg: "RCMaps for this type"]};
IF stb # ustb THEN ReleaseSTB[ustb];
type ← MakeNewType
[utf,
std,
usei,
WITH recordSTB SELECT FROM
t: SymbolTableBase.x =>
XTypeStrings.Create
[t.e,
NARROW[recordSEIndex, SymbolRecordIndex.x].e,
typeStringZone],
t: SymbolTableBase.y =>
YTypeStrings.Create
[t.e,
NARROW[recordSEIndex, SymbolRecordIndex.y].e,
typeStringZone],
ENDCASE => ERROR,
rcmi]}};
Enter[inner ! ANY => GOTO unwind];
EXITS unwind => ERROR};

AcquireRope: PUBLIC PROC[stb: SymbolTableBase, hti: SymbolNameIndex]
RETURNS[ROPE] =
{ a: Strings.SubStringDescriptor;
s: STRING = [100];
SubStringForHash[stb, @a, hti];
s.length ← 0;
Strings.AppendSubString[s, @a];
RETURN[ConvertUnsafe.ToRope[LONG[s]]]};

AcquireAtom: PUBLIC PROC[stb: SymbolTableBase, hti: SymbolNameIndex]
RETURNS[atom: ATOM] =
{ a: Strings.SubStringDescriptor;
s: STRING = [100];
SubStringForHash[stb, @a, hti];
s.length ← 0;
Strings.AppendSubString[s, @a];
RETURN[AtomsPrivate.UnsafeMakeAtom[LOOPHOLE[LONG[s]]]]};

EnumerateTypes: PROC[p: PROC[Type] RETURNS[stop: BOOL]]
RETURNS[stopped: BOOLFALSE] =
{FOR t: TypeIndex IN [FIRST[TypeIndex]..GetLastTypeIndex[]]
DO IF p[[t]] THEN RETURN[TRUE] ENDLOOP};

GetTypeSymbols: PUBLIC PROC[type: Type]
RETURNS[stb: SymbolTableBase, sei: SymbolIndex] =
{ moduleName: ROPE;
IF type = nullType THEN ERROR AMTypes.Error[reason: typeFault, type: type];
[stb, sei, moduleName] ← DoGetTypeSymbols[type];
IF NullStb[stb] THEN ERROR AMTypes.Error[reason: noSymbols, msg: moduleName]};

GetOriginalTypeSymbols: PUBLIC PROC[type: Type]
RETURNS[stb: SymbolTableBase, sei: SymbolIndex] =
{ IF type = nullType THEN ERROR AMTypes.Error[reason: typeFault, type: type];
[stb, sei,] ← DoGetTypeSymbols[type, TRUE];
IF NullStb[stb] THEN ERROR AMTypes.Error[reason: noSymbols]};

IsPreDefinedSEI: PROC[sei: SymbolIndex] RETURNS[BOOL] =
{RETURN[WITH sei SELECT FROM
t: SymbolIndex.x => LOOPHOLE[t.e, CARDINAL] IN bx.PreDefinedSEI,
t: SymbolIndex.y => LOOPHOLE[t.e, CARDINAL] IN by.PreDefinedSEI,
ENDCASE => ERROR]};

DoGetTypeSymbols: PROC[type: Type, originalOnly: BOOLFALSE]
RETURNS[stb: SymbolTableBase, sei: SymbolIndex, moduleName: ROPENIL] =
{stInfo: SymbolAccess = MapTiTd[type].symbolAccess;
sth: SymbolTableHandle ← IF originalOnly
THEN nullHandle
ELSE MapStiStd[stInfo.sti].sth;

sei ← IF originalOnly THEN MapTiTd[type].utf.seIndex ELSE stInfo.sei;
IF NullSth[sth]
THEN IF IsPreDefinedSEI[sei]
THEN -- standard symbol; any table will do
{IF NOT (IF sei.brand = x
THEN NullSth[standardXSTH]
ELSE NullSth[standardYSTH])
THEN sth ← (IF sei.brand = x THEN standardXSTH ELSE standardYSTH)
ELSE FOR i: SymbolTableIndex IN [1..MapStiStd.length)
DO IF MapStiStd[i] = NIL
THEN LOOP
ELSE IF NOT NullSth[MapStiStd[i].sth]
THEN {sth ← MapStiStd[i].sth; EXIT}
ELSE { -- go find the symbol table bits
[sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[i];
MapStiStd[i].sth ← sth;
IF NOT NullSth[sth] THEN EXIT}; -- found one.
ENDLOOP;
}
ELSE -- go find the symbol table bits
{IF originalOnly
THEN sth ← GetSTHForModule
[MapTiTd[type].utf.umid, NIL, NIL
! AMTypes.Error => CONTINUE]
ELSE
{[sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[stInfo.sti];
MapStiStd[stInfo.sti].sth ← sth;
IF NullSth[sth]
THEN -- try for the original defining module
{ std: STDesc = [symbolsStamp: MapTiTd[type].utf.umid,
bcd: MapStiStd[stInfo.sti].bcd];
sei ← MapTiTd[type].utf.seIndex;
IF IsPreDefinedSEI[sei]
THEN
{IF NOT (IF sei.brand = x
THEN NullSth[standardXSTH]
ELSE NullSth[standardYSTH])
THEN sth ← (IF sei.brand = x
THEN standardXSTH
ELSE standardYSTH)
ELSE FOR i: SymbolTableIndex IN [1..MapStiStd.length)
DO IF MapStiStd[i] = NIL
THEN LOOP
ELSE IF NOT NullSth[MapStiStd[i].sth]
THEN {sth ← MapStiStd[i].sth; EXIT}
ELSE { -- go find the symbol table bits
[sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[i];
MapStiStd[i].sth ← sth;
IF NOT NullSth[sth] THEN EXIT}; -- found one.
ENDLOOP;
}
ELSE [sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[FindSTI[std]];
}};
};
IF NullSth[sth]
THEN stb ← nullBase
ELSE {WITH sth SELECT FROM
t: SymbolTableHandle.x =>
IF NullSth[standardXSTH] THEN standardXSTH ← sth;
t: SymbolTableHandle.y =>
IF NullSth[standardYSTH] THEN standardYSTH ← sth;
ENDCASE => ERROR;
stb ← AcquireSTB[sth]};
};

-- Creation of new runtime Type descriptors

-- ts new storage only if ptd = NIL
FindCanonicalType: PROC[stb: SymbolTableBase, csei: SymbolConstructorIndex]
RETURNS[ptd: PTypeDesc, ts: TypeStructure, utf: UniqueTypeFinger] =
{ ts ← WITH stb SELECT FROM
t: SymbolTableBase.x => XTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.x].e,
typeStringZone],
t: SymbolTableBase.y => YTypeStrings.Create
[t.e,
NARROW[csei, SymbolConstructorIndex.y].e,
typeStringZone],
ENDCASE => ERROR;
ptd ← FindCanonicalPTD[ts];
IF ptd # NIL
THEN {typeStringZone.FREE[@ts]; RETURN[ptd, ptd.typeStructure, ptd.utf]}
ELSE {[utf,,] ← ComputeUTF[stb, LOOPHOLE[csei, SymbolIndex]]; RETURN[NIL, ts, utf]}};

-- Recognize identical type previously entered
-- hash map: UniqueTypeFinger -> TypeIndex

FindUTF: PROC [stb: SymbolTableBase, sei: SymbolIndex]
RETURNS[ptd: PTypeDesc,
utf: UniqueTypeFinger,
ustb: SymbolTableBase,
usei: SymbolIndex] =
{ [utf, ustb, usei] ← ComputeUTF[stb, sei];
RETURN[FindPTD[utf], utf, ustb, usei]};

-- ComputeUTF might return a new (ustb, usei) only if sei is a SymbolIdIndex
ComputeUTF: PROC [outerSTB: SymbolTableBase, sei: SymbolIndex]
RETURNS[utf: UniqueTypeFinger, ustb: SymbolTableBase, usei: SymbolIndex] =
{ WITH outerSTB SELECT FROM
t: SymbolTableBase.x =>
[utf, ustb, usei] ← ComputeUTFX[t.e, NARROW[sei, SymbolIndex.x].e];
t: SymbolTableBase.y =>
[utf, ustb, usei] ← ComputeUTFY[t.e, NARROW[sei, SymbolIndex.y].e];
ENDCASE => ERROR};

ComputeUTFX: PROC [outerSTB: bx.SymbolTableBase, sei: bx.SymbolIndex]
RETURNS[utf: UniqueTypeFinger, ustb: SymbolTableBase, usei: SymbolIndex] =
{ ustb ← [x[outerSTB]];
usei ← [x[sei]];
WITH ser: outerSTB.seb[sei] SELECT FROM
id => IF ser.idCtx IN bx.StandardSymbolContextIndex
THEN utf ← [umid: TimeStamp.Null, seIndex: usei] -- a primitive type
ELSE
WITH ctxr: outerSTB.ctxb[ser.idCtx] SELECT FROM
included =>
IF ctxr.level # bx.contextLevelZero
THEN utf ← [umid: outerSTB.mdb[ctxr.module].stamp,
seIndex: [x[LOOPHOLE[ser.idValue, bx.SymbolIndex]]]]
ELSE
{ inner: PROC[stb: SymbolTableBase] =
{ p: PROC[stb: SymbolTableBase, isei: SymbolIdIndex]
RETURNS[stop: BOOL] =
{ ssd1: Strings.SubStringDescriptor;
ssd2: Strings.SubStringDescriptor;
ss1: Strings.SubString = @ssd1;
ss2: Strings.SubString = @ssd2;
SubStringForHash[[x[outerSTB]], ss1, [x[ser.hash]]];
SubStringForHash[stb, ss2, ISEName[stb, isei]];
IF Strings.EqualSubStrings[ss1, ss2]
THEN
{utf ← [umid: NARROW[stb, SymbolTableBase.x].e.stHandle.version,
seIndex: LOOPHOLE[isei, SymbolIndex]];
usei ← LOOPHOLE[isei, SymbolIndex];
RETURN[TRUE]}
ELSE RETURN[FALSE];
};
IF NOT EnumerateCtxIseis[stb: stb, ctx: [x[ctxr.map]], proc: p]
THEN ERROR;
};
Outer[stb: [x[outerSTB]], mdi: [x[ctxr.module]], inner: inner];
ustb ← AcquireSTBFromMDI[[x[outerSTB]], [x[ctxr.module]]];
RETURN
};
ENDCASE => utf ← [umid: outerSTB.stHandle.version, seIndex: [x[sei]]];
cons => utf ← [umid: (IF IsPreDefinedSEI[[x[sei]]]
THEN TimeStamp.Null
ELSE outerSTB.stHandle.version), -- NOTE
seIndex: [x[sei]]];
ENDCASE => ERROR};

ComputeUTFY: PROC [outerSTB: by.SymbolTableBase, sei: by.SymbolIndex]
RETURNS[utf: UniqueTypeFinger, ustb: SymbolTableBase, usei: SymbolIndex] =
{ ustb ← [y[outerSTB]];
usei ← [y[sei]];
WITH ser: outerSTB.seb[sei] SELECT FROM
id => IF ser.idCtx IN by.StandardSymbolContextIndex
THEN utf ← [umid: TimeStamp.Null, seIndex: usei] -- a primitive type
ELSE
WITH ctxr: outerSTB.ctxb[ser.idCtx] SELECT FROM
included =>
IF ctxr.level # by.contextLevelZero
THEN utf ← [umid: outerSTB.mdb[ctxr.module].stamp,
seIndex: [y[LOOPHOLE[ser.idValue, by.SymbolIndex]]]]
ELSE
{ inner: PROC[stb: SymbolTableBase] =
{ p: PROC[stb: SymbolTableBase, isei: SymbolIdIndex]
RETURNS[stop: BOOL] =
{ ssd1: Strings.SubStringDescriptor;
ssd2: Strings.SubStringDescriptor;
ss1: Strings.SubString = @ssd1;
ss2: Strings.SubString = @ssd2;
SubStringForHash[[y[outerSTB]], ss1, [y[ser.hash]]];
SubStringForHash[stb, ss2, ISEName[stb, isei]];
IF Strings.EqualSubStrings[ss1, ss2]
THEN
{utf ← [umid: NARROW[stb, SymbolTableBase.y].e.stHandle.version,
seIndex: LOOPHOLE[isei, SymbolIndex]];
usei ← LOOPHOLE[isei, SymbolIndex];
RETURN[TRUE]}
ELSE RETURN[FALSE];
};
IF NOT EnumerateCtxIseis[stb: stb, ctx: [y[ctxr.map]], proc: p]
THEN ERROR;
};
Outer[stb: [y[outerSTB]], mdi: [y[ctxr.module]], inner: inner];
ustb ← AcquireSTBFromMDI[[y[outerSTB]], [y[ctxr.module]]];
RETURN
};
ENDCASE => utf ← [umid: outerSTB.stHandle.version, seIndex: [y[sei]]];
cons => utf ← [umid: (IF IsPreDefinedSEI[[y[sei]]]
THEN TimeStamp.Null
ELSE outerSTB.stHandle.version), -- NOTE
seIndex: [y[sei]]];
ENDCASE => ERROR};

STDescFromSTB: PROC[stb: SymbolTableBase] RETURNS[STDesc] =
{ version: TimeStamp.Stamp;
space: Space.Handle;
window: Space.WindowOrigin;
sth: SymbolTableHandle;
p: LONG POINTER;
fsp: FileSegment.Pages;

WITH stb SELECT FROM
t: SymbolTableBase.x => {version ← t.e.stHandle.version; p ← t.e.stHandle};
t: SymbolTableBase.y => {version ← t.e.stHandle.version; p ← t.e.stHandle};
ENDCASE;
space ← RTOS.UnRavelUSUs[Space.GetHandle[Space.PageFromLongPointer[p]]];
window ← Space.GetWindow[space];
fsp ← [file: window.file, span: [base: window.base, pages: Space.GetAttributes[space].size]];
sth ← WITH stb SELECT FROM
t: SymbolTableBase.x => [x[fsp]],
t: SymbolTableBase.y => [y[fsp]],
ENDCASE => ERROR;
RETURN[[symbolsStamp: version, sth: sth]]};

END.