IPExecImpl.mesa
Last edited by:
Doug Wyatt, March 9, 1984 1:29:54 pm PST
DIRECTORY
Imager USING [Context],
IO USING [PutFR, rope],
IP USING [Apply, Call, CallWithStateOnPropList, Context, Count, DoWithSaveEffect, Error, GetMarker, Identifier, IdentifierFromRope, InitializeStack, Integer, Mark, Marker, MasterError, MasterWarning, NoPool, nullIndex, nullMarker, NullVector, PopToMark, PopVector, PushIdentifier, PushInt, PushReal, PushVector, RemoveMark, State, StateRep, Unmark, Unmark0, Vector, VectorFromString],
IPExtras USING [],
IPReader USING [Block, BlockNode, BodyNode, FinishBody, GetIndex, GetSkeleton, GetToken, Index, Node, Open, Reader, ReadReal, SetIndex],
RefText USING [TrustTextAsRope],
Rope USING [FromRefText, ROPE];
IPExecImpl: CEDAR PROGRAM
IMPORTS IO, IP, IPReader, RefText, Rope
EXPORTS IP, IPExtras
~ BEGIN OPEN IPReader, IP;
ROPE: TYPE ~ Rope.ROPE;
Reader: TYPE ~ IPReader.Reader;
ReadNextBody: PUBLIC PROC[self: State] RETURNS[index: Index] ~ {
reader: Reader ~ self.master;
reader.GetToken[]; index ← reader.index;
IF reader.token.op=beginBody THEN reader.FinishBody[]
ELSE {
reader.SetIndex[reader.index]; -- back up so we'll read it again
MasterError[$missingBody, "Body literal is missing."];
};
};
IdentifierFromText: PROC[text: REF TEXT] RETURNS[Identifier] ~ {
RETURN[IdentifierFromRope[RefText.TrustTextAsRope[text]]];
};
ExecuteNextBody: PUBLIC PROC[self: State] ~ {
reader: Reader ~ self.master;
reader.GetToken[];
IF reader.token.op=$beginBody THEN DO
reader.GetToken[];
IF reader.token.op=$endBody THEN EXIT
ELSE {
ENABLE Error => GOTO MarkRecovery;
SELECT reader.token.type FROM
$op => Apply[self, reader.token.op];
$shortNumber => PushInt[self, reader.shortNumber];
$integer, $rational, $real => PushReal[self, reader.ReadReal[]];
$identifier => PushIdentifier[self, IdentifierFromText[reader.text]];
$string => PushVector[self, VectorFromString[reader.text]];
$vector => PushVector[self, reader.ReadVector[]];
$insertfile => DoInsertfile[self, Rope.FromRefText[reader.text]];
ENDCASE => { MasterWarning[$bug, "Unexpected token type."]; PushInt[self, 0] };
EXITS MarkRecovery => {
Note: this EXITS clause is outside the scope of the above ENABLE clause.
IF reader.token.op=beginBody THEN reader.FinishBody[]; -- skip misplaced body literal
IF DoMarkRecovery[self].proceed THEN NULL -- carry on
ELSE ERROR Error; -- finished the body; exit this context and retry mark recovery
};
};
ENDLOOP
ELSE {
reader.SetIndex[reader.index]; -- back up so we'll read it again
MasterError[$missingBody, "Body to be executed is missing."];
};
};
PopToActiveMark: PROC[self: State] RETURNS[Marker] ~ {
"the stack is popped until a mark is on top; if the context that placed the mark on the stack no longer exists, the mark is popped and there is another mark recovery"
DO marker: Marker ~ PopToMark[self]; -- this leaves a mark on top of the stack
IF marker=nullMarker THEN RETURN[marker];
FOR context: Context ← self.context, context.caller UNTIL context=NIL DO
IF context.marker=marker THEN RETURN[marker]; -- context still exists
ENDLOOP;
RemoveMark[self, marker]; -- remove orphaned mark and try again
ENDLOOP;
};
DoMarkRecovery: PROC[self: State] RETURNS[proceed: BOOL] ~ {
reader: Reader ~ self.master;
"the stack is popped until a mark is on top ..."
marker: Marker ~ PopToActiveMark[self];
"composed operators in execution are exited until the one which placed the mark is executing"
IF marker#GetMarker[self] THEN { reader.FinishBody[]; RETURN[FALSE] }; -- not me
"literals are skipped in this operator until an UNMARK0 literal is found."
DO reader.GetToken[];
SELECT reader.token.op FROM
unmark0 => EXIT; -- success!
beginBody => reader.FinishBody[]; -- skip body literal
endBody => RETURN[FALSE]; -- reached end of body without seeing unmark0
ENDCASE;
ENDLOOP;
"the UNMARK0 is executed, thus popping the mark from the stack, and execution proceeds from this point."
Unmark0[self]; RETURN[TRUE];
};
PushString: PROC[self: State, text: REF TEXT] ~ {
ERROR;
};
DoInsertfile: PROC[self: State, file: ROPE] ~ {
MasterWarning[$unimplemented, IO.PutFR["Ignoring Insertfile[%g].", IO.rope[file]]];
};
GetIndex: PUBLIC PROC[self: State] RETURNS[Index] ~ {
reader: Reader ~ self.master;
RETURN[reader.GetIndex[]];
};
SetIndex: PUBLIC PROC[self: State, index: Index] ~ {
reader: Reader ~ self.master;
reader.SetIndex[index];
};
ExecuteBody: PUBLIC PROC[self: State, body: Index] ~ {
IF body#nullIndex THEN {
reader: Reader ~ self.master;
index: Index ~ reader.GetIndex[];
reader.SetIndex[body];
ExecuteNextBody[self ! UNWIND => reader.SetIndex[index]];
reader.SetIndex[index];
};
};
ExecuteBlock: PUBLIC PROC[self: State, block: Block] ~ {
MasterError[$unimplemented, "ExecuteBlock is not implemented."];
};
ExecuteNode: PROC[self: State, node: Node] ~ {
WITH node SELECT FROM
node: BodyNode => ExecuteBody[self, node.body];
node: BlockNode => ExecuteBlock[self, node.block];
ENDCASE => ERROR;
};
maxStackLength: Integer ← 1000;
topFrameSize: Integer ~ 50;
initialTopFrame: Vector ~ NullVector[[l: 0, n: topFrameSize]];
emptyVector: Vector ~ NullVector[[l: 0, n: 0]];
OpenMaster: PUBLIC PROC[name: ROPE, imager: Imager.Context] RETURNS[State] ~ {
reader: Reader ~ IPReader.Open[name];
self: State ~ NEW[StateRep ← []];
self.master ← reader;
self.skeleton ← reader.GetSkeleton[];
InitializeStack[self, maxStackLength];
self.imager ← imager;
[] ← DoPreamble[self];
RETURN[self];
};
DoTopAction: PROC[self: State, action: PROC[State]] RETURNS[ok: BOOL] ~ {
inner: PROC ~ { ok ← DoWithMarkProtection[self, action] };
CallWithStateOnPropList[self, inner];
};
DoWithMarkProtection: PUBLIC PROC[self: State, action: PROC[State]] RETURNS[BOOL] ~ {
Mark[self, 0]; action[self ! Error => GOTO MarkRecovery];
Unmark0[self]; RETURN[TRUE];
EXITS MarkRecovery => {
IF PopToActiveMark[self]#GetMarker[self] THEN ERROR Error
ELSE { Unmark0[self]; RETURN[FALSE] };
};
};
CallSaveAll: PROC[self: State, action: PROC[State], frame: Vector, env: Vector] ~ {
CallAction: PROC ~ { Call[self: self, action: action, frame: frame, pool: NoPool[], env: env] };
DoWithSaveEffect[self, CallAction, $saveAll];
};
DoPreamble: PROC[self: State] RETURNS[BOOL] ~ {
InnerDoPreamble: PROC[self: State] ~ {
ExecutePreamble: PROC[self: State] ~ {
Mark[self, 0];
ExecuteNode[self, self.skeleton.preamble];
IF Count[self]<1 THEN Apply[self, $env];
IF Count[self]<2 THEN Apply[self, $frame];
Unmark[self, 2];
};
CallSaveAll[self: self, action: ExecutePreamble, frame: initialTopFrame, env: emptyVector];
self.topFrame ← PopVector[self];
self.topEnv ← PopVector[self];
};
RETURN[DoTopAction[self, InnerDoPreamble]];
};
PageCount: PUBLIC PROC[self: State] RETURNS[NAT] ~ {
RETURN[self.skeleton.size];
};
DoPage: PUBLIC PROC[self: State, n: NAT] RETURNS[BOOL] ~ {
IF n IN[1..self.skeleton.size] THEN {
page: NAT ~ n-1;
InnerDoPage: PROC[self: State] ~ {
ExecutePage: PROC[self: State] ~ { ExecuteNode[self, self.skeleton[page]] };
CallSaveAll[self: self, action: ExecutePage, frame: self.topFrame, env: self.topEnv];
};
RETURN[DoTopAction[self, InnerDoPage]];
}
ELSE RETURN[FALSE];
};
END.
ObtainExternalInstructions: PROC[self: State] RETURNS[Vector] ~ {
RETURN[VectorFromAny[GetP[Env[self], $externalInstructions]]];
};
AddInstructionDefaults: PROC[self: State, computedInstructions, externalInstructions: Vector]
RETURNS[Vector] ~ {
RETURN[computedInstructions]
};
ExecuteInstructionsBody: PROC[self: State, externalInstructions: Vector] RETURNS[Vector] ~ {
body: Index ~ self.skeleton.preamble.instructions;
IF body=nullIndex THEN RETURN[externalInstructions]
ELSE {
reader: Reader ~ NARROW[self.master];
PushVector[self, externalInstructions];
reader.SetIndex[body];
DoBody[self, NoPool[], initialTopFrame, $saveAll];
WHILE Count[self]>1 DO Apply[self, $mergeprop] ENDLOOP;
RETURN[PopVector[self]];
};
};
ComputePrintingInstructions: PROC[self: State] ~ {
externalInstructions: Vector ~ ObtainExternalInstructions[self];
instructions: Vector ← emptyVector;
Mark[self, 0];
instructions ← ExecuteInstructionsBody[self, externalInstructions ! Error => CONTINUE];
Unmark0[self];
instructions ← AddInstructionDefaults[self, instructions, externalInstructions];
self.media ← GetP[instructions, $media];
self.copySelect ← GetP[instructions, $copySelect];
self.pageSelect ← GetP[instructions, $pageSelect];
self.onSimplex ← GetP[instructions, $onSimplex];
self.mediaSelect ← GetP[instructions, $mediaSelect];
self.copyName ← GetP[instructions, $copyName];
self.instructions ← instructions;
};