<<>> <> <> <> <> <<>> DIRECTORY Alloc USING [Notifier], MimData USING [bodyIndex, idANY, idBOOL, monitored, ownSymbols, textIndex], MimosaLog USING [Error, ErrorSei, ErrorTree, ErrorTreeOp, ErrorType, Warning, WarningTree], MimP3 USING [And, Apply, Assignment, Attr, BoundNP, BumpCount, CheckDisjoint, checkedANY, ClearRefStack, ClearType, CloseBase, CopyLock, DeclList, Discrimination, EnterComposite, EnterType, Exp, Extract, FieldDefault, FindLockParams, FirstId, InsertCatchLabel, lockNode, LockVar, MatchFields, MiscStmt, NPUse, OpenBase, phraseNP, PopCtx, PushCtx, Range, RAttr, RAttrPop, RecordMention, Rhs, RPop, RPush, RType, Safety, SealRefStack, SequenceNP, UnsealRefStack, UpdateTreeAttr, UType, voidAttr], MimP3S USING [BodyData, ImplicitInfo, implicit], Pass3Attributes USING [CanonicalType, DefaultInit, IdentifiedType, LhsMode, OperandLhs, TargetType, Voidable], SourceMap USING [Loc, nullLoc, Up], SymbolOps USING [CopyBasicType, CtxLevel, EncodeCard, EncodeTreeIndex, EncodeType, FirstCtxSe, FromType, NextSe, own, RCType, SetCtxLevel, ToBti, ToCtx, TransferTypes, TypeForm, UnderType], Symbols USING [Base, bodyType, BTIndex, BTNull, CBTIndex, ContextLevel, CSEIndex, CSENull, CTXIndex, CTXNull, ctxType, HTNull, ISEIndex, ISENull, lG, mdType, RecordSEIndex, RecordSENull, RootBti, seType, Type, typeANY], SymLiteralOps USING [DescribeRefLits], Tree USING [Base, Index, Link, Map, NodeName, Null, Scan, nullId, nullIndex, treeType], TreeOps USING [FreeNode, FromLoc, GetHash, GetNode, GetTag, MakeList, NthSon, OpName, PopTree, PushNode, PushTree, ReverseScanList, ScanList, SetAttr, SetInfo, ToLoc, UpdateList], Types USING [Assignable]; Pass3S: PROGRAM IMPORTS MimData, MimosaLog, MimP3, MimP3S, Pass3Attributes, SourceMap, SymbolOps, SymLiteralOps, TreeOps, Types EXPORTS MimP3, MimP3S = { OPEN MimP3, Pass3Attributes, Symbols, 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 = { <> tb ¬ base[Tree.treeType]; seb ¬ base[seType]; ctxb ¬ base[ctxType]; mdb ¬ base[mdType]; bb ¬ base[bodyType]; }; <> pathNP: PUBLIC NPUse ¬ none; <> currentBody: PUBLIC MimP3S.BodyData; current: POINTER TO MimP3S.BodyData = @currentBody; currentScope: PUBLIC BTIndex ¬ BTNull; safety: PUBLIC Safety ¬ none; exits: BOOL; BodyList: PUBLIC PROC [firstBti: BTIndex] = { bti: BTIndex ¬ firstBti; IF bti # BTNull THEN DO WITH b: bb[bti] SELECT FROM Callable => IF b.kind # Catch THEN Body[LOOPHOLE[bti, CBTIndex]]; ENDCASE; IF bb[bti].link.which = parent THEN EXIT; bti ¬ bb[bti].link.index; ENDLOOP; }; Body: PROC [bti: CBTIndex] = { saved: MimP3S.BodyData = current­; saveIndex: SourceMap.Loc = MimData.textIndex; saveBodyIndex: CBTIndex = MimData.bodyIndex; saveScope: BTIndex = currentScope; saveSafety: Safety = safety; node: Tree.Index; lockVar: ISEIndex; lockBit: BOOL; inRecord, outRecord, bType: RecordSEIndex; argLevel: ContextLevel; MimData.bodyIndex ¬ currentScope ¬ bti; MimData.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] ¬ SymbolOps.TransferTypes[SymbolOps.own, bb[bti].ioType]; IF inRecord = RecordSENull THEN current.argCtx ¬ CTXNull ELSE { current.argCtx ¬ seb[inRecord].fieldCtx; SymbolOps.SetCtxLevel[current.argCtx, argLevel]; IF argLevel = lG THEN EnterTypes[current.argCtx]; }; IF outRecord # RecordSENull THEN { SymbolOps.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[]; <> 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; }; { ENABLE InsertCatchLabel => {MimosaLog.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 MimData.monitored THEN { PushCtx[SymbolOps.ToCtx[tb[MimP3.lockNode].info]]; DeclList[tb[MimP3.lockNode].son[1]]; IF (lockVar ¬ SymbolOps.FirstCtxSe[SymbolOps.own, SymbolOps.ToCtx[tb[MimP3.lockNode].info]]) # ISENull THEN BumpCount[lockVar]; tb[MimP3.lockNode].son[2] ¬ LockVar[tb[MimP3.lockNode].son[2]]; PopCtx[]; ClearRefStack[FALSE]; }; DeclList[tb[node].son[2]]; IF outInit # Tree.Null THEN { PushTree[outInit]; PushTree[tb[node].son[2]]; PushNode[initlist, 2]; SetInfo[FromLoc[MimData.textIndex]]; tb[node].son[2] ¬ PopTree[]; }; }; bType ¬ bb[bti].type; IF bType # RecordSENull THEN { IF bti = RootBti THEN { EnterTypes[seb[bType].fieldCtx]; FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, seb[bType].fieldCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO IF ~seb[sei].constant AND SymbolOps.RCType[SymbolOps.own, SymbolOps.UnderType[SymbolOps.own, seb[sei].idType]] # none THEN { seb[bType].hints.refField ¬ TRUE; EnterType[bType]; EXIT; } ENDLOOP; }; seb[bType].mark3 ¬ TRUE; }; current.reachable ¬ TRUE; tb[node].son[3] ¬ UpdateList[tb[node].son[3], Stmt ! InsertCatchLabel => {IF ~catchSeen THEN MimosaLog.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]; MimData.bodyIndex ¬ saveBodyIndex; MimData.textIndex ¬ saveIndex; }; Scope: PUBLIC PROC [node: Tree.Index, body: Tree.Map] = { bti: BTIndex = SymbolOps.ToBti[tb[node].info]; saveIndex: SourceMap.Loc = MimData.textIndex; saveScope: BTIndex = currentScope; MimData.textIndex ¬ SourceMap.Up[bb[bti].sourceIndex]; currentScope ¬ bti; PushCtx[bb[bti].localCtx]; DeclList[tb[node].son[1] ! InsertCatchLabel => {MimosaLog.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; MimData.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: NAT] = { IF rSei # RecordSENull THEN { seb[rSei].mark4 ¬ FALSE; FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, seb[rSei].fieldCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO IF seb[sei].mark4 THEN { seb[sei].idValue ¬ SymbolOps.EncodeTreeIndex[Tree.nullIndex]; seb[sei].mark4 ¬ FALSE; }; seb[sei].idInfo ¬ SymbolOps.EncodeCard[nRefs]; ENDLOOP; }; }; EnterTypes: PROC [ctx: CTXIndex] = { FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, ctx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO ut: Type = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType]; IF SymbolOps.RCType[SymbolOps.own, ut] = composite THEN EnterType[ut]; ENDLOOP; }; AssignDefaults: PUBLIC PROC [ctx: CTXIndex, copyable: BOOL] RETURNS [Tree.Link] = { n: INTEGER ¬ 0; FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, ctx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO IF seb[sei].hash # Symbols.HTNull OR seb[sei].extended THEN { 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 MimosaLog.ErrorSei[missingInit, sei]; } ELSE { lhs: Tree.Link = [symbol[sei]]; mode: LhsMode; RecordMention[sei]; mode ¬ OperandLhs[lhs]; PushTree[lhs]; PushTree[t]; PushNode[assign, 2]; SetInfo[FromLoc[MimData.textIndex]]; SetAttr[1, TRUE]; IF mode # counted THEN SetAttr[2, FALSE] ELSE { type: Type = seb[sei].idType; SELECT SymbolOps.RCType[SymbolOps.own, 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]; }; <<<>>> <> <> n ¬ n+1; pathNP ¬ SequenceNP[pathNP][phraseNP]; ClearRefStack[]; }; RPop[]; }; ENDLOOP; RETURN [MakeList[n]]; }; 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 MimP3.checkedANY = CSENull THEN MimP3.checkedANY ¬ SymbolOps.CopyBasicType[typeANY]; seb[MimData.idANY].idInfo ¬ SymbolOps.EncodeType[MimP3.checkedANY]; }; ENDCASE => seb[MimData.idANY].idInfo ¬ SymbolOps.EncodeType[typeANY]; safety ¬ new; } }; <> continued: PUBLIC BOOL ¬ FALSE; markCatch: PUBLIC BOOL ¬ FALSE; SourceSeen: SIGNAL [index: SourceMap.Loc] = CODE; sourceBreak: SourceMap.Loc ¬ SourceMap.nullLoc; Stmt: PUBLIC PROC [stmt: Tree.Link] RETURNS [val: Tree.Link] = { saveIndex: SourceMap.Loc = MimData.textIndex; saveMark: BOOL = markCatch; saveContinued: BOOL = continued; IF stmt = Tree.Null THEN RETURN [Tree.Null]; WITH stmt SELECT GetTag[stmt] FROM subtree => { node: Tree.Index ¬ index; name: Tree.NodeName ¬ tb[node].name; fIndex: SourceMap.Loc ¬ MimData.textIndex ¬ ToLoc[tb[node].info]; IF tb[node].free THEN ERROR; IF fIndex = sourceBreak AND fIndex # SourceMap.nullLoc THEN <> SIGNAL SourceSeen[fIndex]; IF ~current.reachable AND tb[node].name # list THEN { MimosaLog.Warning[unreachable]; current.reachable ¬ TRUE; }; val ¬ stmt; -- the default markCatch ¬ continued ¬ FALSE; SELECT name FROM assign => { Assignment[node]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; }; extract => { Extract[node]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; }; apply => { node ¬ Apply[node, typeANY, TRUE]; val ¬ [subtree[node]]; SELECT tb[node].name FROM wait => MimosaLog.ErrorTree[typeClash, tb[node].son[1]]; error => current.reachable ¬ FALSE; ENDCASE; SELECT RType[] FROM CSENull, typeANY => NULL; ENDCASE => MimosaLog.Error[nonVoidStmt]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; }; block => { saveSafety: Safety = safety; SetSafety[SafetyAttr[node]]; IF saveSafety = checked AND safety = none THEN MimosaLog.Error[unsafeBlock]; Scope[node, Stmt]; SetSafety[saveSafety]; }; if => { saveReachable: BOOL; entryNP, saveNP: NPUse; tb[node].son[1] ¬ Rhs[tb[node].son[1], MimData.idBOOL]; RPop[]; pathNP ¬ entryNP ¬ SequenceNP[pathNP][phraseNP]; ClearRefStack[]; tb[node].son[2] ¬ UpdateList[tb[node].son[2], Stmt]; saveReachable ¬ current.reachable; saveNP ¬ pathNP; current.reachable ¬ TRUE; pathNP ¬ entryNP; tb[node].son[3] ¬ UpdateList[tb[node].son[3], Stmt]; IF saveReachable THEN current.reachable ¬ TRUE; pathNP ¬ BoundNP[saveNP][pathNP]; }; case, bind => { saveNP: NPUse = pathNP; Selection: Tree.Map = { current.reachable ¬ TRUE; pathNP ¬ SequenceNP[saveNP][phraseNP]; v ¬ Stmt[t]; IF current.reachable THEN newReachable ¬ TRUE; newNP ¬ BoundNP[newNP][pathNP]; }; newReachable: BOOL ¬ FALSE; newNP: NPUse ¬ none; IF name = case THEN Case[node, Selection] ELSE Discrimination[node, Selection]; RPop[]; current.reachable ¬ newReachable; pathNP ¬ newNP; }; do => DoStmt[node]; label => { son2: Tree.Link ¬ tb[node].son[2]; InsertLabels[son2]; tb[node].son[1] ¬ UpdateList[tb[node].son[1], Stmt]; DeleteLabels[son2]; LabelList[son2]; }; goto => { ValidateLabel[tb[node].son[1]]; current.reachable ¬ FALSE; }; return => Return[node]; exit, loop => { IF tb[node].name = exit THEN exits ¬ TRUE; IF current.loopDepth = 0 THEN MimosaLog.Error[exit]; current.reachable ¬ FALSE; }; null => NULL; syserror => current.reachable ¬ FALSE; open => { ScanList[tb[node].son[1], OpenItem]; tb[node].son[2] ¬ UpdateList[tb[node].son[2], Stmt]; ReverseScanList[tb[node].son[1], CloseItem]; }; checked => { saveSafety: Safety = safety; SetSafety[SafetyAttr[node]]; IF saveSafety = checked AND safety = none THEN MimosaLog.Error[unsafeBlock]; tb[node].son[1] ¬ Stmt[tb[node].son[1]]; SetSafety[saveSafety]; }; list => val ¬ UpdateList[val, Stmt]; ENDCASE => val ¬ MiscStmt[node]; }; ENDCASE => ERROR; IF markCatch THEN { PushTree[val]; PushNode[catchmark, 1]; SetInfo[FromLoc[MimData.textIndex]]; val ¬ PopTree[]; IF continued THEN current.reachable ¬ TRUE; pathNP ¬ unsafe; }; markCatch ¬ saveMark; continued ¬ saveContinued; ClearRefStack[]; MimData.textIndex ¬ saveIndex; }; <> Case: PUBLIC PROC [node: Tree.Index, selection: Tree.Map] = { saveImplicit: MimP3S.ImplicitInfo = MimP3S.implicit; entryNP: NPUse; attr: Attr; eqTests: BOOL; CaseItem: Tree.Scan = { switchable: BOOL ¬ FALSE; saveIndex: SourceMap.Loc = MimData.textIndex; CaseTest: Tree.Map = { IF t # Tree.Null THEN WITH e: t SELECT GetTag[t] FROM subtree => { node: Tree.Index = e.index; SELECT tb[node].name FROM relE => { son2: Tree.Link ¬ tb[node].son[2] ¬ Rhs[tb[node].son[2], TargetType[MimP3S.implicit.type]]; type: Type ¬ RType[]; tb[node].info ¬ SymbolOps.FromType[MimData.idBOOL]; SELECT SymbolOps.TypeForm[SymbolOps.own, type] FROM $real => {tb[node].attr1 ¬ TRUE; tb[node].attr2 ¬ FALSE}; ENDCASE => { IF OpName[son2] = shorten THEN MimosaLog.ErrorTree[typeClash, NthSon[son2, 1]]; tb[node].attr1 ¬ tb[node].attr2 ¬ FALSE; }; switchable ¬ switchable AND RAttr[].const; v ¬ t; }; ENDCASE => { v ¬ Rhs[t, MimData.idBOOL]; eqTests ¬ switchable ¬ FALSE; }; attr ¬ And[RAttrPop[], attr]; entryNP ¬ SequenceNP[entryNP][phraseNP]; }; ENDCASE; }; IF t # Tree.Null THEN WITH e: t SELECT GetTag[t] FROM subtree => { node: Tree.Index = e.index; IF OpName[tb[node].son[1]] = decl THEN { bti: BTIndex = SymbolOps.ToBti[tb[node].info]; Item: Tree.Map = {phraseNP ¬ entryNP; v ¬ selection[t]}; MimData.textIndex ¬ SourceMap.Up[bb[bti].sourceIndex]; MimosaLog.Error[discrimForm]; switchable ¬ FALSE; Scope[node, Item]; } ELSE { MimData.textIndex ¬ ToLoc[tb[node].info]; switchable ¬ TRUE; tb[node].son[1] ¬ UpdateList[tb[node].son[1], CaseTest]; tb[node].attr1 ¬ switchable; phraseNP ¬ entryNP; tb[node].son[2] ¬ selection[tb[node].son[2]]; }; MimData.textIndex ¬ saveIndex; }; ENDCASE; }; SealRefStack[]; tb[node].son[1] ¬ Exp[tb[node].son[1], typeANY]; MimP3S.implicit.type ¬ CanonicalType[RType[]]; MimP3S.implicit.attr ¬ attr ¬ RAttrPop[]; entryNP ¬ phraseNP; IF ~IdentifiedType[MimP3S.implicit.type] THEN MimosaLog.ErrorTreeOp[missingOp, tb[node].son[1], relE]; MimP3S.implicit.tree ¬ tb[node].son[1]; eqTests ¬ TRUE; UnsealRefStack[]; ScanList[tb[node].son[2], CaseItem]; tb[node].attr1 ¬ eqTests; tb[node].attr2 ¬ attr.const; phraseNP ¬ entryNP; tb[node].son[3] ¬ selection[tb[node].son[3]]; RPush[CSENull, attr]; MimP3S.implicit ¬ saveImplicit; }; <> DoStmt: PROC [node: Tree.Index] = { forNode: Tree.Index; cvType: Type; controlled, block, cvUpdate, newReachable, saveExits: BOOL; saveNP, exitNP: NPUse; saveScope: BTIndex = currentScope; newReachable ¬ controlled ¬ block ¬ cvUpdate ¬ FALSE; IF tb[node].son[1] # Tree.Null THEN { sei: ISEIndex; mode: LhsMode; forNode ¬ GetNode[tb[node].son[1]]; IF tb[forNode].son[1] = Tree.Null THEN { sei ¬ ISENull; mode ¬ uncounted; cvType ¬ typeANY; } ELSE { IF OpName[tb[forNode].son[1]] # decl THEN { tb[forNode].son[1] ¬ Exp[tb[forNode].son[1], typeANY]; IF (mode ¬ OperandLhs[tb[forNode].son[1]]) = none THEN MimosaLog.ErrorTree[nonLHS, tb[forNode].son[1]]; sei ¬ WITH tb[forNode].son[1] SELECT GetTag[tb[forNode].son[1]] FROM symbol => index, ENDCASE => ISENull; } ELSE { bti: BTIndex = SymbolOps.ToBti[tb[forNode].info]; declNode: Tree.Index = GetNode[tb[forNode].son[1]]; block ¬ TRUE; currentScope ¬ bti; PushCtx[bb[bti].localCtx]; DeclList[tb[forNode].son[1]]; sei ¬ FirstId[declNode]; seb[sei].immutable ¬ TRUE; RPush[seb[sei].idType, voidAttr]; mode ¬ IF SymbolOps.CtxLevel[SymbolOps.own, seb[sei].idCtx] = lG THEN counted ELSE uncounted; }; IF sei # ISENull THEN { <> BumpCount[sei]; BumpCount[sei]; } ELSE MimosaLog.ErrorTree[controlId, tb[forNode].son[1]]; cvType ¬ TargetType[RType[]]; RPop[]; }; SELECT mode FROM counted => SELECT SymbolOps.RCType[SymbolOps.own, cvType] FROM simple => {tb[forNode].attr2 ¬ TRUE; tb[forNode].attr3 ¬ FALSE}; composite => tb[forNode].attr2 ¬ tb[forNode].attr3 ¬ TRUE; ENDCASE => tb[forNode].attr2 ¬ FALSE; ENDCASE => tb[forNode].attr2 ¬ FALSE; SELECT tb[forNode].name FROM forseq => { son2: Tree.Link ¬ tb[forNode].son[2] ¬ Rhs[tb[forNode].son[2], cvType]; RPop[]; IF tb[forNode].attr2 AND tb[forNode].attr3 THEN EnterComposite[cvType, tb[forNode].son[2], OpName[tb[forNode].son[1]] = decl]; cvUpdate ¬ TRUE; }; upthru, downthru => { son2: Tree.Link ¬ tb[forNode].son[2] ¬ Range[tb[forNode].son[2], cvType]; lType: CSEIndex = SymbolOps.UnderType[SymbolOps.own, cvType]; rType: CSEIndex = UType[]; controlled ¬ TRUE; IF NOT Types.Assignable[ [MimData.ownSymbols, lType], [MimData.ownSymbols, rType]] THEN { SELECT SymbolOps.TypeForm[SymbolOps.own, ClearType[lType]] FROM signed, unsigned => SELECT SymbolOps.TypeForm[SymbolOps.own, ClearType[rType]] FROM signed, unsigned => GO TO matched; ENDCASE; ENDCASE; MimosaLog.ErrorType[typeClash, son2, [MimData.ownSymbols, cvType]]; EXITS matched => {}; }; RPop[]; }; ENDCASE => ERROR; pathNP ¬ SequenceNP[pathNP][phraseNP]; ClearRefStack[]; }; saveNP ¬ pathNP; pathNP ¬ none; IF tb[node].son[2] # Tree.Null THEN { controlled ¬ TRUE; tb[node].son[2] ¬ Rhs[tb[node].son[2], MimData.idBOOL]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; ClearRefStack[]; }; ScanList[tb[node].son[3], OpenItem]; InsertLabels[tb[node].son[5]]; current.loopDepth ¬ current.loopDepth + 1; saveExits ¬ exits; exits ¬ FALSE; tb[node].son[4] ¬ UpdateList[tb[node].son[4], Stmt]; IF exits THEN newReachable ¬ TRUE; exits ¬ saveExits; DeleteLabels[tb[node].son[5]]; current.loopDepth ¬ current.loopDepth - 1; IF cvUpdate THEN { tb[forNode].son[3] ¬ Rhs[tb[forNode].son[3], cvType]; RPop[]; IF tb[forNode].attr2 AND tb[forNode].attr3 THEN EnterComposite[cvType, tb[forNode].son[3], FALSE]; pathNP ¬ SequenceNP[pathNP][phraseNP]; ClearRefStack[]; }; IF pathNP = refset THEN pathNP ¬ unsafe; saveNP ¬ pathNP ¬ SequenceNP[saveNP][pathNP]; IF tb[node].son[5] # Tree.Null THEN { current.reachable ¬ FALSE; LabelList[tb[node].son[5]]; IF current.reachable THEN newReachable ¬ TRUE; }; exitNP ¬ pathNP; IF tb[node].son[6] # Tree.Null THEN { current.reachable ¬ controlled; pathNP ¬ saveNP; tb[node].son[6] ¬ UpdateList[tb[node].son[6], Stmt]; IF current.reachable THEN newReachable ¬ TRUE; exitNP ¬ BoundNP[exitNP][pathNP]; } ELSE IF controlled THEN newReachable ¬ TRUE; ReverseScanList[tb[node].son[3], CloseItem]; current.reachable ¬ newReachable; pathNP ¬ exitNP; IF block THEN PopCtx[]; currentScope ¬ saveScope; }; <> LabelList: PROC [t: Tree.Link] = { LabelItem: PROC [item: Tree.Link] = { node: Tree.Index = GetNode[item]; current.reachable ¬ tb[node].attr1; pathNP ¬ saveNP; tb[node].son[2] ¬ UpdateList[tb[node].son[2], Stmt]; IF current.reachable THEN newReachable ¬ TRUE; newNP ¬ BoundNP[newNP][pathNP]; }; newReachable: BOOL ¬ current.reachable; saveNP: NPUse ¬ pathNP; newNP: NPUse ¬ none; ScanList[t, LabelItem]; current.reachable ¬ newReachable; pathNP ¬ newNP; }; InsertLabels: PROC [t: Tree.Link] = { labelMark: Tree.Link = current.labelList; InsertLabel: PROC [labeled: Tree.Link] = { node: Tree.Index = GetNode[labeled]; saveIndex: SourceMap.Loc = MimData.textIndex; MimData.textIndex ¬ ToLoc[tb[node].info]; ScanList[tb[node].son[1], StackLabel]; MimData.textIndex ¬ saveIndex; }; StackLabel: PROC [id: Tree.Link] = { node: Tree.Index; FOR t: Tree.Link ¬ current.labelList, tb[node].son[2] UNTIL t = labelMark DO node ¬ GetNode[t]; IF tb[node].son[1] = id AND id # Tree.nullId THEN MimosaLog.ErrorTree[duplicateLabel, id]; ENDLOOP; PushTree[id]; PushTree[current.labelList]; PushNode[item, 2]; SetAttr[1, FALSE]; current.labelList ¬ PopTree[]; }; ScanList[t, InsertLabel]; }; ValidateLabel: PROC [id: Tree.Link] = INLINE { node: Tree.Index; FOR t: Tree.Link ¬ current.labelList, tb[node].son[2] UNTIL t = Tree.Null DO node ¬ GetNode[t]; IF tb[node].son[1] = id THEN {tb[node].attr1 ¬ TRUE; RETURN}; ENDLOOP; MimosaLog.ErrorTree[unknownLabel, id]; }; DeleteLabels: PROC [t: Tree.Link] = { anyReachable: BOOL; DeleteLabel: PROC [labeled: Tree.Link] = { node: Tree.Index = GetNode[labeled]; saveIndex: SourceMap.Loc = MimData.textIndex; MimData.textIndex ¬ ToLoc[tb[node].info]; anyReachable ¬ FALSE; ReverseScanList[tb[node].son[1], UnstackLabel]; tb[node].attr1 ¬ anyReachable; MimData.textIndex ¬ saveIndex; }; UnstackLabel: PROC [id: Tree.Link] = { node: Tree.Index ¬ GetNode[current.labelList]; IF tb[node].attr1 THEN anyReachable ¬ TRUE ELSE MimosaLog.WarningTree[unusedId, tb[node].son[1]]; current.labelList ¬ tb[node].son[2]; tb[node].son[2] ¬ Tree.Null; FreeNode[node]; }; ReverseScanList[t, DeleteLabel]; }; <> BumpArgRefs: PUBLIC PROC [record: RecordSEIndex, write: BOOL] = { IF record # RecordSENull THEN FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, seb[record].fieldCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO IF write THEN BumpCount[sei] ELSE RecordMention[sei]; ENDLOOP; }; CheckLocals: PUBLIC PROC [t: Tree.Link] RETURNS [localsOnly: BOOL ¬ TRUE] = { level: ContextLevel = bb[MimData.bodyIndex].level; CheckElement: Tree.Scan = { WITH t SELECT GetTag[t] FROM literal => NULL; symbol => { sei: ISEIndex = index; IF ~seb[sei].constant AND SymbolOps.CtxLevel[SymbolOps.own, seb[sei].idCtx] # level THEN localsOnly ¬ FALSE }; ENDCASE => localsOnly ¬ FALSE; }; ScanList[t, CheckElement]; }; Return: PROC [node: Tree.Index] = { rSei: RecordSEIndex = current.returnRecord; son1: Tree.Link ¬ tb[node].son[1]; IF current.catchDepth # 0 OR (MimData.bodyIndex = RootBti AND rSei = RecordSENull) THEN MimosaLog.Error[misplacedReturn]; IF rSei # RecordSENull AND son1 = Tree.Null THEN { BumpArgRefs[rSei, FALSE]; FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, seb[rSei].fieldCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO IF seb[sei].hash = HTNull AND ~seb[sei].extended THEN { MimosaLog.Error[illDefinedReturn]; EXIT}; ENDLOOP; tb[node].attr2 ¬ TRUE; } ELSE { son1 ¬ tb[node].son[1] ¬ IF tb[node].attr3 AND rSei # RecordSENull THEN Rhs[son1, rSei] ELSE MatchFields[rSei, son1]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; IF current.entry THEN tb[node].attr2 ¬ CheckLocals[son1]; }; IF (tb[node].attr1 ¬ current.entry) THEN { [] ¬ UpdateTreeAttr[tb[current.bodyNode].son[4]]; pathNP ¬ SequenceNP[pathNP][phraseNP]; }; current.reachable ¬ FALSE; }; ImpliedReturn: Tree.Map = { v ¬ t; IF current.returnRecord # RecordSENull OR current.entry THEN { PushTree[Tree.Null]; PushNode[return, 1]; SetInfo[FromLoc[MimData.textIndex]]; SetAttr[3, FALSE]; PushTree[Stmt[PopTree[]]]; PushTree[t]; v ¬ MakeList[-2]; }; }; <> OpenItem: Tree.Scan = { node: Tree.Index = GetNode[t]; saveIndex: SourceMap.Loc = MimData.textIndex; MimData.textIndex ¬ ToLoc[tb[node].info]; tb[node].son[2] ¬ OpenBase[tb[node].son[2], GetHash[tb[node].son[1]] ! InsertCatchLabel => {MimosaLog.Error[catchLabel]; RESUME}]; ClearRefStack[]; MimData.textIndex ¬ saveIndex; }; CloseItem: Tree.Scan = { node: Tree.Index = GetNode[t]; CloseBase[tb[node].son[2], GetHash[tb[node].son[1]]]; }; }.