<> <<>> <> <> 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 => { <> 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. <<>> <> <> <<};>> <<>> <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> <1 DO Apply[self, $mergeprop] ENDLOOP;>> <> <<};>> <<};>> <<>> <> <> <> <<>> <> < CONTINUE];>> <> <<>> <> <<>> <> <> <> <> <> <> <> <<};>> <<>>