-- file Pass3I.Mesa
-- last modified by Satterthwaite, November 15, 1979 3:45 PM
DIRECTORY
ComData: FROM "comdata"
USING [definitionsOnly, moduleCtx, seAnon, switches, textIndex],
Copier: FROM "copier" USING [CompleteContext, Delink, SearchFileCtx],
InlineDefs: FROM "inlinedefs" USING [BITAND],
Log: FROM "log" USING [ErrorHti, ErrorSei, WarningSei, ErrorTree],
P3: FROM "p3"
USING [
Attr, FullAttr, VoidAttr, Mark, MergeNP,
currentArgCtx, phraseNP,
--And,-- Exp, LongPath, MakePointerType, OperandType,
ResolveType, ResolveValue, RPop, RPush, RType,
VariantUnionType, VoidExp],
Symbols: FROM "symbols"
USING [seType, ctxType, mdType, bodyType,
CTXRecord, ExtensionType,
MDIndex, HTIndex, SEIndex, ISEIndex, CSEIndex, RecordSEIndex,
CTXIndex, IncludedCTXIndex,
HTNull, ISENull, RecordSENull, CTXNull, IncludedCTXNull,
lG, lZ, StandardContext, typeTYPE, typeANY],
SymbolOps: FROM "symbolops"
USING [
ConstantId, EnterExtension, FindExtension, FirstCtxSe, LinkMode, NextSe,
NormalType, SearchContext, SetSeLink, UnderType],
SystemDefs: FROM "systemdefs"
USING [
AllocateHeapNode, AllocateSegment, FreeHeapNode, FreeSegment,
SegmentSize],
Table: FROM "table" USING [Base, Notifier, Allocate],
Tree: FROM "tree"
USING [Index, Link, Map, Scan, Test, Null, NullIndex, treeType],
TreeOps: FROM "treeops"
USING [
FreeNode, FreeTree, GetNode, IdentityMap, PopTree, PushTree, PushNode,
ScanList, SearchList, SetAttr, SetInfo, SetShared, TestTree,
UpdateList, UpdateTree];
Pass3I: PROGRAM
IMPORTS
InlineDefs, Copier, Log, P3, SymbolOps, SystemDefs, Table, TreeOps,
dataPtr: ComData
EXPORTS P3 =
BEGIN
OPEN SymbolOps, P3, Symbols, TreeOps;
And: PROCEDURE [Attr, Attr] RETURNS [Attr] = LOOPHOLE[InlineDefs.BITAND];
-- uninitialized variable processing
RefItem: TYPE = RECORD [kind: {seal, rhs, lhs}, sei: ISEIndex];
RefSeal: RefItem = [kind:seal, sei:ISENull];
refStack: DESCRIPTOR FOR ARRAY OF RefItem;
refIndex: CARDINAL;
AdjustRefStack: PROCEDURE [n: CARDINAL] =
BEGIN
i: CARDINAL;
oldStack: DESCRIPTOR FOR ARRAY OF RefItem ← refStack;
refStack ← DESCRIPTOR[SystemDefs.AllocateHeapNode[n*SIZE[RefItem]], n];
FOR i IN [0..refIndex) DO refStack[i] ← oldStack[i] ENDLOOP;
SystemDefs.FreeHeapNode[BASE[oldStack]];
END;
RecordMention: PUBLIC PROCEDURE [sei: ISEIndex] =
BEGIN
IF dataPtr.switches['u] AND
(seb[sei].idInfo = 0 AND ~seb[sei].mark4)
THEN
BEGIN
IF refIndex >= LENGTH[refStack]
THEN AdjustRefStack[LENGTH[refStack] + 8];
refStack[refIndex] ← [kind:rhs, sei:sei];
refIndex ← refIndex + 1;
END
ELSE BumpCount[sei];
END;
RecordLhs: PUBLIC PROCEDURE [sei: ISEIndex] =
BEGIN
i: CARDINAL;
key: RefItem;
IF dataPtr.switches['u] AND
(seb[sei].idInfo = 0 AND ~seb[sei].mark4)
THEN
BEGIN
key ← [kind:rhs, sei:sei];
FOR i DECREASING IN [0..refIndex)
DO
SELECT refStack[i] FROM
key => BEGIN refStack[i].kind ← lhs; EXIT END;
RefSeal => EXIT;
ENDCASE;
ENDLOOP;
END;
END;
SealRefStack: PUBLIC PROCEDURE =
BEGIN
IF refIndex >= LENGTH[refStack] THEN AdjustRefStack[LENGTH[refStack] + 8];
refStack[refIndex] ← RefSeal; refIndex ← refIndex + 1;
END;
UnsealRefStack: PUBLIC PROCEDURE =
BEGIN
ClearRefStack[]; refIndex ← refIndex - 1;
IF refStack[refIndex] # RefSeal THEN ERROR;
END;
ClearRefStack: PUBLIC PROCEDURE =
BEGIN
i: CARDINAL;
sei: ISEIndex;
FOR i DECREASING IN [0..refIndex) UNTIL refStack[i] = RefSeal
DO
sei ← refStack[i].sei;
IF refStack[i].kind = rhs
AND ~ConstantInit[sei]
AND (~dataPtr.definitionsOnly OR ctxb[seb[sei].idCtx].level # lG)
THEN Log.WarningSei[uninitialized, sei];
BumpCount[sei];
refIndex ← refIndex - 1;
ENDLOOP;
IF LENGTH[refStack] > 16 THEN AdjustRefStack[16];
END;
ConstantInit: PROCEDURE [sei: ISEIndex] RETURNS [BOOLEAN] =
BEGIN
node: Tree.Index;
IF seb[sei].constant THEN RETURN [TRUE];
node ← seb[sei].idValue;
RETURN [seb[sei].immutable
AND node # Tree.NullIndex AND TestTree[tb[node].son[3], body]]
END;
-- tables defining the current symbol table
tb: Table.Base; -- tree base
seb: Table.Base; -- se table
ctxb: Table.Base; -- context table
mdb: Table.Base; -- module directory base
bb: Table.Base; -- body directory base
IdNotify: PUBLIC Table.Notifier =
BEGIN -- called whenever the main symbol table is repacked
tb ← base[Tree.treeType];
seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType];
bb ← base[bodyType];
END;
-- identifier look-up
Id: PUBLIC PROCEDURE [hti: HTIndex] RETURNS [val: Tree.Link] =
BEGIN
sei: ISEIndex;
type: CSEIndex;
ctx: CTXIndex;
baseV: Tree.Link;
attr: Attr;
indirect: BOOLEAN;
attr ← VoidAttr;
[sei, baseV, indirect] ← FindSe[hti];
IF sei # ISENull
THEN
BEGIN
IF baseV = Tree.Null THEN RecordMention[sei] ELSE BumpCount[sei];
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
val ← [symbol[index: sei]]; type ← UnderType[seb[sei].idType];
ctx ← seb[sei].idCtx;
SELECT ctxb[ctx].ctxType FROM
included =>
BEGIN
attr.const ← ConstantId[sei];
IF baseV = Tree.Null AND (~attr.const OR LinkMode[sei] # manifest)
THEN Log.ErrorSei[notImported, sei];
END;
imported =>
BEGIN
IF seb[type].typeTag = pointer THEN
[val, type] ← DeRef[val, type];
attr.const ← FALSE;
END;
ENDCASE =>
BEGIN
IF ~ConstResolved[sei] THEN ResolveIdValue[sei];
attr.const ← seb[sei].constant;
END;
SELECT TRUE FROM
baseV = Tree.Null =>
BEGIN
IF ctx = currentArgCtx THEN phraseNP ← ref;
IF ctxb[ctx].level = lZ AND ~attr.const THEN
SELECT ctx FROM
IN StandardContext, dataPtr.moduleCtx => NULL;
ENDCASE => Log.ErrorSei[missingBase, sei];
END;
(~attr.const AND ctxb[ctx].ctxType # imported) =>
BEGIN
attr ← And[UpdateTreeAttr[baseV], attr];
PushTree[IdentityMap[baseV]]; PushTree[val];
IF indirect
THEN
BEGIN
PushNode[dot, 2];
SetAttr[2, seb[OperandType[baseV]].typeTag = long];
END
ELSE
BEGIN
PushNode[dollar, 2]; SetAttr[2, LongPath[baseV]];
END;
SetInfo[type]; val ← PopTree[];
END;
ENDCASE;
END
ELSE
BEGIN
attr ← And[UpdateTreeAttr[baseV], attr]; type ← OperandType[baseV];
IF indirect
THEN [val, type] ← DeRef[IdentityMap[baseV], type]
ELSE val ← IdentityMap[baseV];
END;
RPush[type, attr];
RETURN
END;
DeRef: PROCEDURE [t: Tree.Link, type: CSEIndex] RETURNS [Tree.Link, CSEIndex] =
BEGIN
rType: CSEIndex;
PushTree[t];
PushNode[uparrow, 1]; SetAttr[2, seb[type].typeTag = long];
type ← NormalType[type];
WITH seb[type] SELECT FROM
pointer => BEGIN dereferenced ← TRUE; rType ← UnderType[refType] END;
ENDCASE => rType ← typeANY;
SetInfo[rType];
RETURN [PopTree[], rType]
END;
FieldId: PUBLIC PROCEDURE [hti: HTIndex, type: RecordSEIndex]
RETURNS [n: CARDINAL, sei: ISEIndex] =
BEGIN
[n, sei] ← SearchRecord[hti, type];
IF n # 0
THEN
BEGIN
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
IF ~ConstResolved[sei] THEN ResolveIdValue[sei];
BumpCount[sei];
END;
RETURN
END;
DefinedId: PUBLIC PROCEDURE [hti: HTIndex, type: CSEIndex]
RETURNS [found: BOOLEAN, sei: ISEIndex] =
BEGIN
WITH seb[type] SELECT FROM
definition =>
BEGIN
[found, sei] ← SearchCtxList[hti, defCtx];
IF found THEN
BEGIN
SELECT ctxb[seb[sei].idCtx].ctxType FROM
imported => NULL;
included =>
IF ~ConstantId[sei] OR LinkMode[sei] # manifest
THEN Log.ErrorSei[notImported, sei];
ENDCASE =>
BEGIN
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
IF ~ConstResolved[sei] THEN ResolveIdValue[sei];
END;
BumpCount[sei];
END;
END;
ENDCASE => BEGIN found ← FALSE; sei ← ISENull END;
RETURN
END;
-- service routines for above
ConstResolved: PROCEDURE [sei: ISEIndex] RETURNS [BOOLEAN] = INLINE
BEGIN
RETURN [seb[sei].mark4 OR ~seb[sei].immutable OR seb[sei].constant]
END;
ResolveIdType: PROCEDURE [sei: ISEIndex] =
BEGIN
declNode: Tree.Index;
declNode ← seb[sei].idValue;
IF tb[declNode].attr3 # P3.Mark THEN ResolveType[sei];
END;
ResolveIdValue: PROCEDURE [sei: ISEIndex] =
BEGIN
declNode: Tree.Index;
declNode ← seb[sei].idValue;
IF seb[sei].mark3 AND tb[declNode].attr2 # P3.Mark THEN ResolveValue[sei];
END;
BumpCount: PUBLIC PROCEDURE [sei: ISEIndex] =
BEGIN OPEN seb[sei];
IF idType # typeTYPE AND
(~mark4 OR (ctxb[idCtx].ctxType = imported AND ~constant))
THEN idInfo ← idInfo + 1;
END;
-- keyed-list matching
CompleteRecord: PUBLIC PROCEDURE [rSei: RecordSEIndex] =
BEGIN
ctx: CTXIndex = seb[rSei].fieldCtx;
WITH ctxb[ctx] SELECT FROM
simple => NULL;
included =>
IF level = lZ
THEN Copier.CompleteContext[LOOPHOLE[ctx, IncludedCTXIndex], FALSE];
ENDCASE;
END;
ArrangeKeys: PUBLIC PROCEDURE [
expList: Tree.Link,
ctx: CTXIndex,
startSei, endSei: ISEIndex,
omittedKey: PROCEDURE [ISEIndex] RETURNS [Tree.Link]]
RETURNS [nItems: CARDINAL] =
BEGIN
Pair: TYPE = RECORD[
key: ISEIndex,
defined: BOOLEAN,
attr: Tree.Link];
i: CARDINAL;
aList: DESCRIPTOR FOR ARRAY OF Pair;
sei: ISEIndex;
KeyItem: Tree.Map =
BEGIN
node: Tree.Index;
hti: HTIndex;
i: CARDINAL;
WITH t SELECT FROM
subtree =>
BEGIN node ← index;
WITH tb[node].son[1] SELECT FROM
hash =>
BEGIN hti ← index;
FOR i IN [0 .. nItems)
DO
IF seb[aList[i].key].hash = hti THEN GO TO found;
REPEAT
found =>
IF ~aList[i].defined
THEN
BEGIN aList[i].attr ← tb[node].son[2];
tb[node].son[2] ← Tree.Null;
aList[i].defined ← TRUE;
END
ELSE
BEGIN Log.ErrorHti[duplicateKey, hti];
tb[node].son[2] ← P3.VoidExp[tb[node].son[2]];
END;
FINISHED =>
BEGIN Log.ErrorHti[unknownKey, hti];
tb[node].son[2] ← P3.VoidExp[tb[node].son[2]];
END;
ENDLOOP;
FreeNode[node];
END;
ENDCASE => ERROR;
END;
ENDCASE => ERROR;
RETURN [Tree.Null]
END;
nItems ← 0;
FOR sei ← startSei, NextSe[sei] UNTIL sei = endSei
DO IF seb[sei].idCtx = ctx THEN nItems ← nItems+1 ENDLOOP;
aList ← DESCRIPTOR[
SystemDefs.AllocateHeapNode[nItems*SIZE[Pair]],
nItems];
i ← 0;
FOR sei ← startSei, NextSe[sei] UNTIL sei = endSei
DO
IF seb[sei].idCtx = ctx
THEN
BEGIN
aList[i] ← Pair[key:sei, defined:FALSE, attr:Tree.Null]; i ← i+1;
END;
ENDLOOP;
expList ← FreeTree[UpdateList[expList, KeyItem]];
FOR i IN [0 .. nItems)
DO
PushTree[IF aList[i].defined
THEN aList[i].attr
ELSE omittedKey[aList[i].key]];
ENDLOOP;
SystemDefs.FreeHeapNode[BASE[aList]];
RETURN
END;
-- service routines for copying/mapping list structure
UpdateTreeAttr: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [attr: Attr] =
BEGIN -- traverses the tree, incrementing reference counts for ids
UpdateAttr: Tree.Map =
BEGIN
WITH t SELECT FROM
symbol =>
BEGIN
IF seb[index].idCtx = currentArgCtx
THEN phraseNP ← MergeNP[phraseNP][ref];
BumpCount[index];
END;
subtree =>
BEGIN
[] ← UpdateTree[t, UpdateAttr];
SELECT tb[index].name FROM
assign, assignx, extract =>
BEGIN
attr.noAssign ← FALSE; phraseNP ← MergeNP[phraseNP][set];
END;
IN [subst..join], IN [callx..joinx], substx =>
BEGIN
attr.noXfer ← FALSE; phraseNP ← MergeNP[phraseNP][set];
END;
ENDCASE => NULL;
END;
ENDCASE => NULL;
RETURN [t]
END;
attr ← FullAttr; phraseNP ← none; [] ← UpdateAttr[t];
attr.const ← FALSE; RETURN
END;
-- context stack management
ContextEntry: TYPE = RECORD[
base: Tree.Link, -- the basing expr (empty if none)
indirect: BOOLEAN, -- true iff basing expr is pointer
info: SELECT tag: * FROM
list => [ctx: CTXIndex], -- a single context
record => [rSei: RecordSEIndex], -- a group of contexts
hash => [ctxHti: HTIndex], -- a single identifier
ENDCASE];
ContextStack: TYPE = DESCRIPTOR FOR ARRAY OF ContextEntry;
ctxStack: ContextStack;
ctxIndex: INTEGER;
ContextIncr: CARDINAL = 25;
MakeStack: PROCEDURE [size: CARDINAL] RETURNS [ContextStack] =
BEGIN OPEN SystemDefs;
base: POINTER = AllocateSegment[size*SIZE[ContextEntry]];
RETURN [DESCRIPTOR[base, SegmentSize[base]/SIZE[ContextEntry]]]
END;
FreeStack: PROCEDURE [s: ContextStack] =
BEGIN
IF LENGTH [s] > 0 THEN SystemDefs.FreeSegment[BASE[s]];
END;
ExpandStack: PROCEDURE =
BEGIN
i: CARDINAL;
oldstack: ContextStack ← ctxStack;
ctxStack ← MakeStack[LENGTH[oldstack]+ContextIncr];
FOR i IN [0 .. LENGTH[oldstack]) DO ctxStack[i] ← oldstack[i] ENDLOOP;
FreeStack[oldstack];
END;
PushCtx: PUBLIC PROCEDURE [ctx: CTXIndex] =
BEGIN
IF (ctxIndex ← ctxIndex+1) >= LENGTH[ctxStack] THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:Tree.Null, indirect:FALSE, info:list[ctx]];
END;
SetCtxBase: PROCEDURE [base: Tree.Link, indirect: BOOLEAN] =
BEGIN
ctxStack[ctxIndex].base ← base; ctxStack[ctxIndex].indirect ← indirect;
END;
PushRecordCtx: PUBLIC PROCEDURE [rSei: RecordSEIndex, base: Tree.Link, indirect: BOOLEAN] =
BEGIN
IF (ctxIndex ← ctxIndex+1) >= LENGTH[ctxStack] THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:base, indirect:indirect, info:record[rSei]];
END;
UpdateRecordCtx: PUBLIC PROCEDURE [type: RecordSEIndex] =
BEGIN
WITH ctxStack[ctxIndex] SELECT FROM
record => rSei ← type;
ENDCASE => ERROR;
END;
PushHtCtx: PUBLIC PROCEDURE [hti: HTIndex, base: Tree.Link, indirect: BOOLEAN] =
BEGIN
IF (ctxIndex ← ctxIndex+1) >= LENGTH[ctxStack] THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:base, indirect:indirect, info:hash[hti]];
END;
PopCtx: PUBLIC PROCEDURE = BEGIN ctxIndex ← ctxIndex-1 END;
TopCtx: PUBLIC PROCEDURE RETURNS [CTXIndex] =
BEGIN
RETURN [WITH ctxStack[ctxIndex] SELECT FROM list => ctx, ENDCASE => ERROR]
END;
-- primary lookup
FindSe: PUBLIC PROCEDURE [hti: HTIndex] RETURNS [ISEIndex, Tree.Link, BOOLEAN] =
BEGIN
i: INTEGER;
found: BOOLEAN;
nHits: CARDINAL;
sei: ISEIndex;
FOR i DECREASING IN [0 .. ctxIndex]
DO
WITH s: ctxStack[i] SELECT FROM
list =>
BEGIN
[found, sei] ← SearchCtxList[hti, s.ctx];
IF found THEN GO TO Found;
END;
record =>
BEGIN
[nHits, sei] ← SearchRecord[hti, s.rSei];
SELECT nHits FROM
= 1 => GO TO Found;
> 1 => GO TO Ambiguous;
ENDCASE;
END;
hash => IF hti = s.ctxHti THEN BEGIN sei ← ISENull; GO TO Found END;
ENDCASE;
REPEAT
Found => RETURN [sei, ctxStack[i].base, ctxStack[i].indirect];
Ambiguous =>
BEGIN
Log.ErrorHti[ambiguousId, hti];
RETURN [dataPtr.seAnon, Tree.Null, FALSE]
END;
FINISHED =>
BEGIN
IF hti # HTNull THEN Log.ErrorHti[unknownId, hti];
RETURN [dataPtr.seAnon, Tree.Null, FALSE]
END;
ENDLOOP;
END;
SearchCtxList: PUBLIC PROCEDURE [hti: HTIndex, ctx: CTXIndex]
RETURNS [found: BOOLEAN, sei: ISEIndex] =
BEGIN
IF ctx = CTXNull THEN RETURN [FALSE, ISENull];
WITH c: ctxb[ctx] SELECT FROM
included =>
IF c.restricted
THEN
BEGIN
sei ← SearchRestrictedCtx[hti, LOOPHOLE[ctx]];
found ← (sei # ISENull);
IF found AND ~seb[sei].public AND ~mdb[c.module].shared
AND sei # dataPtr.seAnon
THEN Log.ErrorHti[noAccess, hti];
END
ELSE
BEGIN
sei ← SearchContext[hti, ctx];
IF sei # ISENull
THEN found ← seb[sei].public OR mdb[c.module].shared
ELSE IF ~c.closed AND ~c.reset
THEN
[found, sei] ← Copier.SearchFileCtx[hti, LOOPHOLE[ctx]]
ELSE found ← FALSE;
END;
imported =>
BEGIN
iCtx: IncludedCTXIndex = c.includeLink;
sei ← SearchContext[hti, ctx];
IF sei # ISENull
THEN
found ← ~ctxb[iCtx].restricted
OR CheckRestrictedCtx[hti, iCtx] # ISENull
ELSE
BEGIN
[found, sei] ← SearchCtxList[hti, iCtx];
IF found AND sei # dataPtr.seAnon THEN
SELECT LinkMode[sei] FROM
val => BEGIN MoveSe[sei, ctx]; ImportSe[sei, ctx] END;
ref =>
BEGIN
MoveSe[sei, ctx];
IF ~dataPtr.definitionsOnly THEN
BEGIN
seb[sei].idType ← MakePointerType[
cType: seb[sei].idType, readOnly: seb[sei].immutable,
hint: typeANY];
seb[sei].immutable ← TRUE;
END;
ImportSe[sei, ctx];
END;
ENDCASE;
END;
END;
ENDCASE =>
BEGIN sei ← SearchContext[hti, ctx]; found ← (sei # ISENull) END;
RETURN
END;
MoveSe: PROCEDURE [sei: ISEIndex, ctx: CTXIndex] =
BEGIN
Copier.Delink[sei]; seb[sei].idCtx ← ctx;
SetSeLink[sei, ctxb[ctx].seList]; ctxb[ctx].seList ← sei;
END;
BindTree: PROCEDURE [t: Tree.Link, importCtx: CTXIndex] RETURNS [Tree.Link] =
BEGIN
iCtx: IncludedCTXIndex = WITH c: ctxb[importCtx] SELECT FROM
imported => c.includeLink,
ENDCASE => ERROR;
UpdateBinding: Tree.Map =
BEGIN
WITH t SELECT FROM
symbol =>
BEGIN
oldSei: ISEIndex = index;
oldCtx: CTXIndex = seb[oldSei].idCtx;
newSei: ISEIndex;
type: CSEIndex;
WITH c: ctxb[oldCtx] SELECT FROM
included =>
IF c.level # lG OR LinkMode[oldSei] = manifest
THEN newSei ← oldSei
ELSE
BEGIN
mdi: MDIndex = c.module;
saveRestricted: BOOLEAN = c.restricted;
saveShared: BOOLEAN = mdb[mdi].shared;
targetCtx: CTXIndex;
c.restricted ← FALSE; mdb[mdi].shared ← TRUE;
targetCtx ← IF oldCtx = iCtx
THEN importCtx
ELSE DefaultImportCtx[LOOPHOLE[oldCtx]];
newSei ← SearchCtxList[seb[oldSei].hash, targetCtx].sei;
mdb[mdi].shared ← saveShared; c.restricted ← saveRestricted;
END;
ENDCASE => newSei ← oldSei;
v ← [symbol[index: newSei]];
IF ~dataPtr.definitionsOnly
AND ctxb[seb[newSei].idCtx].ctxType = imported
THEN
BEGIN
type ← UnderType[seb[newSei].idType];
IF seb[type].typeTag = pointer THEN [v, ] ← DeRef[v, type];
END;
BumpCount[newSei];
END;
subtree => v ← UpdateTree[t, UpdateBinding];
ENDCASE => v ← t;
RETURN
END;
RETURN [UpdateBinding[t]];
END;
ImportRecord: PROCEDURE [rSei: RecordSEIndex, importCtx: CTXIndex] =
BEGIN
sei: ISEIndex;
IF rSei # RecordSENull THEN
FOR sei ← FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei] UNTIL sei = ISENull
DO ImportSe[sei, importCtx] ENDLOOP;
END;
ImportSe: PROCEDURE [sei: ISEIndex, importCtx: CTXIndex] =
BEGIN
t: Tree.Link;
tag: ExtensionType;
type: CSEIndex = UnderType[seb[sei].idType];
WITH t: seb[type] SELECT FROM
transfer =>
BEGIN
ImportRecord[t.inRecord, importCtx];
ImportRecord[t.outRecord, importCtx];
END;
ENDCASE;
IF seb[sei].extended
THEN
BEGIN
[tag, t] ← FindExtension[sei];
EnterExtension[sei, tag, BindTree[t, importCtx]];
END;
END;
DefaultImportCtx: PROCEDURE [iCtx: IncludedCTXIndex] RETURNS [ctx: CTXIndex] =
BEGIN
mdi: MDIndex = ctxb[iCtx].module;
ctx ← mdb[mdi].defaultImport;
IF ctx = CTXNull
THEN
BEGIN
Log.ErrorHti[missingImport, mdb[mdi].moduleId];
ctx ← Table.Allocate[ctxType, SIZE[imported CTXRecord]];
ctxb[ctx] ← CTXRecord[
mark: FALSE,
varUpdated: FALSE,
seList: ISENull,
level: ctxb[iCtx].level,
extension: imported[includeLink: iCtx]];
mdb[mdi].defaultImport ← ctx;
END;
RETURN
END;
-- searching records
SearchRecordSegment: PROCEDURE
[hti: HTIndex, rSei: RecordSEIndex, suffixed: BOOLEAN]
RETURNS [nHits: CARDINAL, sei: ISEIndex] =
BEGIN
tSei: CSEIndex;
found: BOOLEAN;
n: CARDINAL;
match: ISEIndex;
[found, sei] ← SearchCtxList[hti, seb[rSei].fieldCtx];
nHits ← IF found THEN 1 ELSE 0;
IF seb[rSei].hints.variant
THEN
BEGIN
tSei ← VariantUnionType[rSei];
WITH seb[tSei] SELECT FROM
union =>
BEGIN
IF ~suffixed AND ~controlled AND overlayed
THEN
BEGIN
[n, match] ← SearchOverlays[hti, caseCtx];
IF ~found THEN sei ← match;
nHits ← nHits + n;
END;
IF controlled AND seb[tagSei].hash = hti
THEN BEGIN sei ← tagSei; nHits ← nHits + 1 END;
END;
ENDCASE => NULL;
END;
RETURN
END;
SearchOverlays: PROCEDURE [hti: HTIndex, ctx: CTXIndex]
RETURNS [nHits: CARDINAL, sei: ISEIndex] =
BEGIN
vSei: ISEIndex;
rSei: SEIndex;
n: CARDINAL;
match: ISEIndex;
WITH ctxb[ctx] SELECT FROM
included => Copier.CompleteContext[LOOPHOLE[ctx], FALSE];
ENDCASE;
nHits ← 0; sei ← ISENull;
FOR vSei ← FirstCtxSe[ctx], NextSe[vSei] UNTIL vSei = ISENull
DO
rSei ← seb[vSei].idInfo;
WITH r: seb[rSei] SELECT FROM
id => NULL;
cons =>
WITH r SELECT FROM
record =>
BEGIN
[n, match] ← SearchRecordSegment[hti, LOOPHOLE[rSei], FALSE];
IF nHits = 0 THEN sei ← match;
nHits ← nHits + n;
END;
ENDCASE => ERROR;
ENDCASE;
ENDLOOP;
RETURN
END;
SearchRecord: PROCEDURE [hti: HTIndex, type: RecordSEIndex]
RETURNS [nHits: CARDINAL, sei: ISEIndex] =
BEGIN
rSei: RecordSEIndex;
suffixed: BOOLEAN;
rSei ← type; suffixed ← FALSE;
UNTIL rSei = RecordSENull
DO
[nHits, sei] ← SearchRecordSegment[hti, rSei, suffixed];
IF nHits # 0 THEN RETURN;
rSei ← WITH seb[rSei] SELECT FROM
linked => LOOPHOLE[UnderType[linkType]],
ENDCASE => RecordSENull;
suffixed ← TRUE;
ENDLOOP;
RETURN [0, ISENull]
END;
-- management of restricted contexts
CtxRestriction: TYPE = RECORD [ctx: IncludedCTXIndex, list: Tree.Link];
ctxIdTable: DESCRIPTOR FOR ARRAY OF CtxRestriction;
ctxIdTableSize: CARDINAL;
CtxHash: PROCEDURE [ctx: IncludedCTXIndex] RETURNS [CARDINAL] = INLINE
BEGIN
RETURN [
(LOOPHOLE[ctx, CARDINAL]/SIZE[included CTXRecord]) MOD ctxIdTableSize]
END;
MakeIdTable: PUBLIC PROCEDURE [nIdLists: CARDINAL] =
BEGIN
i: CARDINAL;
ctxIdTable ← DESCRIPTOR[
SystemDefs.AllocateHeapNode[nIdLists*SIZE[CtxRestriction]],
nIdLists];
FOR i IN [0..nIdLists)
DO ctxIdTable[i] ← [IncludedCTXNull, Tree.Null] ENDLOOP;
ctxIdTableSize ← nIdLists;
END;
EnterIdList: PUBLIC PROCEDURE [ctx: IncludedCTXIndex, list: Tree.Link] =
BEGIN
i: CARDINAL;
i ← CtxHash[ctx];
DO
IF ctxIdTable[i].ctx = IncludedCTXNull
THEN BEGIN ctxIdTable[i] ← [ctx, list]; EXIT END;
IF (i ← i+1) = ctxIdTableSize THEN i ← 0;
ENDLOOP;
END;
CheckRestrictedCtx: PROCEDURE [hti: HTIndex, ctx: IncludedCTXIndex]
RETURNS [sei: ISEIndex] =
BEGIN
TestId: Tree.Test =
BEGIN
WITH t SELECT FROM
hash => IF index = hti THEN sei ← dataPtr.seAnon;
symbol => IF seb[index].hash = hti THEN sei ← index;
ENDCASE;
RETURN [sei # ISENull]
END;
i: CARDINAL;
i ← CtxHash[ctx];
DO
IF ctxIdTable[i].ctx = ctx THEN EXIT;
IF (i ← i+1) = ctxIdTableSize THEN i ← 0;
ENDLOOP;
sei ← ISENull; SearchList[ctxIdTable[i].list, TestId];
IF sei # ISENull AND seb[sei].idCtx = CTXNull
THEN seb[sei].idCtx ← ctx;
RETURN
END;
SearchRestrictedCtx: PROCEDURE [hti: HTIndex, ctx: IncludedCTXIndex]
RETURNS [sei: ISEIndex] =
BEGIN
sei ← CheckRestrictedCtx[hti, ctx];
IF sei # ISENull AND sei # dataPtr.seAnon AND seb[sei].idCtx # ctx
THEN [ , sei] ← Copier.SearchFileCtx[hti, ctx];
RETURN
END;
CheckDirectoryIds: Tree.Scan =
BEGIN
CheckId: Tree.Scan =
BEGIN
WITH t SELECT FROM
symbol =>
IF seb[index].idCtx = CTXNull THEN Log.WarningSei[unusedId, index];
ENDCASE;
END;
node: Tree.Index = GetNode[t];
saveIndex: CARDINAL = dataPtr.textIndex;
dataPtr.textIndex ← tb[node].info;
ScanList[tb[node].son[3], CheckId];
dataPtr.textIndex ← saveIndex;
END;
CheckDisjoint: PUBLIC PROCEDURE [ctx1, ctx2: CTXIndex] =
BEGIN
sei: ISEIndex;
hti: HTIndex;
saveIndex: CARDINAL = dataPtr.textIndex;
IF ctx1 # CTXNull AND ctx2 # CTXNull
THEN
FOR sei ← FirstCtxSe[ctx2], NextSe[sei] UNTIL sei = ISENull
DO
hti ← seb[sei].hash;
IF hti # HTNull AND SearchContext[hti, ctx1] # ISENull
THEN
BEGIN
IF ~seb[sei].mark3
THEN dataPtr.textIndex ←
tb[LOOPHOLE[seb[sei].idValue, Tree.Index]].info;
Log.ErrorHti[duplicateId, hti];
END;
ENDLOOP;
dataPtr.textIndex ← saveIndex;
END;
-- basing management
OpenPointer: PUBLIC PROCEDURE [t: Tree.Link, type: CSEIndex]
RETURNS [Tree.Link, CSEIndex] =
BEGIN
nType, rType: CSEIndex;
nDerefs: CARDINAL ← 0;
DO
nType ← NormalType[type];
WITH p: seb[nType] SELECT FROM
pointer =>
BEGIN
p.dereferenced ← TRUE; rType ← UnderType[p.refType];
IF seb[NormalType[rType]].typeTag # pointer THEN EXIT;
IF (nDerefs ← nDerefs+1) > 255 THEN EXIT;
END;
ENDCASE;
[t, type] ← DeRef[t, type];
ENDLOOP;
RETURN [t, rType];
END;
BaseTree: PUBLIC PROCEDURE [t: Tree.Link, type: CSEIndex] RETURNS [val: Tree.Link] =
BEGIN
PushTree[t]; PushNode[openx, 1]; SetInfo[type]; SetAttr[1, FALSE];
val ← PopTree[]; SetShared[val, TRUE]; RETURN
END;
OpenBase: PUBLIC PROCEDURE [t: Tree.Link, hti: HTIndex] RETURNS [v: Tree.Link] =
BEGIN
type, vType, nType: CSEIndex;
OpenRecord: PROCEDURE [indirect: BOOLEAN] =
BEGIN
WITH seb[type] SELECT FROM
record =>
BEGIN
v ← BaseTree[v, vType];
IF hti # HTNull
THEN PushHtCtx[hti, v, indirect]
ELSE PushRecordCtx[LOOPHOLE[type, RecordSEIndex], v, indirect];
END;
ENDCASE => IF type # typeANY THEN Log.ErrorTree[typeClash, v];
END;
v ← Exp[t, typeANY];
type ← vType ← RType[]; nType ← NormalType[vType]; RPop[];
WITH seb[nType] SELECT FROM
definition =>
BEGIN
IF hti # HTNull THEN Log.ErrorHti[openId, hti];
PushCtx[defCtx];
END;
pointer =>
BEGIN
[v, type] ← OpenPointer[v, vType]; vType ← OperandType[v];
OpenRecord[TRUE];
END;
ENDCASE => OpenRecord[FALSE];
RETURN
END;
CloseBase: PUBLIC PROCEDURE [t: Tree.Link, hti: HTIndex] =
BEGIN
type: CSEIndex;
CloseRecord: PROCEDURE =
BEGIN
WITH seb[type] SELECT FROM record => PopCtx[]; ENDCASE;
END;
type ← NormalType[OperandType[t]];
WITH seb[type] SELECT FROM
definition => BEGIN IF hti # HTNull THEN NULL; PopCtx[] END;
pointer => BEGIN type ← UnderType[refType]; CloseRecord[] END;
ENDCASE => CloseRecord[];
END;
-- initialization/finalization
IdInit: PUBLIC PROCEDURE =
BEGIN
refStack ← DESCRIPTOR[SystemDefs.AllocateHeapNode[16*SIZE[RefItem]], 16];
refIndex ← 0;
ctxStack ← MakeStack[2*ContextIncr]; ctxIndex ← -1;
END;
IdFinish: PUBLIC Tree.Scan =
BEGIN
ScanList[t, CheckDirectoryIds];
SystemDefs.FreeHeapNode[BASE[ctxIdTable]];
FreeStack[ctxStack];
SystemDefs.FreeHeapNode[BASE[refStack]];
END;
END.