<<>> <> <> <> <> <> <> <> DIRECTORY EditedStream USING [DeliverWhenProc, IsACR, SetDeliverWhen], List USING [AList, DotCons], IO USING [BreakProc, CharsAvail, Close, EndOf, EndOfStream, Error, Flush, GetChar, GetTokenRope, PutF, PutRope, Reset, Rubout, STREAM], MBQueue USING [Create, CreateMenuEntry, Queue], Menus USING [InsertMenuEntry, MenuProc], Process USING [Abort, Detach, GetCurrent, InvalidProcess], ProcessProps USING [AddPropList], ReadEvalPrint, Rope USING [Concat, Fetch, Length, ROPE], RuntimeError USING [UNCAUGHT], TypeScript USING [Create], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, RegisterEventProc], ViewerIO USING [CreateViewerStreams], ViewerOps USING [AddProp, ComputeColumn, FetchProp]; ReadEvalPrintImpl: CEDAR MONITOR IMPORTS EditedStream, IO, List, MBQueue, Menus, Process, ProcessProps, Rope, RuntimeError, TypeScript, ViewerEvents, ViewerIO, ViewerOps EXPORTS ReadEvalPrint = BEGIN Handle: TYPE = ReadEvalPrint.Handle; ViewerInfoRec: TYPE = ReadEvalPrint.ViewerInfoRec; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; CreateViewerEvaluator: PUBLIC PROC [clientProc: ReadEvalPrint.ClientProc, prompt: ROPE ¬ NIL, info: ViewerInfoRec, edited: BOOL ¬ TRUE, deliverWhen: EditedStream.DeliverWhenProc ¬ NIL, clientData: REF ¬ NIL, topLevel: BOOL ¬ TRUE] RETURNS [h: Handle] = { viewer: ViewerClasses.Viewer; h ¬ NEW[ReadEvalPrint.RObject ¬ []]; h.clientProc ¬ clientProc; IF deliverWhen = NIL THEN deliverWhen ¬ EditedStream.IsACR; h.deliverWhenProc ¬ deliverWhen; h.menuHitQueue ¬ MBQueue.Create[]; h.prompt ¬ prompt; h.viewer ¬ viewer ¬ TypeScript.Create[info: [name: info.name, label: info.label, column: SELECT info.column FROM $right => right, $color => color, ENDCASE => left, iconic: info.iconic], paint: FALSE]; h.clientData ¬ clientData; h.topLevel ¬ topLevel; ViewerOps.AddProp[viewer, $ReadEvalPrint, h]; [in: h.in, out: h.out] ¬ ViewerIO.CreateViewerStreams[name: NIL, viewer: viewer, editedStream: edited]; IF edited THEN EditedStream.SetDeliverWhen[h.in, deliverWhen]; Menus.InsertMenuEntry[menu: viewer.menu, line: 0, entry: MBQueue.CreateMenuEntry[q: h.menuHitQueue, name: "STOP!", proc: StopHit, clientData: h]]; ViewerOps.ComputeColumn[column: viewer.column]; }; <<>> CreateStreamEvaluator: PUBLIC PROC [clientProc: ReadEvalPrint.ClientProc, prompt: ROPE ¬ NIL, in, out: STREAM, deliverWhen: EditedStream.DeliverWhenProc ¬ NIL, clientData: REF ¬ NIL, topLevel: BOOL ¬ FALSE] RETURNS [h: Handle] = { h ¬ NEW[ReadEvalPrint.RObject ¬ []]; h.clientProc ¬ clientProc; IF deliverWhen = NIL THEN deliverWhen ¬ EditedStream.IsACR; h.deliverWhenProc ¬ deliverWhen; h.prompt ¬ prompt; h.in ¬ in; h.out ¬ out; h.clientData ¬ clientData; h.topLevel ¬ topLevel; }; Stop: PUBLIC PROC [h: Handle] = { <> h.terminateRequested ¬ TRUE; }; MainLoop: PUBLIC PROC [h: Handle, forkAndDetach: BOOL ¬ TRUE, properties: List.AList] = { inner: PROC = { MainLoopInternal[h]; }; IF forkAndDetach THEN TRUSTED { <> Process.Detach[FORK MainLoop[h, FALSE, properties]]; RETURN; }; <> properties ¬ CONS[List.DotCons[$StdIn, h.in], properties]; properties ¬ CONS[List.DotCons[$StdOut, h.out], properties]; properties ¬ CONS[List.DotCons[$ErrOut, h.out], properties]; ProcessProps.AddPropList[properties, inner]; }; MainLoopInternal: PROC [h: Handle] = { commandLine: ROPE ¬ NIL; result: ROPE ¬ NIL; rejectThisOne: BOOL ¬ FALSE; in: STREAM ¬ h.in; out: STREAM ¬ h.out; breakProc: IO.BreakProc = { IF h.deliverWhenProc[char, NIL, in, NIL].activate THEN RETURN [break] ELSE RETURN [other]; }; DoRead: PROC RETURNS [destroyed: BOOL ¬ FALSE] = { destroyed ¬ IO.EndOf[in ! RuntimeError.UNCAUGHT => {destroyed ¬ TRUE; CONTINUE}]; IF NOT destroyed THEN { IO.PutF[out, h.prompt, [rope["b"]], [rope["B"]] ]; IF h.promptProc # NIL THEN h.promptProc[h]; GetLine[ ! IO.EndOfStream => CONTINUE]; }; }; GetLine: PROC = { <> commandLine ¬ NIL; <> commandLine ¬ IO.GetTokenRope[in, breakProc].token; IF commandLine.Length[] # 0 THEN IF NOT h.deliverWhenProc[commandLine.Fetch[0], NIL, in, NIL].activate THEN commandLine ¬ Rope.Concat[commandLine, IO.GetTokenRope[in, breakProc].token]; }; TRUSTED {h.mainLoopProcess ¬ LOOPHOLE[Process.GetCurrent[], SAFE PROCESS]}; UNTIL h.terminateRequested DO aborted: BOOL ¬ FALSE; syntaxError: BOOL ¬ FALSE; rubout: BOOL ¬ FALSE; <> in ¬ h.in; out ¬ h.out; IF in = NIL OR out = NIL THEN RETURN; <> IF DoRead[ ! ABORTED => {aborted ¬ TRUE; CONTINUE}; IO.Error => { IF ec = StreamClosed THEN EXIT; WITH h.viewer SELECT FROM viewer: ViewerClasses.Viewer => IF viewer.destroyed THEN EXIT; ENDCASE => EXIT; IF ec = SyntaxError THEN {syntaxError ¬ TRUE; CONTINUE}; }; IO.EndOfStream => { WITH h.viewer SELECT FROM viewer: ViewerClasses.Viewer => IF viewer.destroyed THEN EXIT; ENDCASE => EXIT; IF stream = in THEN EXIT; }; IO.Rubout => {rubout ¬ TRUE; CONTINUE}; ] THEN EXIT; { <> ENABLE ABORTED => {aborted ¬ TRUE; GO TO out}; SELECT TRUE FROM rubout => { ENABLE RuntimeError.UNCAUGHT => GO TO out; IF h.ruboutProc # NIL THEN h.ruboutProc[h] ELSE { msg: ROPE ¬ " -- \n"; IF h.readIOSignalRope # NIL THEN msg ¬ h.readIOSignalRope; EatIt[in]; IO.PutRope[out, msg]; }; }; syntaxError => { ENABLE RuntimeError.UNCAUGHT => GO TO out; EatIt[in]; IO.PutRope[out, " -- Syntax error!\n"]; }; commandLine # NIL AND NOT aborted => { result ¬ h.clientProc[h, commandLine]; IF result # NIL THEN { IO.PutRope[out, result]; <> result ¬ NIL; IO.PutRope[out, "\n"]; }; }; ENDCASE => {}; EXITS out => {}; }; IF aborted THEN { msg: ROPE ¬ " -- Aborted.\n"; IF h.evalABORTEDRope # NIL THEN msg ¬ h.evalABORTEDRope; IO.PutRope[out, msg ! RuntimeError.UNCAUGHT => CONTINUE]; IO.Flush[out ! RuntimeError.UNCAUGHT => CONTINUE]; EatIt[in ! ABORTED => CONTINUE]; IF NOT h.topLevel THEN { IF in # NIL THEN IO.Close[in ! RuntimeError.UNCAUGHT => CONTINUE; IO.Error => CONTINUE]; EXIT; }; }; ENDLOOP; }; <> <<>> StopHit: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> h: Handle ¬ NARROW[clientData, Handle]; Process.Abort[h.mainLoopProcess ! Process.InvalidProcess => CONTINUE]; }; EatIt: PROC [st: STREAM] = { <> IF st # NIL THEN { ENABLE { IO.Error => GO TO done; IO.EndOfStream => GO TO done; RuntimeError.UNCAUGHT => GO TO done; }; IO.Reset[st]; WHILE IO.CharsAvail[st] > 0 DO [] ¬ IO.GetChar[st]; IO.Reset[st]; ENDLOOP; EXITS done => {}; }; }; ViewerEvent: ViewerEvents.EventProc = TRUSTED { SELECT event FROM destroy => { prop: REF ¬ ViewerOps.FetchProp[viewer, $ReadEvalPrint]; IF prop # NIL THEN Stop[NARROW[prop, Handle]]; }; ENDCASE; }; Init: PROC = { [] ¬ ViewerEvents.RegisterEventProc[proc: ViewerEvent, event: destroy, filter: $Typescript]; }; <> Init[]; END.