Selection.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite, May 5, 1986 3:56:47 pm PDT
Paul Rovner, September 8, 1983 8:30 am
Russ Atkinson (RRA) March 6, 1985 11:25:00 pm PST
Sweet May 5, 1986 11:57:21 am PDT
DIRECTORY
Alloc USING [Notifier],
Code USING [caseCVState, codeptr, mwCaseCV, xtracting],
CodeDefs USING [Base, BoVarIndex, CaseCVState, CCIndex, CCItem, codeType, JumpCCNull, LabelCCIndex, LabelCCNull, Lexeme, NullLex, OpWordCount, OtherCCIndex, VarComponent, VarIndex, VarNull],
ComData USING [typeBOOL],
FOpCodes USING [qGCRT, qLP, qPOP, qPUSH],
P5 USING [CallCatch, EnterBlock, ExitBlock, Exp, FlowTree, GenAnonLex, LogHeapFree, PurgePendTempList, PushLex, PushRhs, ReleaseTempLex, SAssign, StatementTree, SysCallN],
P5L USING [ComponentForLex, CopyLex, CopyToTemp, EasyToLoad, FieldOfVarOnly, LoadVar, MakeBo, NormalizeExp, NormalLex, OVarItem, ReleaseLex, TOSLex, VarForLex, Words],
P5S USING [Assign],
P5U USING [CCellAlloc, EnumerateCaseArms, FreeChunk, InsertLabel, LabelAlloc, MakeTreeLiteral, MarkedType, NilTree, OperandType, Out0, OutJump, PushLitVal, ReferentType, TreeLiteral, TreeLiteralValue, TypeForTree, VariantTag, WordsForOperand],
RTSD USING [sCheckForNarrowRefFault, sGetCanonicalProcType, sGetCanonicalSignalType, sRaiseNarrowFault],
Stack USING [Decr, DeleteToMark, Dump, Incr, Mark, Off, On, ResetToMark],
SymbolOps USING [RCType, TypeLink, UnderType, VariantField, WordsForType, XferMode],
Symbols USING [Base, BTIndex, CSEIndex, ISEIndex, ISENull, seType, Type],
SymLiteralOps USING [TypeRef],
Tree USING [Base, Index, Link, Map, NodeName, Null, Scan, treeType],
TreeOps USING [FreeTree, GetNode, GetSe, ListLength, MarkShared, PopTree, PushNode, PushSe, PushTree, ScanList, SetAttr, SetInfo, UpdateList];
Selection: PROGRAM
IMPORTS MPtr: ComData, CPtr: Code, P5U, P5L, P5, P5S, Stack, SymbolOps, SymLiteralOps, TreeOps
EXPORTS CodeDefs, P5 = BEGIN OPEN CodeDefs;
imported definitions
Type: TYPE = Symbols.Type;
ISEIndex: TYPE = Symbols.ISEIndex;
ISENull: ISEIndex = Symbols.ISENull;
CSEIndex: TYPE = Symbols.CSEIndex;
BTIndex: TYPE = Symbols.BTIndex;
tb: Tree.Base;  -- tree base (local copy)
seb: Symbols.Base;  -- semantic entry base (local copy)
cb: CodeDefs.Base;  -- code base (local copy)
SelectionNotify: PUBLIC Alloc.Notifier =
BEGIN -- called by allocator whenever table area is repacked
seb ← base[Symbols.seType];
tb ← base[Tree.treeType];
cb ← base[codeType];
END;
CaseDriver: PROC [
node: Tree.Index,
isExp: BOOL,
item: PROC [
node: Tree.Index, isExp: BOOL, tempSei: ISEIndex, failLabel: LabelCCIndex]
RETURNS [VarIndex, ISEIndex],
endCaseLabel: LabelCCIndex ← LabelCCNull]
RETURNS [lex: Lexeme] =
BEGIN
caseEndLabel: LabelCCIndex = P5U.LabelAlloc[];
caseLPEndLabel: LabelCCIndex = P5U.LabelAlloc[];
nWords: CARDINAL =
IF isExp THEN OpWordCount[SymbolOps.WordsForType[tb[node].info]] ELSE 0;
longExpValue: BOOL;
valTsei: ISEIndex ← ISENull;
allConst: BOOL;
CheckConst: Tree.Scan = {allConst ← allConst AND P5U.TreeLiteral[t]};
CaseItem: Tree.Map =
BEGIN
failLabel: LabelCCIndex = P5U.LabelAlloc[];
long: BOOLFALSE;
r: VarIndex;
[r, valTsei] ← item[TreeOps.GetNode[t], isExp, valTsei, failLabel];
IF isExp THEN
BEGIN
[long: long, tsei: valTsei] ← P5L.NormalizeExp[r, valTsei, allConst];
Stack.ResetToMark[];
END;
P5U.OutJump[Jump, IF long THEN caseLPEndLabel ELSE caseEndLabel];
P5U.InsertLabel[failLabel];
RETURN [TreeOps.FreeTree[t]]
END;
IF isExp THEN {allConst ← TRUE; P5U.EnumerateCaseArms[node, CheckConst]}
ELSE P5.PurgePendTempList[];
BEGIN
ENABLE P5.LogHeapFree => {RESUME [FALSE, NullLex]};
tb[node].son[2] ← TreeOps.FreeTree[TreeOps.UpdateList[tb[node].son[2], CaseItem]];
IF CPtr.caseCVState = singleLoaded THEN P5U.Out0[FOpCodes.qPOP];
IF endCaseLabel # LabelCCNull THEN P5U.InsertLabel[endCaseLabel];
IF isExp THEN
BEGIN
r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[3]]];
long: BOOL = P5L.NormalizeExp[r, valTsei, allConst].long;
P5U.OutJump[Jump, IF long THEN caseLPEndLabel ELSE caseEndLabel];
Stack.DeleteToMark[];
END
ELSE tb[node].son[3] ← P5.StatementTree[tb[node].son[3]];
END;
P5U.InsertLabel[caseEndLabel];
longExpValue ← cb[caseLPEndLabel].jumplist # JumpCCNull;
IF longExpValue THEN
{Stack.Off[]; P5U.Out0[FOpCodes.qLP]; Stack.On[]}; -- unreached if all arms long
P5U.InsertLabel[caseLPEndLabel];
IF valTsei # ISENull THEN P5.ReleaseTempLex[[se[valTsei]]];
IF isExp THEN
BEGIN
Stack.Incr[SELECT TRUE FROM
nWords <= 2 => nWords,
longExpValue => 2,
ENDCASE => 1];
lex ← P5L.NormalLex[nWords, longExpValue, allConst];
END
ELSE lex ← NullLex;
RETURN
END;
CaseStmtExp: PUBLIC PROC [rootNode: Tree.Index, isExp: BOOL] RETURNS [lex: Lexeme] =
BEGIN -- generate code for CASE statment and expression
cvSize: CARDINAL = P5U.WordsForOperand[tb[rootNode].son[1]];
saveMwCaseCV: Lexeme = CPtr.mwCaseCV;
saveExtracting: BOOL = CPtr.xtracting;
saveCaseCVState: CaseCVState = CPtr.caseCVState;
cvTlex: Lexeme.se ← NullLex;
cvr: VarIndex;
CPtr.xtracting ← FALSE;
IF isExp THEN Stack.Mark[];
cvr ← P5L.VarForLex[P5.Exp[tb[rootNode].son[1]
! P5.LogHeapFree => {RESUME [FALSE, NullLex]}]];
IF cvSize = 1 THEN {P5L.LoadVar[cvr]; CPtr.caseCVState ← singleLoaded}
ELSE
BEGIN
cvTlex ← P5.GenAnonLex[cvSize];
CPtr.mwCaseCV ← [bdo[P5L.OVarItem[P5L.CopyToTemp[cvr, cvTlex.lexsei].var]]];
CPtr.caseCVState ← multi;
END;
lex ← CaseDriver[rootNode, isExp, CaseItem];
IF cvTlex # NullLex THEN {P5.ReleaseTempLex[cvTlex]; P5L.ReleaseLex[CPtr.mwCaseCV]};
CPtr.mwCaseCV ← saveMwCaseCV;
CPtr.caseCVState ← saveCaseCVState;
CPtr.xtracting ← saveExtracting;
tb[rootNode].son[1] ← TreeOps.FreeTree[tb[rootNode].son[1]];
tb[rootNode].son[2] ← TreeOps.FreeTree[tb[rootNode].son[2]];
tb[rootNode].son[3] ← TreeOps.FreeTree[tb[rootNode].son[3]];
IF tb[rootNode].nSons > 3 THEN TreeOps.MarkShared[tb[rootNode].son[4], FALSE];
RETURN
END;
CaseItem: PROC [
node: Tree.Index, isExp: BOOL, tempSei: ISEIndex, failLabel: LabelCCIndex]
RETURNS [r: VarIndex, tSei: ISEIndex] =
BEGIN -- generate code for a CASE item
IF tb[node].name = caseswitch THEN [r, tSei] ← Branch[node, isExp, tempSei, failLabel]
ELSE
BEGIN
tSei ← tempSei;
CaseTest[tb[node].son[1], failLabel];
IF isExp THEN r ← P5L.VarForLex[P5.Exp[tb[node].son[2]]]
ELSE {
P5.PurgePendTempList[];
tb[node].son[2] ← P5.StatementTree[tb[node].son[2]]; r ← VarNull};
END;
RETURN
END;
CaseTest: PUBLIC PROC [t: Tree.Link, failLabel: LabelCCIndex] =
BEGIN
n: CARDINAL = TreeOps.ListLength[t];
IF n = 1 THEN P5.FlowTree[t, FALSE, failLabel]
ELSE
BEGIN
lastSon: CARDINAL = n-1;
thisSon: CARDINAL ← 0;
itemLabel: LabelCCIndex = P5U.LabelAlloc[];
Test: PROC [t: Tree.Link] =
BEGIN
IF thisSon # lastSon THEN {P5.FlowTree[t, TRUE, itemLabel]; thisSon ← thisSon+1}
ELSE {P5.FlowTree[t, FALSE, failLabel]; P5U.InsertLabel[itemLabel]};
END;
TreeOps.ScanList[t, Test];
END;
END;
BranchTable: TYPE = RECORD [SEQUENCE length: CARDINAL OF LabelCCIndex];
NewBranches: PROC [
t: Tree.Link,
itemLabel, failLabel: LabelCCIndex,
bt: REF BranchTable]
RETURNS [new: BOOL] =
BEGIN -- sees if any new branches need to be added to branch table
AddEntry: PROC [t: Tree.Link] =
BEGIN
i: CARDINAL = P5U.TreeLiteralValue[t];
IF bt[i] = failLabel THEN {bt[i] ← itemLabel; new ← TRUE};
END;
new ← FALSE; TreeOps.ScanList[t, AddEntry];
RETURN
END;
Branch: PROC [
node: Tree.Index, isExp: BOOL, tempSei: ISEIndex, failLabel: LabelCCIndex]
RETURNS [r: VarIndex, tSei: ISEIndex] =
BEGIN -- generate code for case switch if range is densely packed
nWords, range, i: CARDINAL;
btcp, saveCodePtr: CCIndex;
valLabel, valLPLabel: LabelCCIndex;
bt: REF BranchTable;
first: BOOLTRUE;
allConst: BOOL;
longExp: BOOL;
LookForConst: Tree.Scan =
BEGIN -- t is a casetest node
WITH t SELECT FROM
subtree => allConst ← allConst AND P5U.TreeLiteral[tb[index].son[2]];
ENDCASE => ERROR;
END;
CaseItem: Tree.Map =
BEGIN
itemLabel: LabelCCIndex;
WITH t SELECT FROM
subtree =>
BEGIN -- is an item
bNode: Tree.Index = index;
long: BOOLFALSE;
itemLabel ← P5U.LabelAlloc[];
IF NewBranches[tb[bNode].son[1], itemLabel, failLabel, bt] THEN
BEGIN
P5U.InsertLabel[itemLabel];
IF isExp THEN
BEGIN
tr: VarIndex;
IF first THEN first ← FALSE ELSE Stack.ResetToMark[];
tr ← P5L.VarForLex[P5.Exp[tb[bNode].son[2]]];
[nwords: nWords, long: long, tsei: tSei] ← P5L.NormalizeExp[tr, tSei, allConst];
END
ELSE tb[bNode].son[2] ← P5.StatementTree[tb[bNode].son[2]];
P5U.OutJump[Jump, IF long THEN valLPLabel ELSE valLabel];
END
ELSE P5U.FreeChunk[itemLabel, CCItem.label.SIZE];
END;
ENDCASE;
RETURN [TreeOps.FreeTree[t]]
END;
tSei ← tempSei;
IF isExp THEN {allConst ← TRUE; TreeOps.ScanList[tb[node].son[3], LookForConst]};
range ← P5U.TreeLiteralValue[tb[node].son[2]];
valLabel ← P5U.LabelAlloc[];
valLPLabel ← P5U.LabelAlloc[];
P5.PushRhs[tb[node].son[1]];
P5U.PushLitVal[range];
Stack.Decr[2];
P5U.CCellAlloc[other];
cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ←
table[btab: , tablecodebytes: 3, taboffset: ];
btcp ← CPtr.codeptr;
P5U.OutJump[JumpCA, failLabel];
bt ← NEW[BranchTable[range]];
FOR i IN [0..range) DO bt[i] ← failLabel ENDLOOP;
tb[node].son[3] ← TreeOps.FreeTree[TreeOps.UpdateList[tb[node].son[3], CaseItem]];
saveCodePtr ← CPtr.codeptr;
CPtr.codeptr ← btcp;
FOR i IN [0..range) DO P5U.OutJump[JumpC, bt[i]] ENDLOOP;
CPtr.codeptr ← saveCodePtr;
P5U.InsertLabel[valLabel];
longExp ← cb[valLPLabel].jumplist # JumpCCNull;
IF longExp THEN P5U.Out0[FOpCodes.qLP];
P5U.InsertLabel[valLPLabel];
bt ← NIL;
IF isExp THEN RETURN [P5L.VarForLex[P5L.NormalLex[nWords, longExp, allConst]], tSei]
ELSE RETURN [VarNull, tSei];
END;
BindStmtExp: PUBLIC PROC [rootNode: Tree.Index, isExp: BOOL] RETURNS [lex: Lexeme] =
BEGIN -- discrimination with copying
saveMwCaseCV: Lexeme = CPtr.mwCaseCV;
saveExtracting: BOOL = CPtr.xtracting;
saveCaseCVState: CaseCVState = CPtr.caseCVState;
typeTemp: BOOLFALSE;
typeLex: Lexeme.se ← NullLex;
cvTemp: Lexeme.se ← NullLex;
pushableTag: BOOLFALSE;
nItems: CARDINAL ← 0;
sourceType: CSEIndex = P5U.OperandType[tb[rootNode].son[1]];
BindItem: PROC [
node: Tree.Index, isExp: BOOL, tempSei: ISEIndex, failLabel: LabelCCIndex]
RETURNS [r: VarIndex, tSei: ISEIndex] =
BEGIN
bti: BTIndex = tb[node].info;
subNode: Tree.Index = TreeOps.GetNode[tb[node].son[1]];
type: Type = seb[TreeOps.GetSe[tb[subNode].son[1]]].idType;
indirect: BOOL = tb[node].attr1;
subType: Type;
nItems ← nItems + 1;
tSei ← tempSei;
P5.EnterBlock[bti];
IF tb[rootNode].attr2 THEN
BEGIN
subType ← P5U.MarkedType[type];
IF tb[node].attr3 -- will destroy type code
AND typeLex = NullLex AND nItems < TreeOps.ListLength[tb[rootNode].son[2]] THEN
BEGIN
typeLex ← P5.GenAnonLex[1];
IF CPtr.caseCVState # singleLoaded THEN P5U.Out0[FOpCodes.qPUSH];
P5.SAssign[typeLex.lexsei];
CPtr.caseCVState ← single;
END;
IF tb[node].attr2 THEN
BEGIN
t: Tree.Link;
IF typeTemp THEN {PushCopy[typeLex]; CPtr.caseCVState ← singleLoaded};
TreeOps.PushTree[Tree.Null];
TreeOps.PushTree[SymLiteralOps.TypeRef[subType]];
TreeOps.PushNode[relE, 2]; TreeOps.SetInfo[MPtr.typeBOOL]; t ← TreeOps.PopTree[];
P5.FlowTree[t, FALSE, failLabel]; t ← TreeOps.FreeTree[t];
END
ELSE IF CPtr.caseCVState = singleLoaded THEN
BEGIN P5U.Out0[FOpCodes.qPOP]; CPtr.caseCVState ← single END;
pushableTag ← FALSE;
IF tb[node].attr3 THEN typeTemp ← TRUE;
END
ELSE subType ← IF indirect THEN P5U.ReferentType[sourceType] ELSE sourceType;
BEGIN
saveCVState: CaseCVState = CPtr.caseCVState;
CPtr.caseCVState ← multi; -- the value being discriminated
IF tb[node].attr3 THEN
pushableTag ← TestTag[
type: subType,
target: IF indirect THEN P5U.ReferentType[type] ELSE type,
failLabel: failLabel,
indirect: indirect,
long: indirect AND SymbolOps.WordsForType[sourceType] # 1,
onStack: pushableTag];
P5S.Assign[subNode];
CPtr.caseCVState ← saveCVState;
END;
IF isExp THEN r ← P5L.VarForLex[P5.Exp[tb[node].son[2]]]
ELSE {tb[node].son[2] ← P5.StatementTree[tb[node].son[2]]; r ← VarNull};
P5.ExitBlock[bti];
RETURN
END;
endCaseLabel: LabelCCIndex ← LabelCCNull;
CPtr.xtracting ← FALSE;
Stack.Dump[];
IF isExp THEN Stack.Mark[];
[CPtr.mwCaseCV, cvTemp] ← SelectArg[tb[rootNode].son[1], tb[rootNode].attr1];
SELECT TRUE FROM
tb[rootNode].attr2 =>
BEGIN
IF tb[rootNode].attr1 THEN
BEGIN
PushCopy[CPtr.mwCaseCV]; P5U.Out0[FOpCodes.qGCRT];
END
ELSE
BEGIN
Stack.Dump[]; Stack.Mark[];
PushCopy[CPtr.mwCaseCV];
P5.SysCallN[GetTypeEntry[sourceType], 1];
END;
CPtr.caseCVState ← singleLoaded;
END;
tb[rootNode].attr1 =>
BEGIN
t: Tree.Link ← NilPredicate[sourceType];
endCaseLabel ← P5U.LabelAlloc[];
CPtr.caseCVState ← multi;
P5.FlowTree[t, TRUE, endCaseLabel]; t ← TreeOps.FreeTree[t];
END;
ENDCASE;
lex ← CaseDriver[rootNode, isExp, BindItem, endCaseLabel];
IF typeLex # NullLex THEN P5.ReleaseTempLex[typeLex];
P5L.ReleaseLex[CPtr.mwCaseCV];
CPtr.mwCaseCV ← saveMwCaseCV; CPtr.caseCVState ← saveCaseCVState;
CPtr.xtracting ← saveExtracting;
IF cvTemp # NullLex THEN P5.ReleaseTempLex[cvTemp];
RETURN
END;
SelectArg: PROC [t: Tree.Link, indirect: BOOL] RETURNS [lex: Lexeme, anon: Lexeme.se] =
BEGIN -- much stolen from EasilyLoadable and ReusableCopies, but to anon temp.
l: Lexeme;
r: VarIndex;
StableCopy: PROC [var: VarComponent] RETURNS [cvar: VarComponent, anon: Lexeme.se] = {
size: CARDINAL ← P5L.Words[var.wSize, var.bSize];
IF P5L.EasyToLoad[var, load] THEN RETURN [var, NullLex];
anon ← P5.GenAnonLex[size];
cvar ← P5L.CopyToTemp[P5L.OVarItem[var], anon.lexsei].var;
};
l ← P5.Exp[t ! P5.LogHeapFree => {RESUME [FALSE, NullLex]}];
IF indirect THEN {
var: VarComponent;
[var, anon] ← StableCopy[P5L.ComponentForLex[l]];
RETURN[[bdo[P5L.OVarItem[var]]], anon]}
ELSE {
r ← P5L.VarForLex[l];
WITH cc: cb[r] SELECT FROM
o => [cc.var, anon] ← StableCopy[cc.var];
bo => [cc.base, anon] ← StableCopy[cc.base];
ENDCASE => {
bor: BoVarIndex ← P5L.MakeBo[r];
[cb[bor].base, anon] ← StableCopy[cb[bor].base];
r ← bor};
RETURN [[bdo[r]], anon];
};
END;
PushCopy: PROC [l: Lexeme] = {P5.PushLex[P5L.CopyLex[l]]};
TestTag: PROC [
type, target: Type, failLabel: LabelCCIndex, indirect, long, onStack: BOOL]
RETURNS [pushable: BOOL] =
BEGIN OPEN SymbolOps;
link: Type = TypeLink[target];
subLink: CSEIndex = SymbolOps.UnderType[link];
uType: CSEIndex = SymbolOps.UnderType[seb[SymbolOps.VariantField[subLink]].idType];
IF SymbolOps.UnderType[type] # subLink THEN  -- discriminate to the link type
BEGIN
[] ← TestTag[type, link, failLabel, indirect, long, onStack];
onStack ← pushable ← FALSE;
END
ELSE pushable ← TRUE;  -- should force non-commutativity
WITH u: seb[uType] SELECT FROM
union =>
BEGIN OPEN TreeOps;
saveCVState: CaseCVState = CPtr.caseCVState;
tagSei: ISEIndex = u.tagSei;
t: Tree.Link;
PushTree[Tree.Null];
IF onStack THEN CPtr.caseCVState ← single
ELSE-- CPtr.caseCVState = multi
BEGIN
IF indirect THEN {PushNode[uparrow, 1]; SetAttr[1, FALSE]; SetAttr[2, long]}
ELSE PushNode[cast, 1];
SetInfo[subLink];
PushSe[tagSei]; PushNode[dollar, 2];
SetInfo[SymbolOps.UnderType[seb[tagSei].idType]]; SetAttr[2, long];
END;
PushTree[P5U.MakeTreeLiteral[P5U.VariantTag[target, u.caseCtx]]];
PushNode[relE, 2]; SetInfo[MPtr.typeBOOL];
t ← PopTree[]; P5.FlowTree[t, FALSE, failLabel]; t ← FreeTree[t];
CPtr.caseCVState ← saveCVState;
END;
ENDCASE => ERROR;
RETURN
END;
TagPredicate: PROC [type, target: Type, indirect, long: BOOL] RETURNS [Tree.Link] =
BEGIN OPEN SymbolOps, TreeOps;
link: Type = TypeLink[target];
subLink: CSEIndex = SymbolOps.UnderType[link];
uType: CSEIndex = SymbolOps.UnderType[seb[SymbolOps.VariantField[subLink]].idType];
WITH u: seb[uType] SELECT FROM
union =>
BEGIN
tagSei: ISEIndex = u.tagSei;
PushTree[Tree.Null];
IF indirect THEN {PushNode[uparrow, 1]; SetAttr[1, FALSE]; SetAttr[2, long]}
ELSE PushNode[cast, 1];
SetInfo[subLink];
PushSe[tagSei]; PushNode[dollar, 2];
SetInfo[SymbolOps.UnderType[seb[tagSei].idType]]; SetAttr[2, long];
PushTree[P5U.MakeTreeLiteral[P5U.VariantTag[target, u.caseCtx]]];
PushNode[relE, 2]; SetInfo[MPtr.typeBOOL];
END;
ENDCASE => ERROR;
IF SymbolOps.UnderType[type] # subLink THEN  -- discriminate to the link type
BEGIN
PushTree[TagPredicate[type, link, indirect, long]]; PushNode[and, -2];
END;
RETURN [PopTree[]]
END;
TypePredicate: PROC [
source: CSEIndex, dest: Type, node: Tree.Index] RETURNS [t: Tree.Link←Tree.Null] =
BEGIN OPEN TreeOps; -- attrs, son[1] as in narrow, istype
indirect: BOOL = tb[node].attr1;
long: BOOL = indirect AND SymbolOps.WordsForType[source] = 2;
type: Type;
IF tb[node].attr2 THEN
BEGIN
type ← P5U.MarkedType[dest];
PushTree[Tree.Null];
IF ~indirect THEN {PushNode[cast, 1]; SetInfo[source]};
PushNode[gcrt, 1]; SetAttr[2, indirect];
PushTree[SymLiteralOps.TypeRef[type]];
PushNode[relE, 2]; SetInfo[MPtr.typeBOOL];
t ← PopTree[];
END
ELSE type ← IF indirect THEN P5U.ReferentType[source] ELSE source;
IF tb[node].attr3 THEN
BEGIN
add NIL test here if not attr2?
PushTree[
TagPredicate[type, IF indirect THEN P5U.ReferentType[dest] ELSE dest, indirect, long]];
IF t # Tree.Null THEN {PushTree[t]; PushNode[and, -2]};
t ← PopTree[];
END;
RETURN
END;
NilPredicate: PROC [type: CSEIndex] RETURNS [Tree.Link] =
BEGIN OPEN TreeOps;
PushTree[Tree.Null];
PushTree[P5U.NilTree[type]];
PushNode[relE, 2]; SetInfo[MPtr.typeBOOL];
RETURN [PopTree[]]
END;
OrTest: PROC [t1, t2: Tree.Link] RETURNS [Tree.Link] =
BEGIN OPEN TreeOps;
PushTree[t1]; PushTree[t2]; PushNode[or, 2]; SetInfo[MPtr.typeBOOL];
RETURN [PopTree[]]
END;
NarrowExp: PUBLIC PROC [node: Tree.Index] RETURNS [l: Lexeme] =
BEGIN
saveMwCaseCV: Lexeme = CPtr.mwCaseCV;
saveExtracting: BOOL = CPtr.xtracting;
saveCaseCVState: CaseCVState = CPtr.caseCVState;
eLabel: LabelCCIndex = P5U.LabelAlloc[];
cvTemp: Lexeme.se ← NullLex;
indirect: BOOL = tb[node].attr1;
sourceType: CSEIndex = P5U.OperandType[tb[node].son[1]];
targetType: Type =
IF tb[node].son[2] # Tree.Null THEN P5U.TypeForTree[tb[node].son[2]] ELSE tb[node].info;
nWords: CARDINAL = SymbolOps.WordsForType[sourceType];
counted: BOOL = indirect AND (SymbolOps.RCType[sourceType] = simple);
t: Tree.Link;
CPtr.xtracting ← FALSE;
Stack.Dump[]; Stack.Mark[];
t ← TypePredicate[sourceType, targetType, node];
IF indirect # tb[node].attr2 THEN t ← OrTest[NilPredicate[sourceType], t];
[CPtr.mwCaseCV, cvTemp] ← SelectArg[tb[node].son[1], indirect]; CPtr.caseCVState ← multi;
IF indirect THEN PushCopy[CPtr.mwCaseCV];
P5.FlowTree[t, TRUE, eLabel]; t ← TreeOps.FreeTree[t];
IF indirect THEN
BEGIN
IF counted THEN
BEGIN
t ← SymLiteralOps.TypeRef[P5U.ReferentType[targetType], FALSE];
P5.PushRhs[t]; t ← TreeOps.FreeTree[t];
P5.SysCallN[RTSD.sCheckForNarrowRefFault, nWords];
END
ELSE P5.SysCallN[RTSD.sRaiseNarrowFault, nWords];
P5L.ReleaseLex[CPtr.mwCaseCV];
l ← P5L.TOSLex[nWords];
END
ELSE
BEGIN
len: CARDINAL = SymbolOps.WordsForType[SymbolOps.UnderType[targetType]];
P5.SysCallN[RTSD.sRaiseNarrowFault, 0];
IF len = nWords THEN l ← CPtr.mwCaseCV
ELSE-- simulate a chop
BEGIN
r: VarIndex = P5L.VarForLex[CPtr.mwCaseCV];
P5L.FieldOfVarOnly[r: r, wSize: len];
l ← [bdo[r]];
END;
END;
CPtr.mwCaseCV ← saveMwCaseCV; CPtr.caseCVState ← saveCaseCVState;
CPtr.xtracting ← saveExtracting;
P5.CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null];
P5U.InsertLabel[eLabel];
IF cvTemp # NullLex THEN P5.ReleaseTempLex[cvTemp];
RETURN
END;
TypeRel: PUBLIC PROC [node: Tree.Index, tf: BOOL, label: LabelCCIndex] =
BEGIN
saveMwCaseCV: Lexeme = CPtr.mwCaseCV;
saveExtracting: BOOL = CPtr.xtracting;
saveCaseCVState: CaseCVState = CPtr.caseCVState;
cvTemp: Lexeme.se;
sourceType: CSEIndex = P5U.OperandType[tb[node].son[1]];
t: Tree.Link;
CPtr.xtracting ← FALSE;
Stack.Dump[];
t ← TypePredicate[sourceType, P5U.TypeForTree[tb[node].son[2]], node];
IF tb[node].attr1 OR tb[node].attr2 THEN
t ← OrTest[NilPredicate[sourceType], t];
[CPtr.mwCaseCV, cvTemp] ← SelectArg[tb[node].son[1], tb[node].attr1]; CPtr.caseCVState ← multi;
P5.FlowTree[t, tf, label]; t ← TreeOps.FreeTree[t];
P5L.ReleaseLex[CPtr.mwCaseCV];
CPtr.mwCaseCV ← saveMwCaseCV; CPtr.caseCVState ← saveCaseCVState;
IF cvTemp # NullLex THEN P5.ReleaseTempLex[cvTemp];
CPtr.xtracting ← saveExtracting;
END;
GetCanonicalType: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] =
BEGIN
IF tb[node].attr2 THEN
BEGIN
P5.PushRhs[tb[node].son[1]]; P5U.Out0[FOpCodes.qGCRT];
END
ELSE
BEGIN
Stack.Dump[]; Stack.Mark[];
P5.PushRhs[tb[node].son[1]];
P5.SysCallN[GetTypeEntry[P5U.OperandType[tb[node].son[1]]], 1];
END;
RETURN [P5L.TOSLex[1]]
END;
GetTypeEntry: PROC [type: CSEIndex] RETURNS [CARDINAL] =
BEGIN
RETURN [SELECT SymbolOps.XferMode[type] FROM
proc => RTSD.sGetCanonicalProcType,
signal, error => RTSD.sGetCanonicalSignalType,
ENDCASE => 0]
END;
END.