DIRECTORY
A3: TYPE USING [LhsMode, CanonicalType, DefaultInit, IdentifiedType, OperandLhs, TargetType, Voidable],
Alloc: TYPE USING [Notifier],
ComData: TYPE USING [bodyIndex, idANY, idBOOL, monitored, ownSymbols, textIndex],
Log: TYPE USING [Error, ErrorSei, ErrorTree, ErrorTreeOp, ErrorType, Warning, WarningTree],
Pass3: TYPE USING [checkedANY, lockNode],
P3: TYPE USING [Attr, NPUse, Safety, phraseNP, BoundNP, SequenceNP, voidAttr, And, Apply, Assignment, BumpCount, CheckDisjoint, CloseBase, ClearRefStack, CopyLock, DeclList, Discrimination, EnterComposite, EnterType, Exp, Extract, FieldDefault, FindLockParams, FirstId, LockVar, MatchFields, MiscStmt, OpenBase, PopCtx, PushCtx, Range, RAttr, RecordMention, Rhs, RPop, RPush, RType, SealRefStack, UnsealRefStack, UpdateTreeAttr, UType, InsertCatchLabel],
P3S: TYPE USING [BodyData, ImplicitInfo, implicit],
SourceMap: TYPE USING [Loc, Up],
SymLiteralOps: TYPE USING [DescribeRefLits],
Symbols: TYPE USING [Base, ContextLevel, ISEIndex, Type, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, HTNull, ISENull, CSENull, RecordSENull, CTXNull, BTNull, lG, RootBti, typeANY, seType, ctxType, mdType, bodyType],
SymbolOps: TYPE USING [CopyBasicType, CtxLevel, FirstCtxSe, NextSe, RCType, SetCtxLevel, TransferTypes, TypeForm, UnderType],
Tree: TYPE USING [Base, Index, Link, Map, Null, Scan, NullId, NullIndex, treeType],
TreeOps: TYPE USING [FreeNode, GetHash, GetNode, MakeList, OpName, NthSon, PopTree, PushTree, PushNode, ReverseScanList, ScanList, SetAttr, SetInfo, UpdateList],
Types: TYPE USING [Assignable];
Pass3S:
PROGRAM
IMPORTS
A3, Log, P3, P3S, SourceMap, SymLiteralOps, SymbolOps, TreeOps, Types,
dataPtr: ComData, passPtr: Pass3
EXPORTS P3, P3S = {
OPEN SymbolOps, Symbols, A3, P3, TreeOps;
tb: Tree.Base; -- tree base address (local copy)
seb: Symbols.Base; -- se table base address (local copy)
ctxb: Symbols.Base; -- context table base (local copy)
mdb: Symbols.Base; -- module table base (local copy)
bb: Symbols.Base; -- body table base (local copy)
StmtNotify:
PUBLIC Alloc.Notifier = {
called by allocator whenever table area is repacked
tb ← base[Tree.treeType];
seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType];
bb ← base[bodyType]};
currentBody: PUBLIC P3S.BodyData;
current: POINTER TO P3S.BodyData = @currentBody;
currentScope: PUBLIC BTIndex;
safety: PUBLIC Safety ← none;
exits: BOOL;
BodyList:
PUBLIC
PROC[firstBti: BTIndex] = {
bti: BTIndex ← firstBti;
IF bti # BTNull
THEN
DO
WITH bb[bti]
SELECT
FROM
Callable => IF nesting # Catch THEN Body[LOOPHOLE[bti, CBTIndex]];
ENDCASE => NULL;
IF bb[bti].link.which = parent THEN EXIT;
bti ← bb[bti].link.index;
ENDLOOP
Body:
PROC[bti: CBTIndex] = {
saved: P3S.BodyData = current^;
saveIndex: SourceMap.Loc = dataPtr.textIndex;
saveBodyIndex: CBTIndex = dataPtr.bodyIndex;
saveScope: BTIndex = currentScope;
saveSafety: Safety = safety;
node: Tree.Index;
lockVar: ISEIndex;
lockBit: BOOL;
inRecord, outRecord: RecordSEIndex;
argLevel: ContextLevel;
dataPtr.bodyIndex ← currentScope ← bti;
dataPtr.textIndex ← SourceMap.Up[bb[bti].sourceIndex];
current.bodyNode ← node ←
WITH bb[bti].info
SELECT
FROM
Internal => bodyTree,
ENDCASE => ERROR;
current.level ← bb[bti].level; current.entry ← bb[bti].entry;
SetSafety[SafetyAttr[node]];
bb[bti].resident ← FALSE;
current.lockHeld ← bb[bti].entry OR bb[bti].internal;
argLevel ← IF bti = RootBti THEN lG ELSE current.level;
IF bb[bti].ioType # typeANY THEN seb[bb[bti].ioType].mark4 ← FALSE;
[inRecord, outRecord] ← TransferTypes[bb[bti].ioType];
IF inRecord = RecordSENull THEN current.argCtx ← CTXNull
ELSE {
current.argCtx ← seb[inRecord].fieldCtx;
SetCtxLevel[current.argCtx, argLevel];
IF argLevel = lG THEN EnterTypes[current.argCtx]};
IF outRecord # RecordSENull
THEN {
SetCtxLevel[seb[outRecord].fieldCtx, argLevel];
IF argLevel = lG THEN EnterTypes[seb[outRecord].fieldCtx]};
PushArgCtx[current.inputRecord ← inRecord]; SetArgRefs[inRecord, 1];
PushArgCtx[current.returnRecord ← outRecord]; SetArgRefs[outRecord, 0];
ClearRefStack[];
initialize computed attributes
current.labelList ← Tree.Null; current.loopDepth ← 0;
current.catchDepth ← 0; current.unwindEnabled ← FALSE;
current.resumeRecord ← RecordSENull; current.resumeFlag ← FALSE;
IF ~current.entry THEN pathNP ← none
ELSE {
IF (lockVar ← FindLockParams[].actual) # ISENull
THEN {
lockBit ← seb[lockVar].immutable; seb[lockVar].immutable ← TRUE};
tb[node].son[4] ← CopyLock[]; pathNP ← phraseNP};
BEGIN
ENABLE
InsertCatchLabel => {Log.Error[catchLabel]; RESUME};
outInit: Tree.Link ← Tree.Null;
ScanList[tb[node].son[1], OpenItem];
current.noXfers ← TRUE;
IF inRecord # RecordSENull THEN CheckDisjoint[current.argCtx, bb[bti].localCtx];
IF outRecord # RecordSENull
THEN {
CheckDisjoint[seb[outRecord].fieldCtx, bb[bti].localCtx];
outInit ← AssignDefaults[seb[outRecord].fieldCtx, bb[bti].inline]};
PushCtx[bb[bti].localCtx];
IF bti = RootBti
AND dataPtr.monitored
THEN {
PushCtx[tb[passPtr.lockNode].info];
DeclList[tb[passPtr.lockNode].son[1]];
IF (lockVar ← FirstCtxSe[tb[passPtr.lockNode].info]) # ISENull THEN BumpCount[lockVar];
tb[passPtr.lockNode].son[2] ← LockVar[tb[passPtr.lockNode].son[2]];
PopCtx[]; ClearRefStack[]};
DeclList[tb[node].son[2]];
IF outInit # Tree.Null
THEN {
PushTree[outInit]; PushTree[tb[node].son[2]];
PushNode[initlist, 2]; SetInfo[dataPtr.textIndex];
tb[node].son[2] ← PopTree[]};
END;
IF bb[bti].type # RecordSENull
THEN {
IF bti = RootBti
THEN {
EnterTypes[seb[bb[bti].type].fieldCtx];
SetBodyAttrs[bb[bti].type]};
seb[bb[bti].type].mark3 ← TRUE};
current.reachable ← TRUE;
tb[node].son[3] ← UpdateList[tb[node].son[3], Stmt
! InsertCatchLabel => {IF ~catchSeen THEN Log.Error[catchLabel]; RESUME}];
IF current.reachable THEN tb[node].son[3] ← ImpliedReturn[tb[node].son[3]];
BodyList[bb[bti].firstSon];
PopCtx[];
ReverseScanList[tb[node].son[1], CloseItem];
bb[bti].noXfers ← current.noXfers;
bb[bti].hints ← [
safe: pathNP <= ref,
argUpdated: inRecord # RecordSENull AND ctxb[seb[inRecord].fieldCtx].varUpdated,
nameSafe: pathNP # unsafe,
noStrings: ];
PopArgCtx[outRecord]; PopArgCtx[inRecord];
IF bti = RootBti
AND SymLiteralOps.DescribeRefLits[].length # 0
THEN {
rSei: RecordSEIndex = bb[bti].type;
seb[rSei].hints.refField ← TRUE; EnterType[rSei]};
IF current.entry AND lockVar # ISENull THEN seb[lockVar].immutable ← lockBit;
current^ ← saved; currentScope ← saveScope;
SetSafety[saveSafety];
dataPtr.bodyIndex ← saveBodyIndex; dataPtr.textIndex ← saveIndex};
Scope:
PUBLIC
PROC[node: Tree.Index, body: Tree.Map] = {
bti: BTIndex = tb[node].info;
saveIndex: SourceMap.Loc = dataPtr.textIndex;
saveScope: BTIndex = currentScope;
dataPtr.textIndex ← SourceMap.Up[bb[bti].sourceIndex];
currentScope ← bti;
PushCtx[bb[bti].localCtx];
DeclList[tb[node].son[1] ! InsertCatchLabel => {Log.Error[catchLabel]; RESUME}];
IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].mark3 ← TRUE;
tb[node].son[2] ← body[tb[node].son[2]];
BodyList[bb[bti].firstSon];
PopCtx[];
currentScope ← saveScope; dataPtr.textIndex ← saveIndex};
PushArgCtx:
PROC[rSei: RecordSEIndex] =
INLINE {
IF rSei # RecordSENull THEN PushCtx[seb[rSei].fieldCtx]};
PopArgCtx: PROC[rSei: RecordSEIndex] = INLINE {IF rSei # RecordSENull THEN PopCtx[]};
SetArgRefs:
PROC[rSei: RecordSEIndex, nRefs:
CARDINAL] = {
IF rSei # RecordSENull
THEN {
seb[rSei].mark4 ← FALSE;
FOR sei: ISEIndex ← FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei]
UNTIL sei = ISENull
DO
IF seb[sei].mark4 THEN {seb[sei].idValue ← Tree.NullIndex; seb[sei].mark4 ← FALSE};
seb[sei].idInfo ← nRefs;
ENDLOOP}
EnterTypes:
PROC[ctx: CTXIndex] = {
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei]
UNTIL sei = ISENull
DO
IF RCType[UnderType[seb[sei].idType]] = composite
THEN
EnterType[UnderType[seb[sei].idType]];
ENDLOOP
AssignDefault:
PROC[sei: ISEIndex]
RETURNS[v: Tree.Link] = {
IF seb[sei].hash = Symbols.HTNull AND ~seb[sei].extended THEN v ← Tree.Null
ELSE {
t: Tree.Link =
IF seb[sei].extended THEN FieldDefault[sei] ELSE DefaultInit[seb[sei].idType];
IF t = Tree.Null
THEN {
IF ~Voidable[seb[sei].idType] THEN Log.ErrorSei[missingInit, sei];
v ← Tree.Null}
ELSE {
lhs: Tree.Link = [symbol[sei]];
mode: LhsMode;
RecordMention[sei]; mode ← OperandLhs[lhs];
PushTree[lhs]; PushTree[t]; PushNode[assign, 2];
SetInfo[dataPtr.textIndex]; SetAttr[1, TRUE];
IF mode # counted THEN SetAttr[2, FALSE]
ELSE {
type: Type = seb[sei].idType;
SELECT RCType[type]
FROM
simple => {SetAttr[2, OpName[t] # nil]; SetAttr[3, FALSE]};
composite => {
SetAttr[2, TRUE]; SetAttr[3, TRUE]; EnterComposite[type, t, TRUE]};
ENDCASE => SetAttr[2, FALSE]};
v ← PopTree[]};
RPop[]};
RETURN};
AssignDefaults:
PROC[ctx: CTXIndex, copyable:
BOOL]
RETURNS[Tree.Link] =
INLINE {
n: INTEGER ← 0;
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei]
UNTIL sei = ISENull
DO
IF seb[sei].hash # HTNull
OR seb[sei].extended
THEN {
t: Tree.Link = AssignDefault[sei];
IF t # Tree.Null
THEN {
IF seb[sei].hash = HTNull AND copyable THEN Log.ErrorSei[defaultForm, sei];
PushTree[t]; n ← n+1; pathNP ← SequenceNP[pathNP][phraseNP]; ClearRefStack[]}};
ENDLOOP;
RETURN[MakeList[n]]};
SetBodyAttrs:
PROC[rSei: RecordSEIndex] =
INLINE {
FOR sei: ISEIndex ← FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei]
UNTIL sei = ISENull
DO
IF ~seb[sei].constant
AND RCType[UnderType[seb[sei].idType]] # none
THEN {
seb[rSei].hints.refField ← TRUE; EnterType[rSei]; EXIT}
ENDLOOP
SafetyAttr:
PUBLIC
PROC[node: Tree.Index]
RETURNS[Safety] = {
RETURN[
SELECT
TRUE
FROM
tb[node].attr1 => checked,
tb[node].attr2 => asserted,
ENDCASE => none]
SetSafety:
PUBLIC
PROC[new: Safety] = {
IF safety # new
THEN {
SELECT new
FROM
checked => {
IF passPtr.checkedANY = CSENull
THEN
passPtr.checkedANY ← CopyBasicType[typeANY];
seb[dataPtr.idANY].idInfo ← passPtr.checkedANY};
ENDCASE => seb[dataPtr.idANY].idInfo ← typeANY;
safety ← new}