-- file Pass3P.Mesa -- last modified by Satterthwaite, November 13, 1979 1:30 PM DIRECTORY ComData: FROM "comdata" USING [bodyRoot, defBodyLimit, definitionsOnly, nBodies, textIndex], Copier: FROM "copier" USING [CopyArgSe, CopyXferType], Log: FROM "log" USING [Error, ErrorSei], P3: FROM "p3", Symbols: FROM "symbols" USING [seType, ctxType, mdType, bodyType, BodyInfo, BodyRecord, ContextLevel, StandardContext, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, ISENull, RecordSENull, CTXNull, BTNull, HTNull, lL, typeTYPE], SymbolOps: FROM "symbolops" USING [ CtxEntries, DelinkBti, FindExtension, FirstCtxSe, LinkBti, MakeSeChain, NewCtx, NextLevel, NextSe, ParentBti, SetSeLink, SearchContext, TransferTypes, StaticNestError], SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode], Table: FROM "table" USING [Base, Notifier, AddNotify, Allocate, Bounds, DropNotify], Tree: FROM "tree" USING [Index, Link, Map, Scan, Null, NullIndex, treeType], TreeOps: FROM "treeops" USING [ CopyTree, FreeNode, FreeTree, GetNode, ListTail, MakeList, PopTree, PushNode, PushTree, ScanList, SetAttr, SetInfo, SetShared, Shared, TestTree, UpdateList, UpdateTree]; Pass3P: PROGRAM IMPORTS Copier, Log, SymbolOps, SystemDefs, Table, TreeOps, dataPtr: ComData EXPORTS P3 = BEGIN OPEN TreeOps, SymbolOps, Symbols; tb: Table.Base; -- tree base address (local copy) seb: Table.Base; -- se table base address (local copy) ctxb: Table.Base; -- context table base address (local copy) mdb: Table.Base; -- module table base address (local copy) bb: Table.Base; -- body table base address (local copy) PostNotify: Table.Notifier = BEGIN -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]; bb ← base[bodyType]; END; -- driver Postlude: PUBLIC PROCEDURE = BEGIN Table.AddNotify[PostNotify]; LinkImportedBodies[]; ExpandInlines[dataPtr.bodyRoot]; Table.DropNotify[PostNotify]; END; -- included body copying LinkImportedBodies: PROCEDURE = BEGIN bti, nextBti: BTIndex; btLimit: BTIndex = LOOPHOLE[Table.Bounds[bodyType].size]; FOR bti ← LOOPHOLE[dataPtr.defBodyLimit], nextBti UNTIL bti = btLimit DO WITH body: bb[bti] SELECT FROM Callable => BEGIN IF body.inline THEN BEGIN body.link ← bb[dataPtr.bodyRoot].link; bb[dataPtr.bodyRoot].link ← [sibling, bti]; END; nextBti ← bti + (SELECT body.nesting FROM Inner => SIZE[Inner Callable BodyRecord], ENDCASE => SIZE[Outer Callable BodyRecord]); END; ENDCASE => nextBti ← bti + SIZE[Other BodyRecord]; ENDLOOP; END; -- inline expansion -- state information currentMaster: CBTIndex; masterBody: Tree.Index; copyCtx: CTXIndex; copying: BOOLEAN; substSafe: BOOLEAN; currentEnclosing: BTIndex; bodyNesting: CARDINAL; aStack: AList; -- current association list AItem: TYPE = RECORD [id: ISEIndex, name: BOOLEAN, val: Tree.Link]; ANode: TYPE = RECORD [ next: AList, ctx: CTXIndex, nItems: CARDINAL, map: ARRAY [0..0) OF AItem]; AList: TYPE = POINTER TO ANode; -- overall control ExpandInlines: PROCEDURE [rootBti: BTIndex] = BEGIN bti: BTIndex; aStack ← NIL; sharingMap ← NIL; bti ← rootBti; UNTIL bti = BTNull DO ExpandInlines[bb[bti].firstSon]; WITH body: bb[bti] SELECT FROM Callable => IF body.inline THEN ExpandCalls[LOOPHOLE[bti, CBTIndex]]; ENDCASE; bti ← IF bb[bti].link.which=parent THEN BTNull ELSE bb[bti].link.index; ENDLOOP; END; ExpandCalls: PROCEDURE [bti: CBTIndex] = BEGIN saveIndex: CARDINAL = dataPtr.textIndex; sei: ISEIndex = bb[bti].id; current, subNode: Tree.Index; WITH body: bb[bti].info SELECT FROM Internal => BEGIN currentMaster ← bti; masterBody ← IF seb[sei].mark4 THEN GetNode[FindExtension[sei].tree] ELSE body.bodyTree; copying ← TRUE; dataPtr.textIndex ← body.sourceIndex; UNTIL (current ← body.thread) = Tree.NullIndex DO -- process the thread (son[1]) subNode ← GetNode[tb[current].son[1]]; tb[current].son[1] ← tb[subNode].son[1]; currentEnclosing ← tb[subNode].info; body.thread ← GetNode[tb[subNode].son[2]]; tb[subNode].son[1] ← tb[subNode].son[2] ← Tree.Null; FreeNode[subNode]; IF body.thread = Tree.NullIndex AND (~dataPtr.definitionsOnly OR bb[bti].level > lL) THEN copying ← FALSE; IF ~RecursiveSubst[bti, currentEnclosing] THEN ExpandCall[current] ELSE Log.ErrorSei[recursiveInline, bb[bti].id]; ENDLOOP; END; ENDCASE => ERROR; dataPtr.textIndex ← saveIndex; END; ExpandCall: PROCEDURE [node: Tree.Index] = BEGIN typeIn, typeOut: RecordSEIndex; masterCtx: CTXIndex = bb[currentMaster].localCtx; formalCtx: CTXIndex; seChain, saveChain: ISEIndex; nAssigns, nVars: CARDINAL; extendedScope: BOOLEAN; newBti: BTIndex; t: Tree.Link; IF tb[node].name = call THEN dataPtr.textIndex ← tb[node].info; bodyNesting ← 0; IF copying OR masterCtx = CTXNull THEN copyCtx ← CTXNull ELSE BEGIN saveChain ← ctxb[masterCtx].seList; ctxb[masterCtx].seList ← ISENull; ctxb[masterCtx].level ← bb[currentEnclosing].level; copyCtx ← masterCtx; END; [typeIn, typeOut] ← TransferTypes[bb[currentMaster].ioType]; substSafe ← tb[node].attr3 AND bb[currentMaster].hints.nameSafe; nAssigns ← IF typeIn = RecordSENull THEN 0 ELSE MapArgs[seb[typeIn].fieldCtx, node]; tb[node].son[2] ← FreeTree[tb[node].son[2]]; IF typeOut # RecordSENull AND RequiredFields[seb[typeOut].fieldCtx] THEN BEGIN formalCtx ← seb[typeOut].fieldCtx; IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, CtxVars[formalCtx], TRUE]; AppendSeChain[copyCtx, seChain]; MapIds[formalCtx, seChain, 0]; END; IF tb[masterBody].son[1] # Tree.Null THEN PushTree[ExpandOpens[tb[masterBody].son[1]]]; IF masterCtx # CTXNull THEN IF ~copying THEN AppendSeChain[copyCtx, saveChain] ELSE IF (nVars ← CtxVars[masterCtx]) # 0 THEN BEGIN IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, nVars, FALSE]; MapIds[masterCtx, seChain, 0]; AppendSeChain[copyCtx, seChain]; END; -- expand the body IF copyCtx # CTXNull THEN newBti ← MakeEnclosingBody[BTNull, copyCtx]; t ← ExpandDecls[tb[masterBody].son[2]]; PushTree[ExpandTree[tb[masterBody].son[3]]]; IF copyCtx = CTXNull THEN extendedScope ← FALSE ELSE BEGIN extendedScope ← nAssigns # 0 OR tb[masterBody].son[1] # Tree.Null OR tb[masterBody].son[4] # Tree.Null; PushTree[t]; PushNode[block, -2]; SetInfo[newBti]; SetAttr[3, extendedScope]; WITH body: bb[newBti].info SELECT FROM Internal => BEGIN body.bodyTree ← GetNode[t ← PopTree[]]; PushTree[t] END; ENDCASE => ERROR; END; IF tb[masterBody].son[1] # Tree.Null THEN BEGIN PushNode[open, 2]; SetInfo[dataPtr.textIndex] END; IF tb[masterBody].son[4] # Tree.Null THEN BEGIN PushTree[ExpandTree[tb[masterBody].son[4]]]; PushNode[lock, 2]; SetInfo[dataPtr.textIndex]; END; IF masterCtx # CTXNull AND copying AND nVars # 0 THEN UnmapIds[explicit]; IF copyCtx # CTXNull THEN currentEnclosing ← ParentBti[currentEnclosing]; IF ~copying THEN PruneBody[masterBody]; -- complete the setup IF tb[node].nSons > 2 THEN BEGIN PushTree[tb[node].son[3]]; tb[node].son[3] ← Tree.Null; PushNode[enable, -2]; SetInfo[dataPtr.textIndex]; END; IF typeOut # RecordSENull AND RequiredFields[seb[typeOut].fieldCtx] THEN UnmapIds[implicit]; IF typeIn # RecordSENull THEN UnmapIds[implicit]; tb[node].son[2] ← MakeList[nAssigns+1]; IF copyCtx # CTXNull AND nAssigns # 0 THEN UpdateBodyNesting[tb[node].son[2], newBti]; tb[node].name ← IF tb[node].name = callx THEN substx ELSE subst; tb[node].attr3 ← extendedScope; ResetSharing[]; END; RecursiveSubst: PROCEDURE [bti, parent: BTIndex] RETURNS [BOOLEAN] = BEGIN UNTIL parent = BTNull DO IF bti = parent THEN RETURN [TRUE]; parent ← ParentBti[parent]; ENDLOOP; RETURN [FALSE] END; PruneBody: PROCEDURE [node: Tree.Index] = BEGIN OPEN tb[node]; son[1] ← son[2] ← son[3] ← son[4] ← Tree.Null; name ← procinit; END; -- argument list testing/processing NameSafe: PROCEDURE [sei: ISEIndex, t: Tree.Link] RETURNS [safe: BOOLEAN] = BEGIN RETURN [~bb[currentMaster].hints.argUpdated AND (substSafe OR (WITH t SELECT FROM symbol => seb[index].immutable, literal => TRUE, subtree => SELECT tb[index].name FROM cdot, uminus, loophole, clit, llit, cast, mwconst => NameSafe[sei, tb[index].son[1]], ENDCASE => FALSE, ENDCASE => FALSE))] END; CountVars: PROCEDURE [ctx: CTXIndex, t: Tree.Link] RETURNS [CARDINAL] = BEGIN n: CARDINAL; sei: ISEIndex; CountVar: Tree.Scan = BEGIN IF sei # ISENull THEN BEGIN IF ~NameSafe[sei, t] THEN n ← n+1; sei ← NextSe[sei]; END; END; n ← 0; sei ← FirstCtxSe[ctx]; ScanList[t, CountVar]; RETURN [n] END; RequiredFields: PROCEDURE [ctx: CTXIndex] RETURNS [BOOLEAN] = BEGIN sei: ISEIndex; FOR sei ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO IF seb[sei].hash = HTNull THEN RETURN [FALSE]; IF seb[sei].idInfo # 0 THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE] END; ExpandTree: Tree.Map = BEGIN sNode, dNode: Tree.Index; WITH t SELECT FROM subtree => BEGIN sNode ← index; IF tb[sNode].shared THEN v ← ExpandShared[sNode] ELSE SELECT tb[sNode].name FROM body => v ← ExpandBody[sNode]; block => v ← ExpandBlock[sNode]; do => v ← ExpandDo[sNode]; open, bind, bindx => v ← ExpandBinding[sNode]; subst, substx => v ← ExpandSubst[sNode]; thread => v ← ExpandThread[sNode]; ENDCASE => BEGIN v ← IF copying THEN CopyTree[[baseP:@tb, link:t], ExpandTree] ELSE UpdateTree[t, ExpandTree]; WITH v SELECT FROM subtree => BEGIN dNode ← index; SELECT tb[dNode].name FROM return => IF bodyNesting = 0 THEN UpdateReturn[dNode]; call, callx => IF TestTree[tb[dNode].son[1], thread] THEN ThreadSubst[sNode, dNode]; ENDCASE => NULL; END; ENDCASE => NULL; END; END; symbol => v ← ExpandSei[index]; ENDCASE => v ← t; RETURN END; ExpandBlock: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN extendedScope: BOOLEAN = tb[node].attr3; EnterBlock[node, extendedScope]; PushTree[ExpandDecls[tb[node].son[1]]]; PushTree[ExpandTree[tb[node].son[2]]]; IF copying THEN BEGIN PushNode[block, 2]; SetInfo[tb[node].info]; SetAttr[3, extendedScope]; v ← PopTree[]; END ELSE BEGIN tb[node].son[2] ← PopTree[]; tb[node].son[1] ← PopTree[]; v ← [subtree[index: node]]; END; ExitBlock[GetNode[v]]; RETURN END; ExpandBody: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN i: CARDINAL; EnterBody[node]; PushTree[ExpandOpens[tb[node].son[1]]]; PushTree[ExpandDecls[tb[node].son[2]]]; PushTree[ExpandTree[tb[node].son[3]]]; PushTree[ExpandTree[tb[node].son[4]]]; IF copying THEN BEGIN PushNode[body, 4]; SetInfo[tb[node].info]; SetAttr[1, tb[node].attr1]; SetAttr[2, tb[node].attr2]; v ← PopTree[]; END ELSE BEGIN FOR i DECREASING IN [1..4] DO tb[node].son[i] ← PopTree[] ENDLOOP; v ← [subtree[index: node]]; END; ExitBody[GetNode[v]]; RETURN END; ExpandDo: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN i: CARDINAL; FOR i IN [1..2] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; PushTree[ExpandOpens[tb[node].son[3]]]; FOR i IN [4..6] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; IF copying THEN BEGIN PushNode[do, 6]; SetInfo[tb[node].info]; SetAttr[1, tb[node].attr1]; SetAttr[2, tb[node].attr2]; v ← PopTree[]; END ELSE BEGIN FOR i DECREASING IN [1..6] DO tb[node].son[i] ← PopTree[] ENDLOOP; v ← [subtree[index: node]]; END; RETURN END; ExpandBinding: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN i: CARDINAL; nSons: CARDINAL = tb[node].nSons; PushTree[ExpandOpens[tb[node].son[1]]]; FOR i IN [2..nSons] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; IF copying THEN BEGIN PushNode[tb[node].name, nSons]; SetInfo[tb[node].info]; SetAttr[1, tb[node].attr1]; SetAttr[2, tb[node].attr2]; SetAttr[3, tb[node].attr3]; v ← PopTree[]; END ELSE BEGIN FOR i DECREASING IN [1..nSons] DO tb[node].son[i] ← PopTree[] ENDLOOP; v ← [subtree[index: node]]; END; RETURN END; ExpandSubst: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN extendedScope: BOOLEAN = tb[node].attr3; PushTree[ExpandTree[tb[node].son[1]]]; IF extendedScope THEN [] ← MapBlock[FindBlock[tb[node].son[2]]]; PushTree[ExpandTree[tb[node].son[2]]]; IF copying THEN BEGIN PushNode[tb[node].name, 2]; SetInfo[tb[node].info]; SetAttr[3, tb[node].attr3]; v ← PopTree[]; END ELSE BEGIN tb[node].son[2] ← PopTree[]; tb[node].son[1] ← PopTree[]; v ← [subtree[index: node]]; END; RETURN END; ExpandThread: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN IF ~copying THEN BEGIN tb[node].son[1] ← ExpandTree[tb[node].son[1]]; v ← [subtree[node]]; END ELSE BEGIN PushTree[ExpandTree[tb[node].son[1]]]; PushTree[Tree.Null]; PushNode[thread, 2]; SetInfo[tb[node].info]; v ← PopTree[]; END; RETURN END; UpdateReturn: PROCEDURE [node: Tree.Index] = BEGIN typeOut: RecordSEIndex; sei: ISEIndex; n: CARDINAL; IF tb[node].son[1] = Tree.Null AND (typeOut←TransferTypes[bb[currentMaster].ioType].typeOut) # RecordSENull THEN BEGIN n ← 0; FOR sei ← FirstCtxSe[seb[typeOut].fieldCtx], NextSe[sei] UNTIL sei = ISENull DO PushTree[ExpandSei[sei]]; n ← n+1 ENDLOOP; tb[node].son[1] ← MakeList[n]; END; tb[node].name ← result; END; ExpandDecls: Tree.Map = BEGIN n: CARDINAL; ExpandDecl: Tree.Scan = BEGIN node: Tree.Index; LinkDecl: Tree.Scan = BEGIN sei: ISEIndex; WITH t SELECT FROM symbol => BEGIN sei ← index; seb[sei].idValue ← node; IF ~seb[sei].mark4 AND tb[node].son[3] = Tree.Null THEN seb[sei].idInfo ← seb[sei].idInfo - 1; END; ENDCASE; END; copy: Tree.Link; IF ~TestTree[t, typedecl] THEN BEGIN PushTree[copy ← ExpandTree[t]]; n ← n+1; node ← GetNode[copy]; ScanList[tb[node].son[1], LinkDecl]; END; END; IF ~copying THEN v ← ExpandTree[t] ELSE BEGIN n ← 0; ScanList[t, ExpandDecl]; v ← MakeList[n] END; RETURN END; SharingItem: TYPE = RECORD [old, new: Tree.Link, next: SharingList]; SharingList: TYPE = POINTER TO SharingItem; sharingMap: SharingList; MapShared: PROCEDURE [t, v: Tree.Link] = BEGIN p: SharingList ← SystemDefs.AllocateHeapNode[SIZE[SharingItem]]; p↑ ← [old:t, new:v, next:sharingMap]; sharingMap ← p; SetShared[v, TRUE]; END; ExpandShared: PROCEDURE [node: Tree.Index] RETURNS [v: Tree.Link] = BEGIN p: SharingList; UpdateCount: Tree.Map = BEGIN WITH t SELECT FROM symbol => IncrCount[index]; subtree => [] ← UpdateTree[t, UpdateCount]; ENDCASE => NULL; RETURN [t] END; t: Tree.Link = [subtree[index: node]]; FOR p ← sharingMap, p.next UNTIL p = NIL DO IF p.old = t THEN GO TO Found; REPEAT Found => v ← p.new; FINISHED => v ← t; ENDLOOP; IF copying THEN [] ← UpdateCount[v]; RETURN END; ResetSharing: PROCEDURE = BEGIN p: SharingList; UNTIL sharingMap = NIL DO p ← sharingMap; sharingMap ← sharingMap.next; SystemDefs.FreeHeapNode[p]; ENDLOOP; END; ExpandOpens: Tree.Map = BEGIN n: CARDINAL; UpdateOpen: Tree.Scan = BEGIN node: Tree.Index = GetNode[t]; base: Tree.Link; tb[node].son[1] ← ExpandTree[tb[node].son[1]]; IF ~Shared[base ← tb[node].son[2]] THEN tb[node].son[2] ← ExpandTree[base] ELSE BEGIN SetShared[base, FALSE]; base ← ExpandTree[base]; SetShared[base, TRUE]; tb[node].son[2] ← base; END; END; ExpandOpen: Tree.Scan = BEGIN node: Tree.Index = GetNode[t]; base: Tree.Link = tb[node].son[2]; copy: Tree.Link; PushTree[ExpandTree[tb[node].son[1]]]; IF ~Shared[base] THEN PushTree[ExpandTree[base]] ELSE BEGIN SetShared[base, FALSE]; PushTree[copy ← ExpandTree[base]]; SetShared[base, TRUE]; MapShared[base, copy]; END; PushNode[item, 2]; SetInfo[tb[node].info]; n ← n+1; END; IF ~copying THEN BEGIN ScanList[t, UpdateOpen]; v ← t END ELSE BEGIN n ← 0; ScanList[t, ExpandOpen]; v ← MakeList[n] END; RETURN END; -- blocks and bodies FindBlock: PROCEDURE [t: Tree.Link] RETURNS [node: Tree.Index] = BEGIN DO node ← GetNode[t]; SELECT tb[node].name FROM list => t ← ListTail[t]; block => EXIT; open, enable => t ← tb[node].son[2]; lock => t ← tb[node].son[1]; ENDCASE => ERROR; ENDLOOP; RETURN END; EnterBlock: PROCEDURE [node: Tree.Index, extendedScope: BOOLEAN] = BEGIN oldBti: BTIndex = tb[node].info; oldCtx: CTXIndex = bb[oldBti].localCtx; newBti: BTIndex; newCtx: CTXIndex; newCtx ← SELECT TRUE FROM ~extendedScope => MapBlock[node], oldCtx = CTXNull, ~copying => oldCtx, aStack = NIL OR aStack.ctx # oldCtx => ERROR, ENDCASE => ImageContext[aStack]; newBti ← MakeEnclosingBody[IF copying THEN BTNull ELSE oldBti, newCtx]; END; MapBlock: PROCEDURE [node: Tree.Index] RETURNS [newCtx: CTXIndex] = BEGIN oldBti: BTIndex = tb[node].info; oldCtx: CTXIndex = bb[oldBti].localCtx; seChain: ISEIndex; SELECT TRUE FROM oldCtx = CTXNull => newCtx ← CTXNull; ~copying => BEGIN newCtx ← oldCtx; ctxb[newCtx].level ← bb[currentEnclosing].level; END; ENDCASE => BEGIN newCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[newCtx, CtxVars[oldCtx], FALSE]; AppendSeChain[newCtx, seChain]; MapIds[oldCtx, seChain, 0]; END; RETURN END; ImageContext: PROCEDURE [aLink: AList] RETURNS [CTXIndex] = BEGIN RETURN [IF aLink.nItems = 0 THEN CTXNull ELSE WITH aLink.map[0].val SELECT FROM symbol => seb[index].idCtx, ENDCASE => ERROR] END; ExitBlock: PROCEDURE [node: Tree.Index] = BEGIN oldBti: BTIndex = tb[node].info; newBti: BTIndex = currentEnclosing; tb[node].info ← newBti; WITH body: bb[newBti].info SELECT FROM Internal => body.bodyTree ← node; ENDCASE; IF copying AND bb[oldBti].localCtx # CTXNull THEN UnmapIds[explicit]; currentEnclosing ← ParentBti[currentEnclosing]; END; MakeEnclosingBody: PROCEDURE [oldBti: BTIndex, ctx: CTXIndex] RETURNS [newBti: BTIndex] = BEGIN newSon: BTIndex; IF oldBti = BTNull THEN BEGIN newBti ← Table.Allocate[bodyType, SIZE[Other BodyRecord]]; newSon ← BTNull; END ELSE BEGIN newSon ← bb[oldBti].firstSon; DelinkBti[oldBti]; newBti ← oldBti; END; bb[newBti] ← BodyRecord[ link: , firstSon: newSon, localCtx: ctx, level: bb[currentEnclosing].level, info: BodyInfo[Internal[ bodyTree: Tree.NullIndex, sourceIndex: , thread: Tree.NullIndex, frameSize: ]], extension: Other[]]; LinkBti[bti: newBti, parent: currentEnclosing]; currentEnclosing ← newBti; RETURN END; EnterBody: PROCEDURE [node: Tree.Index] = BEGIN oldBti: CBTIndex = tb[node].info; newBti: CBTIndex; type: CSEIndex; level: ContextLevel = NextLevel[bb[currentEnclosing].level !StaticNestError => BEGIN Log.Error[staticNesting]; RESUME END]; SetArgLevel: PROCEDURE [sei: RecordSEIndex] = BEGIN IF sei # RecordSENull THEN ctxb[seb[sei].fieldCtx].level ← level; END; bodyNesting ← bodyNesting + 1; IF ~copying THEN DelinkBti[oldBti]; IF ~copying AND (bb[oldBti].level > lL) = (level > lL) THEN BEGIN newBti ← oldBti; type ← bb[oldBti].ioType END ELSE BEGIN id: ISEIndex; ctx: CTXIndex; IF level > lL THEN BEGIN newBti ←Table.Allocate[bodyType, SIZE[Inner Callable BodyRecord]]; bb[newBti] ← [,,,,, Callable[,,,,,,,,,, Inner[frameOffset: ]]]; END ELSE BEGIN newBti ←Table.Allocate[bodyType, SIZE[Outer Callable BodyRecord]]; bb[newBti] ← [,,,,, Callable[,,,,,,,,,, Outer[]]]; END; IF ~copying THEN BEGIN id ← bb[oldBti].id; type ← bb[oldBti].ioType; ctx ← bb[oldBti].localCtx; ctxb[ctx].level ← level; bb[newBti].firstSon ← bb[oldBti].firstSon; END ELSE BEGIN oldCtx: CTXIndex; IF (id ← bb[oldBti].id) # ISENull THEN id ← SearchContext[seb[id].hash, bb[currentEnclosing].localCtx]; type ← Copier.CopyXferType[bb[oldBti].ioType]; MapFormals[oldType: bb[oldBti].ioType, newType: type]; IF (oldCtx ← bb[oldBti].localCtx) = CTXNull THEN ctx ← CTXNull ELSE BEGIN ctx ← NewCtx[level]; ctxb[ctx].seList ← MakeSeChain[ctx, CtxVars[oldCtx], FALSE]; MapIds[oldCtx, ctxb[ctx].seList, 0]; END; bb[newBti].firstSon ← BTNull; dataPtr.nBodies ← dataPtr.nBodies+1; END; bb[newBti].localCtx ← ctx; bb[newBti].info ← bb[oldBti].info; bb[newBti].inline ← bb[oldBti].inline; bb[newBti].resident ← bb[oldBti].resident; bb[newBti].id ← id; bb[newBti].ioType ← type; bb[newBti].monitored ← bb[oldBti].monitored; bb[newBti].stopping ← bb[oldBti].stopping; bb[newBti].entry ← bb[oldBti].entry; bb[newBti].internal ← bb[oldBti].internal; bb[newBti].hints ← bb[oldBti].hints; END; bb[newBti].level ← level; WITH seb[type] SELECT FROM transfer => BEGIN SetArgLevel[inRecord]; SetArgLevel[outRecord] END; ENDCASE; LinkBti[bti: newBti, parent: currentEnclosing]; currentEnclosing ← newBti; END; ExitBody: PROCEDURE [node: Tree.Index] = BEGIN newBti: CBTIndex = LOOPHOLE[currentEnclosing]; ExitBlock[node]; IF copying THEN UnmapFormals[bb[newBti].ioType]; bodyNesting ← bodyNesting - 1; END; UpdateBodyNesting: PROCEDURE [list: Tree.Link, newBti: BTIndex] = BEGIN oldBti: BTIndex = ParentBti[newBti]; UpdateLinks: Tree.Map = BEGIN node: Tree.Index; WITH t SELECT FROM subtree => BEGIN node ← index; SELECT tb[node].name FROM block => BEGIN bti: BTIndex = tb[node].info; IF ParentBti[bti] = oldBti THEN BEGIN DelinkBti[bti]; LinkBti[bti, newBti] END; v ← t; END; thread => BEGIN IF tb[node].info = oldBti THEN tb[node].info ← newBti; tb[node].son[1] ← UpdateTree[tb[node].son[1], UpdateLinks]; v ← t; END; ENDCASE => v ← UpdateTree[t, UpdateLinks]; END; ENDCASE => v ← t; END; UpdateItem: Tree.Scan = BEGIN node: Tree.Index; WITH t SELECT FROM subtree => BEGIN node ← index; IF tb[node].name = assign THEN tb[node].son[2] ← UpdateTree[tb[node].son[2], UpdateLinks]; END; ENDCASE; END; ScanList[list, UpdateItem]; END; -- id translation AppendSeChain: PROCEDURE [ctx: CTXIndex, chain: ISEIndex] = BEGIN last, next: ISEIndex; SELECT TRUE FROM chain = ISENull => NULL; (last ← ctxb[ctx].seList) = ISENull => ctxb[ctx].seList ← chain; ENDCASE => BEGIN UNTIL (next ← NextSe[last]) = ISENull DO last ← next ENDLOOP; SetSeLink[last, chain]; END; END; CtxVars: PROCEDURE [ctx: CTXIndex] RETURNS [n: CARDINAL] = BEGIN sei: ISEIndex; n ← 0; FOR sei ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO IF seb[sei].idType # typeTYPE THEN n ← n+1; ENDLOOP; RETURN END; AllocateAList: PROCEDURE [ctx: CTXIndex] RETURNS [aLink: AList] = BEGIN maxItems: CARDINAL = CtxEntries[ctx]; aLink ← SystemDefs.AllocateHeapNode[SIZE[ANode] + maxItems*SIZE[AItem]]; aLink↑ ← [next:NIL, ctx:ctx, nItems:0, map:]; END; FreeAList: PROCEDURE [aLink: AList] = SystemDefs.FreeHeapNode; -- mapping MapArgs: PROCEDURE [formalCtx: CTXIndex, node: Tree.Index] RETURNS [nAssigns: CARDINAL] = BEGIN nVars: CARDINAL; seChain: ISEIndex; sei1, sei2: ISEIndex; aLink: AList; MapArg: Tree.Map = BEGIN name: BOOLEAN; val: Tree.Link; IF sei1 = ISENull THEN v ← t ELSE BEGIN IF TestTree[t, safen] THEN BEGIN node: Tree.Index ← GetNode[t]; t ← tb[node].son[1]; tb[node].son[1] ← Tree.Null; FreeNode[node]; END; IF NameSafe[sei1, t] THEN BEGIN name ← TRUE; val ← t END ELSE BEGIN Copier.CopyArgSe[sei2, sei1]; IF seb[sei2].mark4 THEN seb[sei2].idValue ← Tree.NullIndex; seb[sei2].mark4 ← FALSE; seb[sei2].idInfo ← 0; name ← FALSE; val ← [symbol[index: sei2]]; IF t # Tree.Null THEN BEGIN PushTree[val]; PushTree[t]; PushNode[assign, 2]; SetInfo[dataPtr.textIndex]; IncrCount[sei2]; nAssigns ← nAssigns + 1; END; sei2 ← NextSe[sei2]; END; aLink.map[aLink.nItems] ← [id: sei1, name: name, val: val]; aLink.nItems ← aLink.nItems + 1; sei1 ← NextSe[sei1]; v ← Tree.Null; END; RETURN END; aLink ← AllocateAList[formalCtx]; IF (nVars ← CountVars[formalCtx, tb[node].son[2]]) = 0 THEN seChain ← ISENull ELSE BEGIN IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, nVars, TRUE]; AppendSeChain[copyCtx, seChain]; END; sei1 ← FirstCtxSe[formalCtx]; sei2 ← seChain; nAssigns ← 0; tb[node].son[2] ← UpdateList[tb[node].son[2], MapArg]; PushAList[aLink]; RETURN END; MapIds: PROCEDURE [ctx: CTXIndex, chain: ISEIndex, nRefs: [0..1]] = BEGIN sei1, sei2: ISEIndex; aLink: AList = AllocateAList[ctx]; sei1 ← FirstCtxSe[ctx]; sei2 ← chain; UNTIL sei1 = ISENull DO IF seb[sei1].idType # typeTYPE THEN BEGIN Copier.CopyArgSe[sei2, sei1]; IF seb[sei2].mark4 THEN seb[sei2].idValue ← Tree.NullIndex; seb[sei2].idInfo ← nRefs; aLink.map[aLink.nItems] ← [id: sei1, name: FALSE, val: [symbol[index:sei2]]]; aLink.nItems ← aLink.nItems + 1; sei2 ← NextSe[sei2]; END; sei1 ← NextSe[sei1]; ENDLOOP; PushAList[aLink]; END; UnmapIds: PROCEDURE [decl: {implicit, explicit}] = BEGIN i: CARDINAL; aLink: AList ← PopAList[]; FOR i IN [0..aLink.nItems) DO WITH aLink.map[i].val SELECT FROM symbol => IF decl = implicit AND ~aLink.map[i].name THEN seb[index].mark4 ← TRUE; ENDCASE; aLink.map[i].val ← FreeTree[aLink.map[i].val]; ENDLOOP; FreeAList[aLink]; END; MapFields: PROCEDURE [oldRecord, newRecord: RecordSEIndex, nRefs: [0..1]] = BEGIN sei1, sei2: ISEIndex; aLink: AList; IF oldRecord # RecordSENull THEN BEGIN aLink ← AllocateAList[seb[oldRecord].fieldCtx]; sei1 ← FirstCtxSe[seb[oldRecord].fieldCtx]; sei2 ← FirstCtxSe[seb[newRecord].fieldCtx]; UNTIL sei1 = ISENull DO seb[sei2].idInfo ← nRefs; aLink.map[aLink.nItems] ← [id: sei1, name: FALSE, val: [symbol[index:sei2]]]; aLink.nItems ← aLink.nItems + 1; sei1 ← NextSe[sei1]; sei2 ← NextSe[sei2]; ENDLOOP; PushAList[aLink]; END; END; MapFormals: PROCEDURE [oldType, newType: CSEIndex] = BEGIN WITH new: seb[newType] SELECT FROM transfer => WITH old: seb[oldType] SELECT FROM transfer => BEGIN MapFields[old.inRecord, new.inRecord, 1]; MapFields[old.outRecord, new.outRecord, 0]; END; ENDCASE => ERROR; ENDCASE; END; UnmapFormals: PROCEDURE [type: CSEIndex] = BEGIN WITH seb[type] SELECT FROM transfer => BEGIN IF outRecord # RecordSENull THEN UnmapIds[implicit]; IF inRecord # RecordSENull THEN UnmapIds[implicit]; END; ENDCASE; END; -- association lists PushAList: PROCEDURE [aLink: AList] = BEGIN aLink.next ← aStack; aStack ← aLink; END; PopAList: PROCEDURE RETURNS [aLink: AList] = BEGIN IF aStack = NIL THEN ERROR; aLink ← aStack; aStack ← aLink.next; END; ExpandSei: PROCEDURE [sei: ISEIndex] RETURNS [v: Tree.Link] = BEGIN aLink: AList; i: CARDINAL; FOR aLink ← aStack, aLink.next UNTIL aLink = NIL DO IF seb[sei].idCtx = aLink.ctx THEN FOR i IN [0 .. aLink.nItems) DO IF aLink.map[i].id = sei THEN GO TO Found; ENDLOOP; REPEAT Found => BEGIN saveCopying: BOOLEAN = copying; copying ← TRUE; v ← ExpandTree[aLink.map[i].val]; copying ← saveCopying; END; FINISHED => BEGIN IF copying THEN IncrCount[sei]; v ← [symbol[index:sei]]; END; ENDLOOP; RETURN END; IncrCount: PROCEDURE [sei: ISEIndex] = -- modified BumpCount (Pass3I) BEGIN ctx: CTXIndex; IF seb[sei].idType # typeTYPE AND (~seb[sei].mark4 OR (~seb[sei].constant AND (ctx ← seb[sei].idCtx) ~IN StandardContext AND ctxb[ctx].ctxType # included)) THEN seb[sei].idInfo ← seb[sei].idInfo + 1; END; -- nested calls ThreadSubst: PROCEDURE [sNode, dNode: Tree.Index] = BEGIN sThread, dThread: Tree.Index; dThread ← GetNode[tb[dNode].son[1]]; IF sNode # Tree.NullIndex AND sNode # dNode THEN BEGIN DO sThread ← GetNode[tb[sNode].son[1]]; IF tb[sThread].son[2] = Tree.Null THEN EXIT; sNode ← GetNode[tb[sThread].son[2]]; ENDLOOP; tb[sThread].son[2] ← [subtree[index: dNode]]; tb[dThread].son[2] ← Tree.Null; END; tb[dThread].info ← currentEnclosing; END; END.