IPExecImpl.mesa
Copyright Ó 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, November 26, 1986 9:35:38 am PST
Doug Wyatt, December 3, 1986 5:38:45 pm PST
Allan H. Wax December 3, 1986 5:48:11 pm PST
Allan Wax: February 4, 1987 10:50:11 am PST
DIRECTORY
FS USING [StreamOpen],
Imager USING [Context, ContextRep, DoSave, DoSaveAll, ShowText],
ImagerFont USING [MapText, XStringProc],
Interpress USING [classMasterError, classMasterWarning, LogProc, Master, MasterImplRep, MasterRep, Credentials, Instructions],
IO USING [int, PutFR1, STREAM],
IPExecute USING [defaultMaxStackLength],
IPInterpreter USING [Any, Apply, Array, ArrayFromVector, Cardinal, Context, ContextRep, Count, Get, Mark, Marker, Operator, OperatorClass, OperatorClassRep, OperatorRep, PopToActiveMark, PushIdentifier, PushNum, PushVector, Ref, Rep, StackArrayRep, Unmark, Vector, VectorFromArray, VectorFromBits, VectorFromBytes, VectorFromString, ZeroVec],
IPMaster USING [Block, Body, BYTE, GetSkeleton, GetToken, IntFromSequenceData, OpFromEncodingValue, Node, NodeRep, Preamble, RealFromSequenceData, SequenceType, Skeleton, SkeletonRecord, SkipBytes, SkipToEndOfBody, Token, Vector],
RefText USING [ReserveChars],
Rope USING [AppendChars, Concat, Fetch, FromRefText, ROPE, Size, Substr],
RopeFile USING [FromStream];
IPExecImpl: CEDAR PROGRAM
IMPORTS FS, IO, Imager, ImagerFont, IPInterpreter, IPMaster, RefText, Rope, RopeFile
EXPORTS Interpress, IPInterpreter, IPExecute
~ {
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
Token: TYPE ~ IPMaster.Token;
Body: TYPE ~ IPMaster.Body;
Block: TYPE ~ IPMaster.Block;
Node: TYPE ~ IPMaster.Node;
NodeRep: TYPE ~ IPMaster.NodeRep;
BYTE: TYPE ~ IPMaster.BYTE;
MarkRecovery: PUBLIC ERROR ~ CODE;
Bug: PUBLIC ERROR ~ CODE;
contextFreeCountMax: INT ← 8;
AllocContext: PROC [self: IPInterpreter.Ref] RETURNS [context: IPInterpreter.Context] ~ {
IF self.contextFreeCount>0 THEN {
context ← self.contextFree;
self.contextFree ← context.caller;
self.contextFreeCount ← self.contextFreeCount-1}
ELSE context ← NEW [IPInterpreter.ContextRep];
};
FreeContext: PROC [self: IPInterpreter.Ref, context: IPInterpreter.Context] ~ {
IF self.contextFreeCount<contextFreeCountMax THEN {
context.caller ← self.contextFree;
context.initialFrame ← NIL;
context.frame ← NIL;
context.env ← NIL;
self.contextFree ← context;
self.contextFreeCount ← self.contextFreeCount+1};
};
Call: PUBLIC PROC[self: IPInterpreter.Ref, action: PROC, frame, env: IPMaster.Vector] ~ {
context: IPInterpreter.Context ~ AllocContext[self];
context^ ← [caller: self.context, marker: self.lastMarker+1,
token: [], initialFrame: frame, frame: NIL, env: env];
self.lastMarker ← context.marker;
self.context ← context;
action[! UNWIND => { self.context ← context.caller; FreeContext[self, context] }];
IF self.context=context THEN { self.context ← context.caller; FreeContext[self, context] }
ELSE ERROR Bug;
};
Frame: PUBLIC PROC[self: IPInterpreter.Ref] RETURNS[IPMaster.Vector] ~ {
context: IPInterpreter.Context ~ self.context;
IF context.frame=NIL THEN RETURN[context.initialFrame]
ELSE RETURN[IPInterpreter.VectorFromArray[context.frame]];
};
FGet: PUBLIC PROC[self: IPInterpreter.Ref, i: IPInterpreter.Cardinal] RETURNS[IPInterpreter.Any] ~ {
context: IPInterpreter.Context ~ self.context;
IF context.frame=NIL THEN RETURN[IPInterpreter.Get[context.initialFrame, i]]
ELSE { array: IPInterpreter.Array ~ context.frame; RETURN[array[i-array.lowerBound]] };
};
FSet: PUBLIC PROC[self: IPInterpreter.Ref, x: IPInterpreter.Any, i: IPInterpreter.Cardinal] ~ {
context: IPInterpreter.Context ~ self.context;
IF context.frame=NIL THEN context.frame ← IPInterpreter.ArrayFromVector[context.initialFrame];
{ array: IPInterpreter.Array ~ context.frame; array[i-array.lowerBound] ← x };
};
Env: PUBLIC PROC[self: IPInterpreter.Ref] RETURNS[IPMaster.Vector] ~ {RETURN[self.context.env]};
DoSave: PUBLIC PROC[self: IPInterpreter.Ref, action: PROC] ~ {
Someday, this might worry about pools other than the Imager pool
Imager.DoSave[self.imager, action];
};
DoSaveAll: PUBLIC PROC[self: IPInterpreter.Ref, action: PROC] ~ {
Someday, this might worry about pools other than the Imager pool
Imager.DoSaveAll[self.imager, action];
};
Run: TYPE ~ RECORD[start, len: INT];
RunList: TYPE ~ LIST OF Run;
DoString: PROC [self: IPInterpreter.Ref, text: REF TEXT] ~ {
string: ImagerFont.XStringProc ~ { ImagerFont.MapText[text: text, charAction: charAction] };
IPInterpreter.PushVector[self, IPInterpreter.VectorFromString[string]];
};
DoIdentifier: PROC [self: IPInterpreter.Ref, text: REF TEXT] ~ {
len: NAT ~ text.length;
warn: BOOLFALSE;
FOR i: NAT IN[0..len) DO
char: CHAR ~ text[i];
SELECT char FROM
IN['a..'z], IN['A..'Z] => NULL;
IN['0..'9], '- => IF i=0 THEN warn ← TRUE;
ENDCASE => warn ← TRUE;
ENDLOOP;
IF len=0 THEN warn ← TRUE;
IPInterpreter.PushIdentifier[self, Rope.FromRefText[text]];
IF warn THEN MasterWarning[$invalidEncoding, "Invalid Identifier"];
};
DoCardinal: PROC [self: IPInterpreter.Ref, text: REF TEXT] ~ {
len: NAT ~ text.length;
IF len<=4 THEN {
val: INT ~ IPMaster.IntFromSequenceData[text];
IPInterpreter.PushNum[self, [int[val]]]}
ELSE {
val: REAL ~ IPMaster.RealFromSequenceData[text];
IPInterpreter.PushNum[self, [real[val]]]};
};
DoRational: PROC [self: IPInterpreter.Ref, text: REF TEXT] ~ {
len: NAT ~ text.length;
half: NAT ~ len/2;
IF half<=4 THEN {
n: INT ~ IPMaster.IntFromSequenceData[text: text, start: 0, len: half];
d: INT ~ IPMaster.IntFromSequenceData[text: text, start: half, len: half];
IF n IN INTEGER AND d IN INTEGER THEN IPInterpreter.PushNum[self, [rational[n: n, d: d]]]
ELSE IPInterpreter.PushNum[self, [real[REAL[n]/REAL[d]]]]}
ELSE {
n: REAL ~ IPMaster.RealFromSequenceData[text: text, start: 0, len: half];
d: REAL ~ IPMaster.RealFromSequenceData[text: text, start: half, len: half];
IPInterpreter.PushNum[self, [real[n/d]]]};
IF (half+half)#len THEN MasterWarning[$invalidEncoding,
IO.PutFR1["Invalid sequenceRational (length=%g)", IO.int[len]]];
};
DoInsertFile: PROC [self: IPInterpreter.Ref, text: REF TEXT] ~ {
MasterWarning[$unimplemented, "sequenceInsertFile found after PreScanning"];
};
Fetch16: PROC [rope: ROPE, startByte: INT] RETURNS [CARDINAL] ~ {
b0: CARDINAL ~ Rope.Fetch[rope, startByte]-'\000;
b1: CARDINAL ~ Rope.Fetch[rope, startByte+1]-'\000;
RETURN [b0*256+b1];
};
RopeFromRuns: PROC [ropeChunk: ROPE, runs: LIST OF Run, sequenceLength: INT] RETURNS [rope: ROPENIL] ~ {
FOR r: LIST OF Run ← runs, r.rest UNTIL r = NIL DO
run: Run ← r.first;
rope ← Rope.Concat[rope, Rope.Substr[ropeChunk, run.start, run.len]];
ENDLOOP;
IF Rope.Size[rope] # sequenceLength THEN ERROR;
};
ExecuteToEndOfBody: PROC [self: IPInterpreter.Ref] ~ {
sequenceData: {nil, text, runs, skip} ← nil;
sequenceType: IPMaster.SequenceType ← nil;
sequenceLength: INT ← 0;
sequenceRuns: INT ← 0;
text: REF TEXTNIL;
buffer: REF TEXT ~ self.buffer;
runsHead, runsTail: LIST OF Run ← NIL;
token: IPMaster.Token;
BeginSequence: PROC [seq: IPMaster.SequenceType] ~ {
SELECT sequenceType ← seq FROM
sequenceString, sequenceIdentifier, sequenceInsertFile, sequenceComment,
sequenceInteger, sequenceRational => sequenceData ← text;
sequenceLargeVector, sequencePackedPixelVector, sequenceCompressedPixelVector, sequenceAdaptivePixelVector => sequenceData ← runs;
ENDCASE => sequenceData ← skip;
SELECT sequenceData FROM
text => { text ← buffer; text.length ← 0 };
runs => { runsHead ← runsTail ← NIL };
ENDCASE;
sequenceLength ← 0;
};
ExtendSequence: PROC [length: INT] ~ {
SELECT sequenceData FROM
nil => {
MasterWarning[$invalidEncoding, "Misplaced sequenceContinued"];
self.index ← IPMaster.SkipBytes[self.rope, self.index, length]};
text => {
len: NAT ~ length;
IF (text.maxLength-text.length) < len THEN text ← RefText.ReserveChars[text, len];
[] ← Rope.AppendChars[buffer: text, rope: self.rope, start: self.index, len: len];
self.index ← IPMaster.SkipBytes[self.rope, self.index, length] -- This wasn't here before -- };
runs => {
prevTail: LIST OF Run ~ runsTail;
runsTail ← LIST[[start: self.index, len: length]];
IF prevTail=NIL THEN runsHead ← runsTail ELSE prevTail.rest ← runsTail;
self.index ← IPMaster.SkipBytes[self.rope, self.index, length]};
skip => self.index ← IPMaster.SkipBytes[self.rope, self.index, length];
ENDCASE => ERROR;
sequenceRuns ← sequenceRuns+1;
sequenceLength ← sequenceLength+length;
};
FinishSequence: PROC ~ {
SELECT sequenceType FROM
sequenceString => DoString[self, text];
sequenceIdentifier => DoIdentifier[self, text];
sequenceInteger => DoCardinal[self, text];
sequenceRational => DoRational[self, text];
sequenceInsertFile => DoInsertFile[self, text];
sequenceComment => NULL;
sequenceLargeVector => {
rope: ROPE ~ RopeFromRuns[self.rope, runsHead, sequenceLength];
b: NAT ~ Rope.Fetch[rope, 0]-'\000;
vector: IPMaster.Vector ~ IPInterpreter.VectorFromBytes[bytes: Rope.Substr[rope, 1], bytesPerElement: b, signed: TRUE];
IPInterpreter.PushVector[self, vector]};
sequencePackedPixelVector => {
rope: ROPE ~ RopeFromRuns[self.rope, runsHead, sequenceLength];
bitsPerSample: [1..1] ~ Fetch16[rope, 0]; -- only one bit per sample supported here
scanLength: NAT ~ Fetch16[rope, 2];
dataBitsPerLine: NAT ~ bitsPerSample*scanLength;
padBitsPerLine: NAT ~ NAT[32 - (dataBitsPerLine MOD 32)] MOD 32;
vector: IPMaster.Vector ~ IPInterpreter.VectorFromBits[bytes: Rope.Substr[rope, 4], dataBitsPerLine: dataBitsPerLine, padBitsPerLine: padBitsPerLine];
IPInterpreter.PushVector[self, vector]};
sequenceCompressedPixelVector => MasterWarning[$unimplemented, "Not implemented: sequenceCompressedPixelVector"];
sequenceAdaptivePixelVector => MasterWarning[$unimplemented, "Not implemented: sequenceAdaptivePixelVector"];
sequenceContinued => MasterWarning[$invalidEncoding, "Misplaced sequenceContinued"];
ENDCASE => MasterWarning[$invalidEncoding, IO.PutFR1["Invalid sequence type (%g)", IO.int[ORD[sequenceType]]]];
sequenceData ← nil;
sequenceType ← nil;
};
DO -- for each Token
[token, self.index] ← IPMaster.GetToken[encoding: self.rope, start: self.index];
IF token.seq=sequenceContinued THEN { ExtendSequence[token.len]; LOOP };
self.context.token ← token;
IF sequenceType=sequenceString THEN {
done: BOOLTRUE;
SELECT token.op FROM
show => Imager.ShowText[context: self.imager, text: text];
showandxrel => Imager.ShowText[context: self.imager, text: text, xrel: TRUE];
ENDCASE => done ← FALSE;
IF done THEN { sequenceData ← nil; sequenceType ← nil; LOOP }};
IF sequenceData#nil THEN FinishSequence[];
IF token.op=endBody THEN EXIT;
SELECT token.type FROM
op => IPInterpreter.Apply[self, IPMaster.OpFromEncodingValue[token.op]];
num => IPInterpreter.PushNum[self, [int[token.num]]];
seq => { BeginSequence[token.seq]; ExtendSequence[token.len] };
ENDCASE => ERROR;
ENDLOOP
};
BeginBody: PROC [self: IPInterpreter.Ref] RETURNS [INT] ~ {
[self.context.token, self.index] ← IPMaster.GetToken[self.rope, self.index];
IF self.context.token.op # beginBody THEN MasterError[$missingBody, "Missing body"];
RETURN[self.index];
};
SkipInlineBody: PUBLIC PROC [self: IPInterpreter.Ref] ~ {
self.index ← BeginBody[self];
self.index ← IPMaster.SkipToEndOfBody[self.rope, self.index];
};
GetInlineBody: PUBLIC PROC [self: IPInterpreter.Ref] RETURNS [IPMaster.Body] ~ {
start, stop: INT ← 0;
start ← self.index;
self.index ← BeginBody[self];
stop ← self.index ← IPMaster.SkipToEndOfBody[self.rope, self.index];
RETURN[Rope.Substr[self.rope, start, stop-start]];
};
ExecuteInlineBody: PROC [self: IPInterpreter.Ref] ~ {
self.index ← BeginBody[self];
DO error: BOOLFALSE;
ExecuteToEndOfBody[self ! MarkRecovery => { error ← TRUE; CONTINUE }];
IF error THEN { -- do mark recovery
marker: IPInterpreter.Marker ~ IPInterpreter.PopToActiveMark[self];
IF marker=self.context.marker THEN {
token: IPMaster.Token;
DO
[token, self.index] ← IPMaster.GetToken[self.rope, self.index];
SELECT token.op FROM
endBody => ERROR MarkRecovery; -- end of body
beginBody => self.index ← IPMaster.SkipToEndOfBody[self.rope, self.index]; -- skip body literal
unmark0 => EXIT; -- found UNMARK0
ENDCASE => NULL;
IF token.type=seq THEN self.index ← IPMaster.SkipBytes[self.rope, self.index, token.len];
ENDLOOP}
ELSE ERROR MarkRecovery; -- not this context's marker
}
ELSE EXIT; -- normal completion
ENDLOOP;
};
CallInlineBody: PUBLIC PROC [self: IPInterpreter.Ref, frame, env: IPMaster.Vector] ~ {
action: PROC ~ { ExecuteInlineBody[self] };
Call[self: self, action: action, frame: frame, env: env];
};
CallBody: PROC [self: IPInterpreter.Ref, body: IPMaster.Body, frame: IPMaster.Vector, env: IPMaster.Vector] ~ {
saveBody: ROPE ~ self.rope;
saveIndex: INT ~ self.index;
self.rope ← body;
self.index ← 0;
CallInlineBody[self: self, frame: frame, env: env
! UNWIND => {self.rope ← saveBody; self.index ← saveIndex}];
self.rope ← saveBody;
self.index ← saveIndex;
};
DoWithMarkProtection: PUBLIC PROC [self: IPInterpreter.Ref, action: PROC] ~ {
error: BOOLFALSE;
inner: PROC ~ { IPInterpreter.Mark[self, 0]; action[]; IPInterpreter.Unmark[self, 0] };
inner[! MarkRecovery => { error ← TRUE; CONTINUE}];
IF error THEN { -- do mark recovery
marker: IPInterpreter.Marker ~ IPInterpreter.PopToActiveMark[self];
IF marker=self.context.marker THEN IPInterpreter.Unmark[self, 0]
ELSE ERROR MarkRecovery;
};
};
Do: PUBLIC PROC [self: IPInterpreter.Ref, op: IPInterpreter.Operator] ~ { op.class.do[op, self] };
composedClass: IPInterpreter.OperatorClass ~ NEW[IPInterpreter.OperatorClassRep ← [
type: $Composed, do: ComposedDo]];
ComposedData: TYPE ~ REF ComposedDataRep;
ComposedDataRep: TYPE ~ RECORD[
frame: IPMaster.Vector, -- initial frame
env: IPMaster.Vector, -- environment
body: IPMaster.Body -- body of the operator
];
ComposedDo: PROC [op: IPInterpreter.Operator, state: IPInterpreter.Ref] ~ {
data: ComposedData ~ NARROW[op.data];
CallBody[self: state, body: data.body, frame: data.frame, env: data.env];
};
MakeCO: PUBLIC PROC [frame, env: IPMaster.Vector, body: IPMaster.Body]
RETURNS [IPInterpreter.Operator] ~ {
data: ComposedData ~ NEW[ComposedDataRep ← [frame: frame, env: env, body: body]];
RETURN[NEW[IPInterpreter.OperatorRep ← [class: composedClass, data: data]]];
};
CallPreamble: PUBLIC PROC [self: IPInterpreter.Ref, preamble: IPMaster.Preamble, frame, env: IPMaster.Vector] ~ {
IF preamble # NIL THEN {
preambleProc: PROC ~ {
IPInterpreter.Mark[self, 0];
ExecuteInlineBody[self];
IF IPInterpreter.Count[self]<1 THEN IPInterpreter.PushVector[self, Env[self]];
IF IPInterpreter.Count[self]<2 THEN IPInterpreter.PushVector[self, Frame[self]];
IPInterpreter.Unmark[self, 2]};
IF preamble.initialFrame = NIL THEN {
oldSource: ROPE = self.rope;
oldIndex: INT = self.index;
self.rope ← preamble.source;
self.index ← 0;
self.topFrame ← frame;
self.topEnv ← env;
Call[self: self, action: preambleProc, frame: frame, env: env];
self.rope ← oldSource;
self.index ← oldIndex;
preamble.initialFrame ← self.topFrame}
ELSE self.topFrame ← preamble.initialFrame}
ELSE ERROR;
};
CallNode: PUBLIC PROC [self: IPInterpreter.Ref, node: Node, frame, env: IPMaster.Vector] ~ {
WITH node SELECT FROM
node: REF NodeRep.body => {
self.rope ← node.body;
self.index ← 0;
CallInlineBody[self: self, frame: frame, env: env]}; -- May have to save old self values
node: REF NodeRep.block => {
block: Block ~ node.block;
pageFrame, pageEnv: Vector;
CallPreamble[self, block.preamble, frame, env];
pageFrame ← PopVector[self];
pageEnv ← PopVector[self];
FOR i: NAT IN[0..block.size) DO
CallNode[self, block[i], pageFrame, pageEnv];
ENDLOOP;
};
ENDCASE => ERROR;
};
Master: TYPE ~ Interpress.Master;
MasterRep: TYPE ~ Interpress.MasterRep;
MasterImpl: TYPE ~ REF MasterImplRep;
MasterImplRep: PUBLIC TYPE ~ RECORD [ -- exported to Interpress
skeleton: IPMaster.Skeleton,
interpreter: IPInterpreter.Ref
];
LogProc: TYPE ~ Interpress.LogProc;
Error: SIGNAL [class: INT, code: ATOM, explanation: ROPE] ~ CODE;
ReportError: PUBLIC PROC [class: INT, code: ATOM, explanation: ROPE] ~ {
SIGNAL Error[class: class, code: code, explanation: explanation];
IF class=Interpress.classMasterError THEN ERROR MarkRecovery;
};
MasterError: PUBLIC PROC [code: ATOM, explanation: ROPE] ~ {
ReportError[class: Interpress.classMasterError, code: code, explanation: explanation];
};
MasterWarning: PUBLIC PROC [code: ATOM, explanation: ROPE ←] ~ {
ReportError[class: Interpress.classMasterWarning, code: code, explanation: explanation];
};
DoTopAction: PUBLIC PROC [self: IPInterpreter.Ref, action: PROC, log: LogProc] ~ {
protect: PROC ~ { DoWithMarkProtection[self, action] };
call: PROC ~ { Call[self, protect, IPInterpreter.ZeroVec[0], IPInterpreter.ZeroVec[0]] };
save: PROC ~ { IF self.imager=NIL THEN call[] ELSE DoSaveAll[self, call] };
save[! Error => { IF log#NIL THEN {log[class, code, explanation]; RESUME} ELSE REJECT }];
};
DoPreamble: PROC [master: Master, log: LogProc] ~ {
impl: MasterImpl ~ master.impl;
self: IPInterpreter.Ref ~ impl.interpreter;
block: Block ~ impl.skeleton.topBlock;
action: PROC ~ {
CallPreamble[self: self, preamble: block.preamble, frame: iPExecute.topFrame, env: iPExecute.topEnv];
self.topFrame ← IPInterpreter.PopVector[self];
self.topEnv ← IPInterpreter.PopVector[self];
};
DoTopAction[self, action, log];
};
Open: PUBLIC PROC [fileName: ROPE, log: LogProc, credentials: Interpress.Credentials ← NIL, instructionsHandle: Interpress.Instructions ← NIL] RETURNS [Master] ~ {
RETURN [FromStream[FS.StreamOpen[fileName], log]];
};
FromStream: PUBLIC PROC [stream: STREAM, log: LogProc, credentials: Interpress.Credentials ← NIL, instructionsHandle: Interpress.Instructions ← NIL] RETURNS [Master] ~ {
skeleton: IPMaster.Skeleton ← NEW[IPMaster.SkeletonRecord ← IPMaster.GetSkeleton[master: RopeFile.FromStream[stream], start: 0]];
self: IPInterpreter.Ref ~ NEW[IPInterpreter.Rep -- ← [stream: stream] --];
impl: MasterImpl ~ NEW[MasterImplRep ← [skeleton: skeleton, interpreter: self]];
master: Master ~ NEW[MasterRep ← [pages: skeleton.topBlock.totalPlates, impl: impl]];
self.buffer ← NEW[TEXT[200]];
self.stackArray ← NEW[IPInterpreter.StackArrayRep ← ALL[[zero[]]]];
self.stackCountMax ← IPExecute.defaultMaxStackLength;
self.imager ← imager; -- -- dummy imager context
DoPreamble[master, log]; *** Already done by GetSkeleton ***
RETURN[master];
};
BlockForPage: PROC [skeleton: IPMaster.Skeleton, page: INT] RETURNS [block: Block] ~ {
FindBlock: PROC [block: Block, page: INT] RETURNS [blockFound: Block ← NIL] ~ {
currentPage: INT ← block.startingPlateNumber+1;
IF block.startingPlateNumber > page-1 THEN ERROR;
IF block.startingPlateNumber+block.totalPlates < page THEN RETURN;
The requested page is contained within this block
FOR i: NAT IN [0..block.size) DO
node: Node = block[i];
WITH node SELECT FROM
node: REF NodeRep.body =>
IF currentPage = page THEN RETURN [block]
ELSE currentPage ← currentPage+1;
node: REF NodeRep.block =>
IF (blockFound ← FindBlock[node.block, page]) # NIL THEN RETURN
ELSE currentPage ← currentPage+node.block.totalPlates;
ENDCASE => ERROR;
ENDLOOP;
ERROR; -- Should never get here
};
RETURN [FindBlock[block: skeleton.topBlock, page: page]]
};
NodeForPage: PROC [block: Block, page: INT] RETURNS [node: Node] ~ {
FindNode: PROC [block: Block, page: INT] RETURNS [nodeFound: Node ← NIL] ~ {
currentPage: INT ← block.startingPlateNumber+1;
IF block.startingPlateNumber > page-1 THEN ERROR;
IF block.startingPlateNumber+block.totalPlates < page THEN RETURN;
The requested page is contained within this block
FOR i: NAT IN [0..block.size) DO
node: Node = block[i];
WITH node SELECT FROM
node: REF NodeRep.body =>
IF currentPage = page THEN RETURN [node]
ELSE currentPage ← currentPage+1;
node: REF NodeRep.block =>
IF (nodeFound ← FindNode[node.block, page]) # NIL THEN RETURN
ELSE currentPage ← currentPage+node.block.totalPlates;
ENDCASE => ERROR;
ENDLOOP;
ERROR; -- Should never get here
};
RETURN [FindNode[block: block, page: page]]
};
DoPage: PUBLIC PROC [master: Master, page: INT, context: Imager.Context, log: LogProc, copy: INT ← 1] ~ {
IF page IN[1..master.pages] THEN {
impl: MasterImpl ~ master.impl;
block: Block ~ BlockForPage[impl.skeleton, page];
node: Node ~ NodeForPage[block, page];
self: IPInterpreter.Ref ~ impl.interpreter;
action: PROC ~ { CallNode[self: self, node: node, frame: self.topFrame, env: self.topEnv] };
self.imager ← context;
self.topFrame ← block.preamble.initialFrame;
self.topEnv ← block.preamble.environment;
DoTopAction[self, action, log];
self.imager ← NIL};
};
Close: PUBLIC PROC [master: Master] ~ {
Eventually will use the new structure for the Master which includes a list of SIF/SIM files referenced and delete/flush them after all RopeFile references to them have been un-made. This will preclude using up the cache on Cedar and is necessary for the NS version of the product.
};
}.
ObtainExternalInstructions: PROC [self: Ref] RETURNS [Vector] ~ {
RETURN[VectorFromAny[GetP[Env[self], $externalInstructions]]];
};
AddInstructionDefaults: PROC [self: Ref, computedInstructions, externalInstructions: Vector]
RETURNS [Vector] ~ {
RETURN[computedInstructions]
};
ExecuteInstructionsBody: PROC [self: Ref, externalInstructions: Vector] RETURNS [Vector] ~ {
body: Index ~ self.skeleton.preamble.instructions;
IF body=nullIndex THEN RETURN[externalInstructions]
ELSE {
reader: Reader ~ NARROW[self.reader];
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: Ref] ~ {
externalInstructions: Vector ~ ObtainExternalInstructions[self];
instructions: Vector ← iPExecute.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;
};