file Pass3M.mesa
last modified by Satterthwaite, May 10, 1983 9:21 am
last modified by Donahue, 9-Dec-81 14:45:35
Last Edited by: Maxwell, July 28, 1983 11:46 am
DIRECTORY
A3: TYPE USING [
Bundling, CanonicalType, DefaultInit, LongPath, NewableType, OperandInternal,
OperandLhs, OperandType, TypeForTree, Unbundle, Voidable],
Alloc: TYPE USING [Notifier, Top],
ComData: TYPE USING [
bodyIndex, idUNWIND, ownSymbols, seAnon, stopping, table, textIndex,
typeCONDITION, typeListANY, typeLOCK],
ConvertUnsafe: TYPE USING [SubString],
Log: TYPE USING [Error, ErrorSei, ErrorTree],
Pass3: TYPE USING [lockNode],
P3: TYPE USING [
Attr, fullAttr, NPUse, Safety, TextForm,
pathNP, phraseNP, BoundNP, MergeNP, SequenceNP, SetNP,
And, Apply, BindTree, BumpArgRefs, CheckLocals, CheckScope,
ClearRefStack, CopyTree, EnterType, EnterComposite, Exp, FirstId, InitialExp,
MakeLongType, MakeRefType, MatchFields, PopCtx, PushCtx,
RAttr, Rhs, RPop, RPush, RType, SafetyAttr, SetSafety, SealRefStack, SearchCtxList,
Stmt, TypeAppl, UnsealRefStack, UpdateTreeAttr, VoidExp],
P3S: TYPE USING [BodyData, continued, currentBody, markCatch, safety],
Symbols: TYPE USING [
Base, HTIndex, SERecord, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, RefSEIndex,
CTXIndex, BodyRecord, BTIndex, CBTIndex,
HTNull, SENull, ISENull, CSENull, RecordSENull, CTXNull, CBTNull,
lG, lZ, RootBti, typeANY, seType, ctxType, mdType, bodyType],
SymbolOps: TYPE USING [
ArgCtx, ArgRecord, EnterString, FindString, FirstCtxSe, MakeNonCtxSe,
NextSe, NormalType, ReferentType, TransferTypes, TypeRoot, UnderType],
Tree: TYPE USING [Base, Index, Link, Map, NodeName, Null, NullIndex, Scan, treeType],
TreeOps: TYPE USING [
FreeNode, FreeTree, GetNode, ListLength, MakeList, MakeNode,
NthSon, PopTree, PushList, PushTree, PushSe, PushNode, OpName,
ReverseUpdateList, ScanList, SetAttr, SetInfo, UpdateList],
Types: TYPE USING [Assignable, Equivalent];
Pass3M: PROGRAM
IMPORTS
A3, Alloc, Log, P3, P3S, SymbolOps, TreeOps, Types,
dataPtr: ComData, passPtr: Pass3
EXPORTS P3 = {
OPEN SymbolOps, Symbols, A3, P3, TreeOps;
InsertCatchLabel: PUBLIC SIGNAL [catchSeen, exit: BOOL] = CODE;
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)
MiscNotify: 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]};
current: POINTER TO P3S.BodyData = @P3S.currentBody;
statements
MiscStmt: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
val ← [subtree[index: node]]; -- the default
SELECT tb[node].name FROM
signal, error, start, join, wait => {
PushTree[SELECT tb[node].name FROM
start => Start[node],
join => Join[node],
wait => Wait[node],
ENDCASE => Signal[node]];
SELECT RType[] FROM
CSENull, typeANY => NULL;
ENDCASE => Log.Error[nonVoidStmt];
SetInfo[dataPtr.textIndex]; val ← PopTree[]; RPop[];
pathNP ← SequenceNP[pathNP][phraseNP];
IF OpName[val] = error THEN current.reachable ← FALSE};
xerror => {
subNode: Tree.Index;
IF current.catchDepth # 0 THEN Log.Error[misplacedReturn];
tb[node].name ← error;
val ← MiscStmt[node]; subNode ← GetNode[val];
IF tb[subNode].attr1 THEN Log.ErrorTree[typeClash, val];
SELECT tb[subNode].name FROM
error, errorx => tb[subNode].name ← xerror;
ENDCASE => NULL;
tb[subNode].attr1 ← current.entry; tb[subNode].attr3 ← FALSE;
IF current.entry THEN tb[subNode].attr2 ← CheckLocals[tb[subNode].son[2]];
IF tb[subNode].nSons > 2 THEN Log.Error[misplacedCatch];
current.reachable ← FALSE};
resume => Resume[node];
reject => {
IF current.catchDepth = 0 THEN Log.Error[misplacedResume];
current.reachable ← FALSE};
continue, retry => {
SIGNAL InsertCatchLabel[catchSeen:FALSE, exit:tb[node].name=continue];
current.reachable ← FALSE};
restart => {val ← Restart[node]; pathNP ← SequenceNP[pathNP][phraseNP]};
stop => {
IF dataPtr.bodyIndex # RootBti OR current.catchDepth # 0
OR current.returnRecord # SENull THEN Log.Error[misplacedStop];
dataPtr.stopping ← TRUE; pathNP ← SetNP[pathNP]};
notify, broadcast => {
OPEN tb[node];
type: CSEIndex;
IF ~current.lockHeld THEN Log.Error[misplacedMonitorRef];
son[1] ← Exp[son[1], typeANY];
IF OperandLhs[son[1]] = none THEN Log.ErrorTree[nonLHS, son[1]];
type ← RType[]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP];
IF type # dataPtr.typeCONDITION THEN Log.ErrorTree[typeClash, son[1]]};
free => {
OPEN tb[node];
type, subType: CSEIndex;
long, counted: BOOL;
[v:son[1], long:long, counted:counted] ← EvalZone[son[1]]; RPop[];
son[2] ← Exp[son[2], typeANY]; type ← RType[]; RPop[];
subType ← NormalType[type];
WITH s: seb[subType] SELECT FROM
ref => {
IF s.readOnly THEN Log.ErrorTree[nonLHS, son[2]];
type ← UnderType[s.refType];
IF long # (seb[type].typeTag = long) THEN GO TO fail;
type ← NormalType[type];
WITH t: seb[type] SELECT FROM
ref => IF t.counted # counted THEN GO TO fail;
ENDCASE => GO TO fail;
IF P3S.safety = checked AND ~counted THEN
Log.ErrorTree[unsafeOperation, [subtree[node]]];
EXITS
fail => Log.ErrorTree[typeClash, son[2]]};
ENDCASE => Log.ErrorTree[typeClash, son[2]];
IF nSons > 3 THEN {
saveNP: NPUse = phraseNP;
[] ← CatchPhrase[son[4]]; phraseNP ← MergeNP[saveNP][phraseNP]};
attr2 ← long; attr3 ← counted;
SELECT TRUE FROM
~counted => attr1 ← FALSE;
(OpName[son[2]] # addr) => {Log.ErrorTree[other, son[2]]; attr1 ← FALSE};
ENDCASE => attr1 ← OperandLhs[NthSon[son[2], 1]] = counted};
dst, lst, lste, lstf => {
OPEN tb[node];
v: Tree.Link;
v ← son[1] ← Exp[son[1], typeANY]; RPop[];
SELECT name FROM
dst => IF OperandLhs[son[1]] = none THEN GO TO fail;
lst => NULL;
lste => current.noXfers ← FALSE;
lstf => current.reachable ← FALSE;
ENDCASE;
IF name = lste OR name = lstf THEN phraseNP ← SetNP[phraseNP];
pathNP ← SequenceNP[pathNP][phraseNP];
check for simple addressability
DO
WITH v SELECT FROM
symbol => IF seb[index].constant THEN GO TO fail ELSE EXIT;
subtree => {
IF tb[index].name # dollar THEN GO TO fail; v ← tb[index].son[1]};
ENDCASE => GO TO fail;
ENDLOOP;
IF P3S.safety = checked THEN Log.ErrorTree[unsafeOperation, [subtree[node]]];
EXITS
fail => Log.ErrorTree[nonLHS, tb[node].son[1]]};
enable => {
OPEN tb[node];
saveEnabled: BOOL = current.unwindEnabled;
IF CatchPhrase[son[1]].unwindCaught THEN current.unwindEnabled ← TRUE;
IF phraseNP # none THEN pathNP ← unsafe;
son[2] ← UpdateList[son[2], Stmt]; attr3 ← FALSE;
current.unwindEnabled ← saveEnabled};
ENDCASE => Log.Error[unimplemented];
RETURN};
dynamic storage allocation
New: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = {
OPEN tb[node];
pType: RefSEIndex;
subType, rootType: SEIndex;
attr: Attr;
saveNP: NPUse;
long, counted: BOOL;
[v:son[1], long:long, counted:counted] ← EvalZone[son[1]];
attr ← RAttr[]; RPop[]; saveNP ← phraseNP;
current.noXfers ← attr.noXfer ← FALSE; attr.const ← FALSE;
son[2] ← TypeAppl[son[2]];
attr ← And[attr, RAttr[]]; saveNP ← MergeNP[saveNP][phraseNP]; RPop[];
subType ← TypeForTree[son[2]]; rootType ← TypeRoot[subType];
IF ~NewableType[subType] THEN Log.ErrorTree[typeLength, son[2]];
IF counted THEN EnterType[rootType, FALSE];
IF son[3] = Tree.Null THEN son[3] ← DefaultInit[subType]
ELSE {
StringInit: PROC [t: Tree.Link] RETURNS [BOOL] = INLINE {
RETURN [SELECT OpName[t] FROM
stringinit => TRUE,
lengthen => (OpName[NthSon[t, 1]] = stringinit),
ENDCASE => FALSE]};
extFlag: BOOL;
[son[3], extFlag] ← InitialExp[son[3], subType];
SELECT TRUE FROM
extFlag => Log.ErrorTree[misusedInline, son[3]];
StringInit[son[3]] => Log.ErrorTree[defaultForm, son[3]];
ENDCASE};
attr ← And[attr, RAttr[]]; phraseNP ← SequenceNP[saveNP][phraseNP]; RPop[];
pType ← MakeRefType[
cType: subType, readOnly: tb[node].attr1, counted: counted,
hint: NormalType[target]];
IF counted AND son[3] # Tree.Null THEN
EnterComposite[UnderType[subType], son[3], TRUE];
IF son[3] = Tree.Null AND ~Voidable[subType] THEN
Log.ErrorTree[missingInit, [subtree[node]]];
IF nSons > 3 THEN {
saveNP: NPUse = phraseNP;
[] ← CatchPhrase[son[4]]; phraseNP ← MergeNP[saveNP][phraseNP]};
attr2 ← long; attr3 ← counted;
RPush[IF long THEN MakeLongType[pType, target] ELSE pType, attr];
RETURN [[subtree[index: node]]]};
EvalZone: PROC [t: Tree.Link] RETURNS [v: Tree.Link, long, counted: BOOL] = {
type, nType: CSEIndex;
nDerefs: CARDINAL;
long ← counted ← TRUE;
IF t = Tree.Null THEN {v ← Tree.Null; RPush[typeANY, fullAttr]}
ELSE {
v ← Exp[t, typeANY]; type ← RType[]; nDerefs ← 0;
DO
nType ← NormalType[type];
WITH s: seb[nType] SELECT FROM
zone => {long ← ~s.mds; counted ← s.counted; GO TO success};
ref => {
IF (nDerefs ← nDerefs + 1) > 63 THEN GO TO failure;
PushTree[v]; PushNode[uparrow, 1]; SetAttr[2, seb[type].typeTag = long];
type ← UnderType[s.refType]; SetInfo[type]; v ← PopTree[]};
record =>
IF Bundling[nType] # 0 THEN type ← Unbundle[LOOPHOLE[nType, RecordSEIndex]]
ELSE GO TO failure;
ENDCASE => GO TO failure;
REPEAT
success => NULL;
failure => Log.ErrorTree[typeClash, v];
ENDLOOP};
RETURN};
list allocation
Cons: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = {
nType: CSEIndex = NodeType[target, [subtree[node]]];
PushTree[tb[node].son[1]]; tb[node].son[1] ← Tree.Null;
PushNode[implicitTC, 0]; SetInfo[nType];
PushTree[tb[node].son[2]]; tb[node].son[2] ← Tree.Null;
PushTree[Tree.Null]; PushNode[apply, -2]; SetAttr[1, FALSE];
IF tb[node].nSons > 2 THEN {
PushTree[tb[node].son[3]]; tb[node].son[3] ← Tree.Null; PushNode[new, 4]}
ELSE PushNode[new, 3];
FreeNode[node];
RETURN [Exp[PopTree[], target]]};
ListCons: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = {
nType: CSEIndex = NodeType[target, [subtree[node]]];
n: CARDINAL = ListLength[tb[node].son[2]];
k: CARDINAL ← n;
list, zone: Tree.Link;
ListItem: Tree.Map = {
PushTree[IF (k←k-1) = 0 THEN zone ELSE P3.CopyTree[zone]];
PushNode[implicitTC, 0]; SetInfo[nType];
PushTree[t]; PushTree[list]; PushList[2];
PushTree[Tree.Null]; PushNode[apply, -2]; SetAttr[1, FALSE];
list ← MakeNode[new, 3];
RETURN [Tree.Null]};
PushTree[Tree.Null]; list ← MakeNode[nil, 1];
IF n = 0 THEN [v: tb[node].son[1]] ← EvalZone[tb[node].son[1]]
ELSE {
zone ← tb[node].son[1]; tb[node].son[1] ← Tree.Null;
tb[node].son[2] ← ReverseUpdateList[tb[node].son[2], ListItem]};
FreeNode[node];
RETURN [Exp[list, target]]};
NodeType: PROC [target: CSEIndex, t: Tree.Link] RETURNS [nType: CSEIndex] = {
subType: CSEIndex = NormalType[target];
WITH r: seb[subType] SELECT FROM
ref => {
rType: CSEIndex = UnderType[r.refType];
IF ~r.list AND (seb[rType].typeTag = any OR rType = typeANY) THEN
nType ← ReferentType[dataPtr.typeListANY]
ELSE {
IF ~r.list THEN Log.ErrorTree[typeClash, t];
nType ← rType}};
ENDCASE =>
IF subType = typeANY THEN nType ← ReferentType[dataPtr.typeListANY]
ELSE {Log.ErrorTree[typeClash, t]; nType ← typeANY};
RETURN};
control transfers
MiscXfer: PUBLIC PROC [node: Tree.Index, target: CSEIndex] RETURNS [val: Tree.Link] = {
SELECT tb[node].name FROM
new => val ← New[node, target];
signalx, errorx => val ← Signal[node];
create => val ← Create[node, target];
startx => val ← Start[node];
fork => val ← Fork[node, target];
joinx => val ← Join[node];
cons => val ← Cons[node, target];
listcons => val ← ListCons[node, target];
ENDCASE => {Log.Error[unimplemented]; val ← [subtree[node]]};
RETURN};
MakeFrameRecord: PUBLIC PROC [t: Tree.Link] RETURNS [rSei: CSEIndex] = {
bti: CBTIndex = XferBody[t];
IF bti # CBTNull THEN {
argType: SEIndex = TransferTypes[bb[bti].ioType].typeIn;
rSei ← IF bb[bti].type # RecordSENull AND argType = SENull
THEN bb[bti].type
ELSE AllocFrameRecord[bti, argType]}
ELSE {Log.Error[nonTypeCons]; rSei ← typeANY};
RETURN};
AllocFrameRecord: PROC [bti: CBTIndex, link: SEIndex] RETURNS [sei: RecordSEIndex] = {
sei ← LOOPHOLE[MakeNonCtxSe[SERecord.cons.record.linked.SIZE]];
seb[sei] ← SERecord[mark3: TRUE, mark4: FALSE,
body: cons[record[
machineDep: FALSE,
painted: TRUE, argument: FALSE,
hints: [
unifield: FALSE, variant: FALSE,
assignable: FALSE, comparable: FALSE, privateFields: TRUE,
refField: TRUE, default: FALSE, voidable: FALSE],
fieldCtx: bb[bti].localCtx,
length: IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].length ELSE 0,
monitored: bb[bti].monitored,
linkPart: linked[link]]]];
RETURN};
XferBody: PROC [t: Tree.Link] RETURNS [bti: CBTIndex] = {
sei: ISEIndex;
type: CSEIndex;
WITH t SELECT FROM
symbol => {
sei ← index; type ← UnderType[seb[sei].idType];
bti ← WITH seb[type] SELECT FROM
transfer =>
IF ~seb[sei].immutable
THEN CBTNull
ELSE
SELECT mode FROM
program =>
IF seb[sei].mark4
THEN (IF seb[sei].constant THEN seb[sei].idInfo ELSE CBTNull)
ELSE RootBti,
proc =>
IF sei = bb[dataPtr.bodyIndex].id THEN dataPtr.bodyIndex ELSE CBTNull,
ENDCASE => CBTNull,
ENDCASE => CBTNull};
ENDCASE => bti ← CBTNull;
RETURN};
XferForFrame: PUBLIC PROC [ctx: CTXIndex] RETURNS [type: CSEIndex ← CSENull] = {
bti: BTIndex ← BTIndex.FIRST;
btLimit: BTIndex = (dataPtr.table).Top[bodyType];
UNTIL bti = btLimit DO
WITH entry: bb[bti] SELECT FROM
Callable => {
IF entry.localCtx = ctx THEN RETURN [UnderType[entry.ioType]];
bti ← bti + (WITH entry SELECT FROM
Inner => BodyRecord.Callable.Inner.SIZE,
Catch => BodyRecord.Callable.Catch.SIZE,
ENDCASE => BodyRecord.Callable.Outer.SIZE)};
ENDCASE => bti ← bti + BodyRecord.Other.SIZE;
ENDLOOP;
RETURN [CSENull]};
Create: PROC [node: Tree.Index, target: CSEIndex] RETURNS [val: Tree.Link] = {
subNode: Tree.Index;
val ← ForceApplication[tb[node].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
subNode ← GetNode[val];
BEGIN OPEN tb[subNode];
type, mType, rType: CSEIndex;
attr: Attr;
CreateError: PROC = {Log.ErrorTree[typeClash, son[1]]; type ← typeANY};
name ← create; attr1 ← TRUE;
son[1] ← Exp[son[1], typeANY];
mType ← RType[]; attr ← RAttr[]; RPop[]; phraseNP ← SetNP[phraseNP];
WITH seb[mType] SELECT FROM
transfer =>
IF mode = program THEN
SELECT XferBody[son[1]] FROM
CBTNull => type ← mType;
RootBti => {
type ← IF seb[target].typeTag = ref
THEN MakeRefType[MakeFrameRecord[son[1]], target]
ELSE mType;
attr1 ← FALSE};
ENDCASE => CreateError[]
ELSE CreateError[];
ref => {
type ← mType; rType ← UnderType[refType];
WITH seb[rType] SELECT FROM
record =>
SELECT TRUE FROM
(ctxb[fieldCtx].level # lG) => CreateError[];
(seb[target].typeTag = transfer) => {
type ← XferForFrame[fieldCtx];
IF type = CSENull THEN {Log.Error[unimplemented]; type ← typeANY}};
ENDCASE;
ENDCASE => IF refType # typeANY THEN CreateError[]};
ENDCASE => IF mType = typeANY THEN type ← typeANY ELSE CreateError[];
IF son[2] # Tree.Null THEN {
Log.ErrorTree[noApplication, son[1]]; son[2] ← UpdateList[son[2], VoidExp]};
IF nSons > 2 THEN [] ← CatchPhrase[son[3]];
current.noXfers ← attr.noXfer ← FALSE; attr.const ← FALSE;
RPush[type, attr];
END;
RETURN};
Start: PROC [node: Tree.Index] RETURNS [Tree.Link] = {
subNode: Tree.Index;
subNode ← Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE];
SELECT tb[subNode].name FROM
start, startx, apply => NULL;
ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
RETURN [[subtree[subNode]]]};
Restart: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
subNode: Tree.Index;
type: CSEIndex;
val ← ForceApplication[tb[node].son[1]];
subNode ← GetNode[val];
BEGIN OPEN tb[subNode];
name ← tb[node].name; info ← tb[node].info;
son[1] ← Exp[son[1], typeANY]; type ← RType[]; RPop[];
phraseNP ← SetNP[phraseNP];
WITH seb[type] SELECT FROM
ref => NULL;  -- a weak check for now
transfer =>
IF mode # program OR XferBody[son[1]] # CBTNull THEN Log.ErrorTree[typeClash, son[1]];
ENDCASE => IF type # typeANY THEN Log.ErrorTree[typeClash, son[1]];
IF son[2] # Tree.Null THEN {
Log.ErrorTree[noApplication, son[1]]; son[2] ← UpdateList[son[2], VoidExp]};
IF nSons > 2 THEN [] ← CatchPhrase[son[3]];
END;
current.noXfers ← FALSE;
tb[node].son[1] ← Tree.Null; FreeNode[node]; RETURN};
Fork: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = {
subNode: Tree.Index;
type: CSEIndex;
attr: Attr;
t: Tree.Link ← ForceApplication[tb[node].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
subNode ← Apply[GetNode[t], typeANY, TRUE]; attr ← RAttr[]; RPop[];
SELECT tb[subNode].name FROM
call, callx => {
s: Tree.Link ← tb[subNode].son[1];
subType: CSEIndex;
IF OpName[s] = thread THEN {
s ← NthSon[s, 1]; Log.ErrorTree[misusedInline, s]};
IF current.lockHeld AND OperandInternal[s] THEN
Log.ErrorTree[internalCall, s];
subType ← OperandType[s];
WITH procType: seb[subType] SELECT FROM
transfer => {
type ← MakeNonCtxSe[SERecord.cons.transfer.SIZE];
seb[type] ← SERecord[mark3: TRUE, mark4: TRUE,
body: cons[transfer[
mode: process, safe: procType.safe,
typeIn: RecordSENull,
typeOut: procType.typeOut]]];
IF P3S.safety = checked THEN {
CheckArg: Tree.Map = {
argType: CSEIndex = OperandType[t];
subType: CSEIndex = NormalType[argType];
WITH s: seb[subType] SELECT FROM
ref => {IF s.var THEN Log.ErrorTree[unsafeOperation, t]; v ← t};
transfer => v ← CheckScope[t, argType];
ENDCASE => v ← t;
RETURN};
tb[subNode].son[1] ← CheckScope[s, subType];
tb[subNode].son[2] ← UpdateList[tb[subNode].son[2], CheckArg]}};
ENDCASE => ERROR;
tb[subNode].name ← fork};
apply => type ← typeANY;
ENDCASE => {Log.ErrorTree[typeClash, tb[node].son[1]]; type ← typeANY};
tb[subNode].info ← type; RPush[type, attr];
RETURN [[subtree[subNode]]]};
Join: PROC [node: Tree.Index] RETURNS [Tree.Link] = {
subNode: Tree.Index;
subNode ← Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE];
SELECT tb[subNode].name FROM
join, joinx => NULL;
apply => NULL;
ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
RETURN [[subtree[subNode]]]};
Wait: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
subNode: Tree.Index;
saveNP: NPUse;
IF ~current.lockHeld THEN Log.Error[misplacedMonitorRef];
subNode ← Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE];
SELECT tb[subNode].name FROM
wait => NULL;
apply => NULL;
ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
IF OperandLhs[tb[subNode].son[1]] = none THEN Log.ErrorTree[nonLHS, tb[subNode].son[1]];
[] ← FreeTree[tb[subNode].son[2]];
saveNP ← phraseNP;
tb[subNode].son[2] ← tb[subNode].son[1]; tb[subNode].son[1] ← CopyLock[];
phraseNP ← MergeNP[saveNP][phraseNP];
RETURN [[subtree[subNode]]]};
monitors
LockVar: PUBLIC PROC [t: Tree.Link] RETURNS [val: Tree.Link] = {
type, nType: CSEIndex;
desc: ConvertUnsafe.SubString;
sei: ISEIndex;
nDerefs: CARDINAL;
long, b: BOOL;
Dereference: PROC [type: CSEIndex] = {
PushTree[val]; PushNode[uparrow, 1]; SetInfo[type]; SetAttr[2, long];
val ← PopTree[]};
val ← Exp[t, typeANY]; long ← LongPath[val];
type ← RType[]; RPop[]; nDerefs ← 0;
DO
IF type = dataPtr.typeLOCK THEN {IF nDerefs # 0 THEN Dereference[type]; GO TO success};
type ← UnderType[TypeRoot[type]]; nType ← NormalType[type];
WITH seb[nType] SELECT FROM
record => {
IF monitored THEN {
desc ← ["LOCK"L, 0, ("LOCK"L).length];
[b, sei] ← SearchCtxList[EnterString[desc], fieldCtx];
IF ~b THEN {Log.Error[noAccess]; sei ← dataPtr.seAnon};
PushTree[val]; PushSe[sei];
PushNode[IF nDerefs = 0 THEN dollar ELSE dot, 2];
SetInfo[dataPtr.typeLOCK]; SetAttr[2, long]; val ← PopTree[];
GO TO success};
GO TO failure};
ref => {
IF (nDerefs ← nDerefs + 1) > 63 THEN GO TO failure;
long ← seb[type].typeTag = long;
IF nDerefs > 1 THEN Dereference[type];
type ← UnderType[refType]};
ENDCASE => GO TO failure;
REPEAT
success => NULL;
failure => Log.ErrorTree[typeClash, val];
ENDLOOP;
IF OperandLhs[val] = none THEN Log.ErrorTree[nonLHS, val];
RETURN};
FindLockParams: PUBLIC PROC RETURNS [formal, actual: ISEIndex] = {
node: Tree.Index = GetNode[tb[passPtr.lockNode].son[1]];
found: BOOL;
IF node = Tree.NullIndex THEN formal ← actual ← ISENull
ELSE {
formal ← FirstId[node];
IF current.inputRecord = SENull THEN found ← FALSE
ELSE [found, actual] ← SearchCtxList[
seb[formal].hash,
seb[current.inputRecord].fieldCtx];
IF ~found THEN actual ← ISENull};
RETURN};
LambdaApply: PROC [t: Tree.Link, formal, actual: ISEIndex] RETURNS [v: Tree.Link] = {
BindFormal: PROC [sei: ISEIndex] RETURNS [Tree.Link] = {
RETURN [[symbol[index: IF sei = formal THEN actual ELSE sei]]]};
v ← BindTree[t, BindFormal];
[] ← UpdateTreeAttr[v];
RETURN};
CopyLock: PUBLIC PROC RETURNS [val: Tree.Link] = {
formal, actual: ISEIndex;
SELECT TRUE FROM
passPtr.lockNode = Tree.NullIndex => val ← Tree.Null;
tb[current.bodyNode].son[4] # Tree.Null =>
val ← LambdaApply[tb[current.bodyNode].son[4], ISENull, ISENull];
ENDCASE => {
[formal:formal, actual:actual] ← FindLockParams[];
IF formal # SENull THEN {
IF actual = SENull THEN {Log.ErrorSei[missingLock, formal]; actual ← dataPtr.seAnon};
IF ~Types.Assignable[
[dataPtr.ownSymbols, UnderType[seb[formal].idType]],
[dataPtr.ownSymbols, UnderType[seb[actual].idType]]] THEN
Log.ErrorSei[typeClash, actual]};
val ← LambdaApply[tb[passPtr.lockNode].son[2], formal, actual]};
RETURN};
signals
Signal: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
subNode: Tree.Index;
nodeTag: Tree.NodeName = tb[node].name;
subNode ← Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE];
SELECT tb[subNode].name FROM
signal, signalx => tb[subNode].name ← nodeTag;
error, errorx => {
SELECT nodeTag FROM
signal, signalx => Log.ErrorTree[typeClash, tb[subNode].son[1]];
ENDCASE => NULL;
tb[subNode].name ← nodeTag};
apply => NULL;
ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]];
tb[node].son[1] ← Tree.Null; FreeNode[node];
RETURN [[subtree[subNode]]]};
ForceApplication: PROC [t: Tree.Link] RETURNS [Tree.Link] = {
IF OpName[t] = apply THEN RETURN [t];
PushTree[t]; PushTree[Tree.Null];
RETURN [MakeNode[apply, 2]]};
catch phrases
CatchPhrase: PUBLIC PROC [t: Tree.Link] RETURNS [unwindCaught: BOOL] = {
saveReachable: BOOL = current.reachable;
savePathNP: NPUse = pathNP;
saveSafety: Safety = P3S.safety;
enclosingSafe: BOOL = (saveSafety = checked);
entryNP, exitNP: NPUse;
CatchItem: Tree.Scan = {
node: Tree.Index = GetNode[t];
type: CSEIndex ← typeANY;
mixed, safe, error: BOOLFALSE;
saveIndex: CARDINAL = dataPtr.textIndex;
CatchLabel: Tree.Map = {
subType: CSEIndex;
v ← Exp[t, typeANY]; subType ← CanonicalType[RType[]]; RPop[];
entryNP ← SequenceNP[entryNP][phraseNP];
WITH t: seb[subType] SELECT FROM
transfer =>
IF t.mode = signal OR t.mode = error THEN {
IF type = typeANY THEN type ← subType
ELSE IF ~Types.Equivalent[
[dataPtr.ownSymbols, type], [dataPtr.ownSymbols, subType]] THEN
mixed ← TRUE;
IF t.safe THEN safe ← TRUE;
IF t.mode = error THEN error ← TRUE}
ELSE Log.ErrorTree[typeClash, v];
ENDCASE => IF subType # typeANY THEN Log.ErrorTree[typeClash, v];
RETURN};
dataPtr.textIndex ← tb[node].info;
tb[node].son[1] ← UpdateList[tb[node].son[1], CatchLabel];
IF mixed THEN type ← typeANY;
tb[node].son[2] ← CatchBody[
tb[node].son[2], type, safe OR (error AND enclosingSafe)];
IF tb[node].son[1] = Tree.Link[symbol[index: dataPtr.idUNWIND]] THEN {
unwindCaught ← TRUE;
IF current.entry AND ~current.unwindEnabled AND current.catchDepth = 0 THEN {
PushTree[tb[node].son[2]]; PushTree[CopyLock[]];
PushNode[unlock, 1]; SetInfo[dataPtr.textIndex];
tb[node].son[2] ← MakeList[2]}};
tb[node].info ← IF type # typeANY THEN type ELSE SENull;
dataPtr.textIndex ← saveIndex; RETURN};
CatchBody: PROC [body: Tree.Link, type: CSEIndex, safe: BOOL]
RETURNS [val: Tree.Link] = {
saveRecord: RecordSEIndex = current.resumeRecord;
saveFlag: BOOL = current.resumeFlag;
current.catchDepth ← current.catchDepth + 1;
WITH t: seb[type] SELECT FROM
transfer => {
current.resumeFlag ← t.mode = signal;
PushArgCtx[t.typeIn];
BumpArgRefs[ArgRecord[t.typeIn], TRUE];
PushArgCtx[current.resumeRecord ← ArgRecord[t.typeOut]];
ClearRefStack[]};
ENDCASE => {
current.resumeFlag ← FALSE; current.resumeRecord ← RecordSENull};
current.reachable ← TRUE; pathNP ← entryNP;
SELECT OpName[body] FROM
block, checked => SetSafety[SafetyAttr[GetNode[body]]];
ENDCASE;
IF safe AND P3S.safety = none THEN Log.Error[unsafeBlock];
val ← UpdateList[body, Stmt ! InsertCatchLabel => {IF catchSeen THEN RESUME}];
exitNP ← BoundNP[exitNP][pathNP];
WITH t: seb[type] SELECT FROM
transfer => {PopArgCtx[t.typeOut]; PopArgCtx[t.typeIn]};
ENDCASE;
current.catchDepth ← current.catchDepth - 1;
current.resumeRecord ← saveRecord; current.resumeFlag ← saveFlag;
SetSafety[saveSafety]; RETURN};
setLabel, continued: BOOL;
node: Tree.Index = GetNode[t];
SealRefStack[];
setLabel ← continued ← unwindCaught ← FALSE; entryNP ← exitNP ← none;
BEGIN
ENABLE InsertCatchLabel => {
IF ~catchSeen THEN {
setLabel ← TRUE; IF exit THEN continued ← TRUE;
SIGNAL InsertCatchLabel[catchSeen:TRUE, exit:exit]; RESUME}};
ScanList[tb[node].son[1], CatchItem];
IF tb[node].nSons > 1 THEN
tb[node].son[2] ← CatchBody[tb[node].son[2], typeANY, enclosingSafe];
END;
IF setLabel THEN {P3S.markCatch ← TRUE; P3S.continued ← continued};
UnsealRefStack[]; current.reachable ← saveReachable;
phraseNP ← exitNP; pathNP ← savePathNP; RETURN};
PushArgCtx: PROC [sei: CSEIndex] = {
ctx: CTXIndex = ArgCtx[sei];
IF ctx # CTXNull THEN {
ctxb[ctx].level ← current.level + current.catchDepth; PushCtx[ctx]}};
PopArgCtx: PROC [sei: CSEIndex] = {
ctx: CTXIndex = ArgCtx[sei];
IF ctx # CTXNull THEN {PopCtx[]; ctxb[ctx].level ← lZ}};
Resume: PROC [node: Tree.Index] = {
OPEN tb[node];
rSei: RecordSEIndex = current.resumeRecord;
IF ~current.resumeFlag THEN Log.Error[misplacedResume];
IF rSei # SENull AND son[1] = Tree.Null THEN {
n: CARDINAL ← 0;
BumpArgRefs[rSei, FALSE];
FOR sei: ISEIndex ← FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei] UNTIL sei = SENull DO
n ← n+1;
IF n=1 AND seb[sei].hash = HTNull THEN Log.Error[illDefinedReturn];
PushSe[sei];
ENDLOOP;
son[1] ← MakeList[n]}
ELSE {
son[1] ← IF attr1 AND rSei # SENull
THEN Rhs[son[1], rSei]
ELSE MatchFields[rSei, son[1]];
RPop[];
pathNP ← SequenceNP[pathNP][phraseNP]};
current.reachable ← FALSE};
Rope identification (temporary)
CheckHash: PROC [hti: HTIndex, s: LONG STRING] RETURNS [BOOL] = {
desc: ConvertUnsafe.SubString;
desc ← [base: s, offset: 0, length: s.length];
RETURN [FindString[desc] = hti]};
TextRep: PUBLIC PROC [rType: SEIndex] RETURNS [form: TextForm ← text] = {
type: CSEIndex = UnderType[rType];
rope: STRING = "Rope"L;
ropeRep: STRING = "RopeRep"L;
textRep: STRING = "TextRep"L;
WITH se: seb[rType] SELECT FROM
id =>
IF CheckHash[se.hash, ropeRep] THEN form ← rope
ELSE IF CheckHash[se.hash, textRep] THEN form ← ropeText;
ENDCASE;
WITH t: seb[type] SELECT FROM
record =>
WITH c: ctxb[t.fieldCtx] SELECT FROM
included => IF ~CheckHash[mdb[c.module].moduleId, rope] THEN form ← text;
ENDCASE => form ← text;
ENDCASE => form ← text;
RETURN};
}.