Pass3S.mesa
Copyright Ó 1985, 1986, 1987, 1990, 1991 by Xerox Corporation. All rights reserved.
Satterthwaite, June 18, 1986 12:29:52 pm PDT
Russ Atkinson (RRA) February 5, 1990 7:21:57 pm PST
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 = {
called by allocator whenever table area is repacked
tb ¬ base[Tree.treeType];
seb ¬ base[seType];
ctxb ¬ base[ctxType];
mdb ¬ base[mdType];
bb ¬ base[bodyType];
};
parameter usage
pathNP: PUBLIC NPUse ¬ none;
bodies and blocks
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[];
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;
};
{
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];
note: pushes onto the R-stack
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];
};
<<RRA: Why is this test here? It does not seem to be doing any good, and leads to error messages in places that do not appear to be wrong!>>
IF seb[sei].hash = HTNull AND copyable THEN
MimosaLog.ErrorSei[defaultForm, sei];
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;
}
};
statements
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
For debugging down to the statement level
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 driver
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;
};
iteration
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 {
account for implicit refs
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;
};
labels
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];
};
control transfers
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];
};
};
basing
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]]];
};
}.