ReadEvalPrint.mesa
A comman read-eval-print loop for use with viewers. Original version by P. Rovner March 30, 1983 3:34 pm
Last Edited by L. Stewart, October 30, 1983 1:13 pm
Russ Atkinson, September 26, 1983 10:56 pm
Paul Rovner, November 29, 1983 8:41 am
This interface attempts to abstract some of the notion of a Read-Eval-Print loop. In particular, the common case of a viewer based Read-Eval-Print loop is fully supported.
DIRECTORY
EditedStream USING [DeliverWhenProc],
IO USING [STREAM],
List USING [AList],
MBQueue USING [Queue],
Rope USING [ROPE],
ViewerClasses USING [Viewer, ViewerRec];
ReadEvalPrint: CEDAR DEFINITIONS =
BEGIN
The major goal of this package is to provide the (rather complex) catch phrases needed to isolate mortal programmers from the many signals that can arise during user interaction. These catch phrases are hard to get right and it is hoped that those whose applications fit the read-eval-print model closely enough can use this package as is. Those with more complex requirements can use the implementation of this package as a starting point for modifications.
Handle: TYPE = REF RObject;
RObject:
TYPE =
MONITORED
RECORD [
viewer: ViewerClasses.Viewer ← NIL,
in: IO.STREAM ← NIL,
out: IO.STREAM ← NIL,
menuHitQueue: MBQueue.Queue,
terminateRequested: BOOL ← FALSE,
mainLoopProcess: PROCESS ← NIL,
clientProc: ClientProc ← NIL,
deliverWhenProc: EditedStream.DeliverWhenProc ← NIL,
prompt: Rope.ROPE ← NIL,
promptProc: PROC [Handle] ← NIL,
topLevel: BOOL ← TRUE,
clientData: REF ANY ← NIL,
ruboutProc: PROC [Handle] ← NIL,
readABORTEDRope: Rope.ROPE ← NIL, -- " aborted\n"
readIOSignalRope: Rope.ROPE ← NIL, -- " XXX\n"
evalABORTEDRope: Rope.ROPE ← NIL, -- " ...Aborted\n"
evalUNWINDRope: Rope.ROPE ← NIL -- " ...Unwound\n"
];
Advanced features:
topLevel = FALSE disables the catch phrases during the Eval and print parts of the loop. If ReadEvalPrint is used for nested command files, generally only the top level should be protected by these catch phrases.
menuHitQueue is used to serialize any mouse actions on buttons in the caption area of the viewer (if the viewer exists). The package provides only a STOP button, whose only action is to Process.Abort[h.mainLoopProcess]. The client may wish to add more buttons for other functions. Look at the ReadEvalPrintImpl to see how to do this.
If a promptProc is specified, it will be called right after the prompt rope is printed.
If a ruboutPrompt is specified, it will be called if ViewerIO.Rubout is raised during the read phase.
If any of the 'read' or 'eval' ropes are not NIL, then they will be used when the given signals are caught during the read or eval phases. All of these ropes are printed using IO.PutF, so the client may register PFStarCodeProcs.
ClientProc:
TYPE =
PROC [h: Handle, command: Rope.
ROPE]
RETURNS [result: Rope.
ROPE ←
NIL];
The ClientProc is expected to implement the Eval and Print parts of the read-eval-print loop. The ClientProc will be called with each "line" of input (as defined by the DeliverWhenProc, see below). Inside the ClientProc, the client can make arbitrary use of the streams h.in and h.out and may change the prompt and clientData fields of the handle. The package's call to ClientProc is protected only by catch phrases for ABORTED and UNWIND (and only if topLevel is FALSE). Thus other signals raised by ClientProc will go through to the debugger (or to catch phrases in the caller of MainLoop - see below).
CreateViewerEvaluator:
PROC [clientProc: ClientProc, prompt: Rope.
ROPE ←
NIL, info: ViewerClasses.ViewerRec ← [], edited:
BOOL ←
TRUE, deliverWhen: EditedStream.DeliverWhenProc ←
NIL, clientData:
REF
ANY ←
NIL, topLevel:
BOOL ←
TRUE]
RETURNS [Handle];
A viewer of the specified sort is created and edited (or not) IO streams are attached to it. If deliverWhen is non-NIL, it is used to identify input break characters, i.e. to determine when to deliver an input "line" to clientProc. The character for which deliverWhen returns TRUE will appear as the last character in the "line". Also see comments for CreateStreamEvaluator.
CreateStreamEvaluator:
PROC [clientProc: ClientProc, prompt: Rope.
ROPE ←
NIL, in, out:
IO.
STREAM, deliverWhen: EditedStream.DeliverWhenProc ←
NIL, clientData:
REF
ANY ←
NIL, topLevel:
BOOL ←
FALSE]
RETURNS [Handle];
Creates a Read-Eval-Print loop using the given STREAMs. Otherwise, the evaluator created is like the one above. In this case, Handle.viewer will be NIL. If the client wants an edited stream, it is the client's responsibility to provide one. If deliverWhen is NIL, ViewerIO.IsACR is used. If deliverWhen is not NIL, the reader will activate when deliverWhen[char] = TRUE; char will be the last one on the line that is passed to clientProc. As above, the loop will stop if in.Endof[] = TRUE. The prompt rope is printed using IO.PutF, so PFStarCodeProcs may be used, but the character '% must be handled specially
MainLoop:
PROC [h: Handle, forkAndDetach:
BOOL ←
TRUE, properties: List.AList];
This procedure is the main loop of the read-eval-print. The main loop is fully protected against signals and errors arising during the Read phase, but only against ABORTED and UNWIND during the eval and print phases. The evaluator will stop when Stop is called (see below), or when the input stream reports EOF. A client may wish to protect the call to MainLoop by catch phrases in order to protect calls to ClientProc from signals other than ABORTED and UNWIND. MainLoop may be called recursivly from a ClientProc. If forkAndDetach = TRUE, then the call to MainLoop will return almost right away. IF properties # NIL THEN the new process will be called with them as the process properties list.
Stop:
PROC [h: Handle];
Cause a Read-Eval-Print loop to shut down. clientProc will not be called again, the MainLoop process will disappear, but the viewer (if any) will not be destroyed and the streams will not be closed. Stop may be called either from inside the ClientProc or from the debugger (if the client called MainLoop directly, rather than by using CreateViewerEvaluator, then a Client catch phrase above MainLoop may call Stop.)
END.