DIRECTORY
A3: TYPE USING [LongPath, MarkedType, OperandType, PermanentType, TypeForTree, VarType],
Alloc: TYPE USING [Notifier, AddNotify, DropNotify],
ComData: TYPE USING [interface, moduleCtx, seAnon, switches, table, textIndex, typeAtomRecord],
Copier: TYPE USING [CompleteContext, Delink, SearchFileCtx],
Log: TYPE USING [Error, ErrorHti, ErrorSei, ErrorTree, ErrorTreeOp, WarningSei],
P3: TYPE USING [Attr, fullAttr, voidAttr, mark, MergeNP, phraseNP, And, Exp, FirstId, InterfaceCtx, ItemType, MakeRefType, ResolveType, ResolveValue, RPop, RPush, RType, SetDefaultImport, VariantUnionType, VoidExp],
P3S: TYPE USING [currentBody, currentScope, safety],
SourceMap: TYPE USING [Loc],
Symbols: TYPE USING [seType, ctxType, mdType, Base, CTXRecord, ExtensionType, MDIndex, HTIndex, Type, ISEIndex, CSEIndex, ArraySEIndex, RecordSEIndex, CTXIndex, IncludedCTXIndex, Closure, HTNull, nullType, ISENull, CSENull, RecordSENull, CTXNull, IncludedCTXNull, lG, lZ, StandardContext, typeTYPE, typeANY],
SymbolOps: TYPE USING [ArgCtx, ConstantId, CtxLevel, EnterExtension, FindExtension, FirstCtxSe, LinkMode, NextSe, NormalType, RCType, RecordRoot, ReferentType, SearchContext, SetSeLink, TypeForm, TypeLink, TypeRoot, UnderType],
SymLiteralOps: TYPE USING [EnterAtom, EnterType],
Tree: TYPE USING [Base, Index, Link, Map, Scan, Test, Null, NullIndex, treeType],
TreeOps:
TYPE
USING [CopyTree, FreeTree, GetHash, GetNode, GetSe, ListLength, MarkShared, NthSon, OpName, PopTree, PushTree, PushNode, ScanList, ScanSons, SearchList, SetAttr, SetInfo, UpdateList, UpdateLeaves];
Id:
PUBLIC
PROC[hti: HTIndex]
RETURNS[val: Tree.Link] = {
sei: ISEIndex;
type: Type;
ctx: CTXIndex;
baseV: Tree.Link;
attr: Attr ← voidAttr;
indirect: BOOL;
[sei, baseV, indirect] ← FindSe[hti];
IF sei # ISENull
THEN {
IF baseV = Tree.Null THEN RecordMention[sei] ELSE BumpCount[sei];
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
val ← [symbol[index: sei]]; type ← seb[sei].idType;
ctx ← seb[sei].idCtx;
SELECT ctxb[ctx].ctxType
FROM
included => {
attr.const ← ConstantId[sei];
IF baseV = Tree.Null
AND (~attr.const
OR ~InterfaceConst[sei])
THEN
Log.ErrorSei[notImported, sei]};
imported => {
IF ~dataPtr.interface
AND TypeForm[type] = $ref
THEN
[val, type] ← DeRef[val, type];
attr.const ← FALSE};
ENDCASE => {
IF ~ConstResolved[sei] THEN ResolveIdValue[sei];
attr.const ← seb[sei].constant};
SELECT
TRUE
FROM
baseV = Tree.Null => {
IF ctx = P3S.currentBody.argCtx THEN phraseNP ← ref;
IF CtxLevel[ctx] = lZ
AND ~attr.const
THEN
SELECT ctx
FROM
IN StandardContext, dataPtr.moduleCtx => NULL;
ENDCASE => Log.ErrorSei[missingBase, sei]
};
(~attr.const
AND ctxb[ctx].ctxType # imported) => {
attr ← And[UpdateTreeAttr[baseV], attr];
PushTree[CopyTree[baseV]]; PushTree[val];
IF indirect
THEN {
PushNode[dot, 2]; SetAttr[2, TypeForm[OperandType[baseV]] = $long]}
ELSE {PushNode[dollar, 2]; SetAttr[2, LongPath[baseV]]};
SetInfo[type]; val ← PopTree[]};
ENDCASE;
IF VarType[type] THEN [val, type] ← DeRef[val, type, TRUE];
IF seb[sei].extended THEN attr ← And[UpdateExtension[sei], attr]}
ELSE {
attr ← And[UpdateTreeAttr[baseV], attr]; type ← OperandType[baseV];
IF indirect THEN [val, type] ← DeRef[CopyTree[baseV], type]
ELSE val ← CopyTree[baseV]};
RPush[type, attr];
RETURN};
DeRef:
PROC[t: Tree.Link, type: Type, var:
BOOL←
FALSE]
RETURNS [Tree.Link, Type] = {
rType: Type = ReferentType[type];
PushTree[t];
PushNode[uparrow, 1];
SetInfo[rType]; SetAttr[2, TypeForm[type] = $long]; SetAttr[3, var];
RETURN[PopTree[], rType]};
UpdateExtension:
PROC[sei: ISEIndex]
RETURNS[attr: Attr] = {
t: Tree.Link;
tag: ExtensionType;
[tag, t] ← FindExtension[sei];
IF tag # value THEN attr ← fullAttr
ELSE {attr ← UpdateTreeAttr[t]; attr.const ← TRUE};
RETURN};
FieldId:
PUBLIC
PROC[hti: HTIndex, type: RecordSEIndex]
RETURNS[n: CARDINAL, sei: ISEIndex] = {
[n, sei] ← SearchRecord[hti, type];
IF n # 0
THEN {
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
IF ~ConstResolved[sei] THEN ResolveIdValue[sei];
BumpCount[sei]};
RETURN};
InterfaceId:
PUBLIC
PROC[hti: HTIndex, ctx: CTXIndex]
RETURNS[found: BOOL, sei: ISEIndex] = {
[found, sei] ← SearchCtxList[hti, ctx];
IF found
THEN {
SELECT ctxb[seb[sei].idCtx].ctxType
FROM
imported => NULL;
included =>
IF ~ConstantId[sei] OR ~InterfaceConst[sei] THEN Log.ErrorSei[notImported, sei];
ENDCASE => {
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
IF ~ConstResolved[sei] THEN ResolveIdValue[sei]};
BumpCount[sei]};
RETURN};
ClusterId:
PUBLIC
PROC[hti: HTIndex, ctx: CTXIndex]
RETURNS[found: BOOL, sei: ISEIndex] = {
WITH c: ctxb[ctx]
SELECT
FROM
simple => [found, sei] ← SearchCtxList[hti, ctx];
included => {
mdi: MDIndex = c.module;
IF mdb[mdi].defaultImport = CTXNull
THEN {
-- avoid creating spurious principal imports
IF SearchCtxList[hti, ctx].found
THEN
[found, sei] ← SearchCtxList[hti, DefaultImport[LOOPHOLE[ctx], FALSE]]
ELSE {found ← FALSE; sei ← ISENull}}
ELSE [found, sei] ← SearchCtxList[hti, mdb[mdi].defaultImport]};
ENDCASE => {found ← FALSE; sei ← ISENull};
IF found
THEN {
IF ~seb[sei].mark3 THEN ResolveIdType[sei];
BumpCount[sei]};
RETURN};
ContextEntry:
TYPE =
RECORD[
base: Tree.Link, -- the basing expr (empty if none)
indirect: BOOL, -- 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
ContextSequence: TYPE = RECORD[SEQUENCE length: NAT OF ContextEntry];
ContextStack: TYPE = REF ContextSequence;
ctxStack: ContextStack;
ctxIndex: INTEGER;
ContextIncr: CARDINAL = 16;
ExpandStack:
PROC = {
oldstack: ContextStack ← ctxStack;
ctxStack ← NEW[ContextSequence[oldstack.length + ContextIncr]];
FOR i: CARDINAL IN [0 .. oldstack.length) DO ctxStack[i] ← oldstack[i] ENDLOOP;
oldstack ← NIL};
PushCtx:
PUBLIC
PROC[ctx: CTXIndex] = {
IF (ctxIndex ← ctxIndex+1) >= ctxStack.length THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:Tree.Null, indirect:FALSE, info:list[ctx]]};
PushRecordCtx:
PUBLIC
PROC[rSei: RecordSEIndex, base: Tree.Link, indirect:
BOOL] = {
IF (ctxIndex ← ctxIndex+1) >= ctxStack.length THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:base, indirect:indirect, info:record[rSei]]};
UpdateRecordCtx:
PUBLIC
PROC[type: RecordSEIndex] = {
WITH ctxStack[ctxIndex]
SELECT
FROM
record => rSei ← type;
ENDCASE => ERROR
PushHtCtx:
PUBLIC
PROC[hti: HTIndex, base: Tree.Link, indirect:
BOOL] = {
IF (ctxIndex ← ctxIndex+1) >= ctxStack.length THEN ExpandStack[];
ctxStack[ctxIndex] ← [base:base, indirect:indirect, info:hash[hti]]};
PopCtx: PUBLIC PROC = {ctxIndex ← ctxIndex-1};
TopCtx:
PUBLIC
PROC
RETURNS[CTXIndex] = {
RETURN[WITH ctxStack[ctxIndex] SELECT FROM list => ctx, ENDCASE => ERROR]};
Shared:
PUBLIC
PROC[ctx: CTXIndex]
RETURNS[
BOOL] = {
RETURN[
WITH c: ctxb[ctx]
SELECT
FROM
included => mdb[c.module].shared,
imported => Shared[c.includeLink],
ENDCASE => TRUE]
CtxRestriction: TYPE = RECORD[ctx: IncludedCTXIndex, list: Tree.Link, linked: BOOL←FALSE];
CtxIdTable: TYPE = RECORD[SEQUENCE length: CARDINAL OF CtxRestriction];
ctxIdTable: REF CtxIdTable;
CtxHash:
PROC[ctx: IncludedCTXIndex]
RETURNS[
CARDINAL] =
INLINE {
RETURN[(LOOPHOLE[ctx, CARDINAL]/CTXRecord.included.SIZE) MOD ctxIdTable.length]};
MakeIdTable:
PUBLIC
PROC[nIdLists:
CARDINAL] = {
ctxIdTable ← NEW[CtxIdTable[nIdLists]];
FOR i: CARDINAL IN [0..nIdLists) DO ctxIdTable[i] ← [IncludedCTXNull, Tree.Null] ENDLOOP};
EnterIdList:
PUBLIC
PROC[ctx: IncludedCTXIndex, list: Tree.Link] = {
i: CARDINAL ← CtxHash[ctx];
DO
SELECT ctxIdTable[i].ctx
FROM
IncludedCTXNull => {ctxIdTable[i] ← [ctx, list]; EXIT};
ctx => ctxIdTable[i].linked ← TRUE;
ENDCASE;
IF (i ← i+1) = ctxIdTable.length THEN i ← 0;
ENDLOOP
CheckRestrictedCtx:
PROC[hti: HTIndex, ctx: IncludedCTXIndex]
RETURNS [sei: ISEIndex] = {
TestId: Tree.Test = {
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]};
i: CARDINAL ← CtxHash[ctx];
DO
IF ctxIdTable[i].ctx = ctx
THEN {
sei ← ISENull; SearchList[ctxIdTable[i].list, TestId];
IF sei # ISENull OR ~ctxIdTable[i].linked THEN EXIT};
IF (i ← i+1) = ctxIdTable.length THEN i ← 0;
ENDLOOP;
IF sei # ISENull AND seb[sei].idCtx = CTXNull THEN seb[sei].idCtx ← ctx;
RETURN};
SearchRestrictedCtx:
PROC[hti: HTIndex, ctx: IncludedCTXIndex]
RETURNS [sei: ISEIndex] = {
sei ← CheckRestrictedCtx[hti, ctx];
IF sei # ISENull
AND sei # dataPtr.seAnon
AND seb[sei].idCtx # ctx
THEN {
[ , sei] ← Copier.SearchFileCtx[hti, ctx];
seb[sei].public ← TRUE}; -- second copy, access already checked
RETURN};
CheckDirectoryIds: Tree.Scan = {
CheckId: Tree.Scan = {
WITH t
SELECT
FROM
symbol => IF seb[index].idCtx = CTXNull THEN Log.WarningSei[unusedId, index];
ENDCASE};
node: Tree.Index = GetNode[t];
saveIndex: SourceMap.Loc = dataPtr.textIndex;
dataPtr.textIndex ← tb[node].info;
ScanList[tb[node].son[3], CheckId];
dataPtr.textIndex ← saveIndex};
CheckDisjoint:
PUBLIC
PROC[ctx1, ctx2: CTXIndex] = {
hti: HTIndex;
saveIndex: SourceMap.Loc = dataPtr.textIndex;
IF ctx1 # CTXNull
AND ctx2 # CTXNull
THEN
FOR sei: ISEIndex ← FirstCtxSe[ctx2], NextSe[sei]
UNTIL sei = ISENull
DO
hti ← seb[sei].hash;
IF hti # HTNull
AND SearchContext[hti, ctx1] # ISENull
THEN {
IF ~seb[sei].mark3
THEN
dataPtr.textIndex ← tb[LOOPHOLE[seb[sei].idValue, Tree.Index]].info;
Log.ErrorHti[duplicateId, hti]};
ENDLOOP;
dataPtr.textIndex ← saveIndex};