JunoProcViewerImpl.mesa (ex OldParseWindowImpl.mesa)
Coded September 6, 1982 12:26 am
Last Edited by: Gnelson, January 17, 1984 11:56 am
Last Edited by: Stolfi June 13, 1984 11:17:30 am PDT

Maintains a text viewer containing the current set of Juno procedures. Exports procedures that search this list and that append new procedures to it.

The viewer has two extra menu buttons:
Parse: parses the viewer contents, saves the result as the "current global alist",unparses it, and stuffs the unparsed text back into the viewer.
NewProc: Appends a new node to the viewer, with the skeleton of a procedure declaration (to be edited by the user).
NewProc: Appends a new node to the viewer, with the skeleton of a procedure declaration (to be edited by the user).

TO FIX: Everything.

DIRECTORY

JunoProcViewer,
Rope USING [ROPE, Length, Equal],
ViewerClasses USING [Viewer],
ViewerOps USING [CreateViewer, DestroyViewer],
TiogaOps USING
[Ref, CallWithLocks, ViewerDoc, LastWithin, SelectNodes, Break, UnNest,
InsertRope, Nest, SelectBranches, Location, FirstChild, SelectPoint, SetSelection,
AddLooks, GetRope, GoToNextCharacter, Next];

JunoProcViewerImpl: CEDAR PROGRAM

IMPORTS

Rope,
ViewerOps,
TiogaOps

EXPORTS

JunoProcViewer =

BEGIN

OPEN

Rope,
JunoProcViewer;

- - - - PUBLIC PROCEDURES

TiogaNode: TYPE = TiogaOps.Ref;

NewViewer: PUBLIC PROC RETURNS [viewer: Viewer] =

BEGIN

viewer ← ViewerOps.CreateViewer

[flavor: $Text,
info: [column: right,
iconic: FALSE],
paint: TRUE];

-- !! register tioga procs to detect when the contents is edited

END;

DoInsertText: PROC
[viewer: Viewer, n: TiogaNode, text1, text2: ROPE, errBeg, errEnd: INT ← -1] =

To be called through TiogaOps.CallWithLocks. Inserts text1, text2, (and error flag, if errBeg >= 0) at current selection (which should include all of the level

{TiogaOps.SelectBranches
[viewer: viewer, start: n, end: n, level: char, pendingDelete: TRUE];
TiogaOps.InsertRope[text1];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.InsertRope[text2];
IF errBeg >= 0 THEN
{m: TiogaNode ← TiogaOps.FirstChild[n];
nLen: INT = text1.Length;
Loc: PROC [pos: INT] RETURNS [TiogaOps.Location] =
{RETURN[IF pos < nLen THEN [n, pos] ELSE [m, pos-nLen]]};
locBeg: TiogaOps.Location = Loc[errBeg];
TiogaOps.SelectPoint[viewer, Loc[errEnd]];
TiogaOps.InsertRope["\n"];
TiogaOps.SelectPoint[viewer, locBeg];
TiogaOps.InsertRope["\nERROR: "];
TiogaOps.SetSelection[viewer,
[locBeg.node, locBeg.where+1], [locBeg.node, locBeg.where+5]];
TiogaOps.AddLooks[looks: "b"]}};

ParseViewer: PUBLIC PROC [viewer: Viewer, Proc: BranchVisitProc]
RETURNS [nerrors: INTEGER] =
Parses the contents of the viewer and rebuilds AList. Resets the notParsed flag.
To be called by the top level program before refreshing the image

BEGIN

DoParseViewer: PROC [root: TiogaNode] =

{n: TiogaNode ← TiogaOps.FirstChild[root];
nok: INT ← 0; -- number of correct nodes
firstError: TiogaOps.Location;
nerrors ← 0;
IF viewer.destroyed THEN RETURN;
-- Should test whether the viewer has been edited since last call
WHILE n # NIL DO
m: TiogaNode = TiogaOps.FirstChild[n];
text1: ROPE = TiogaOps.GetRope[n];
text2: ROPE = TiogaOps.GetRope[m];
new1, new2: ROPE;
errBeg, errEnd: INT;
TRUSTED {[new1, new2, errBeg, errEnd] ← Proc[text1, text2]};
IF NOT Rope.Equal[text1, new1]
OR NOT Rope.Equal[text2, new2]
OR errBeg >= 0 THEN
{DoInsertText[viewer, n, new1, new2, errBeg, errEnd]};
IF errBeg >=0 THEN
{nerrors ← nerrors+1;
IF nerrors = 1 THEN firstError ← [n, errBeg];
IF nerrors > 10 AND nerrors > nok/5 THEN
{TiogaOps.SelectPoint[viewer: viewer, caret: [firstError.node, 0]];
TiogaOps.GoToNextCharacter[firstError.where];
RETURN};
n ← TiogaOps.Next[n]};
ENDLOOP};

TiogaOps.CallWithLocks[DoParseViewer, TiogaOps.ViewerDoc[viewer]]

END;

AddBranch: PUBLIC PROC [viewer: Viewer, text1, text2: ROPE] =
Adds a new branch (with one nested child) at the end of the viewer.

BEGIN

DoAddText: SAFE PROC[root: TiogaOps.Ref] = CHECKED

{nd: TiogaOps.Ref;
IF viewer.destroyed THEN RETURN;
nd ← TiogaOps.LastWithin[TiogaOps.ViewerDoc[viewer]];
TiogaOps.SelectNodes[viewer: viewer,
start: nd, end: nd, level: node, caretBefore: FALSE];
TiogaOps.Break[];
TiogaOps.UnNest[];
DoInsertText[viewer, nd, text1, text2]};

TiogaOps.CallWithLocks[DoAddText, TiogaOps.ViewerDoc[viewer]]

END;

CondDestroyViewer: PROC [viewer: Viewer] =
Destroys a viewer if contents is safe.

{-- Maybe we should we lock the viewer before testing newVersion
IF NOT viewer.newVersion THEN ViewerOps.DestroyViewer[viewer]};

END.

- - - - JUNK

PN2: PROC [n: TiogaNode, pw: Handle]
RETURNS [success: BOOL, tree: REF ANY, text1: ROPE, text2: ROPE] =

{r: Rope.ROPE;
vc: VerdictAndCulprit;
errorMessage: ROPENIL;
text1 ← TiogaOps.GetRope[n];
text2 ← TiogaOps.GetRope[TiogaOps.FirstChild[n]];
-- next three lines try to skip parsing if old parsed result is present in pw.contents:
{ l: LIST OF NodeContent ← pw.content
; WHILE l # NIL
AND NOT(Rope.Equal[l.first.text1, text1] AND Rope.Equal[l.first.text2, text2])
DO l ← l.rest ENDLOOP
; IF l # NIL THEN { success ← TRUE ; tree ← l.first.tree ; text1 ← l.first.text1; text2 ← l.first.text2 ; RETURN } };
IF ~ pw.contentValid THEN RETURN;
pw.ph.in.in ← IO.RIS[Rope.Cat[text1, text2, " "]];
pw.ph.in.eof ← FALSE;
pw.ph.in.error ← NIL;
pw.ph.in.Lex[];
IF pw.ph.in.eof THEN {success ← TRUE; tree ← text1 ← text2 ← NIL; RETURN};
pw.ph.Parse[];
pw.ph.result ← tree ← CONS[pw.ph.result, NIL];
-- necessary because WellFormed and Unparse work on the CAR of their argument
-- and ignore the cdr.
IF pw.ph.error = NIL AND pw.ph.eof
THEN {vc ← pw.WellFormed[pw.ph.result];
IF vc.verdict # Yes
THEN errorMessage ← "Not a WFF"
ELSE {vc.culprit ← NIL; errorMessage ← NIL}}
ELSE {vc.culprit ← NIL;
errorMessage ← IF pw.ph.error # NIL THEN pw.ph.error ELSE "Bad Syntax"};

r ← Unparser.Unparse[pw.ph.result, vc.culprit, 57, pw.ph.table, pw.ph.openCount];
--! change "57" to "width of window"
tree ← NARROW[pw.ph.result, LIST OF REF ANY].first;
IF pw.ph.error # NIL OR ~pw.ph.eof
THEN {r ← Rope.Cat[r, " \000", Rope.FromRefText[pw.ph.in.buf], "\000"];
WHILE ~ IO.EndOf[pw.ph.in.in]
DO r ← Rope.Cat[r, Rope.FromChar[IO.GetChar[pw.ph.in.in]]]
ENDLOOP};
{i: INT ← r.SkipTo[0, "\000"];
j: INT;
endOfHeader: INT = r.SkipTo[0, "\n"];
firstLine: Rope.ROPE = r.Substr[0, endOfHeader];
restOfLines: Rope.ROPE =
IF endOfHeader = r.Length THEN NIL ELSE r.Substr[endOfHeader + 1];
Foo: SAFE PROC[root: TiogaOps.Ref] = TRUSTED
{m: TiogaNode = IF TiogaOps.FirstChild[n] = NIL THEN n ELSE TiogaOps.FirstChild[n];
TiogaOps.SelectNodes[viewer: pw.viewer, start:n, end:m, pendingDelete: TRUE, level:char];
IF i = r.Length[]
THEN {TiogaOps.InsertRope[firstLine];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.InsertRope[restOfLines]}
ELSE {j ← r.SkipTo[i + 1, "\000"];
TiogaOps.InsertRope[Rope.Cat[r.Substr[0, i], r.Substr[i+1, j - i - 1], r.Substr[j+1]]];
TiogaOps.SetSelection[pw.viewer, [n, i], [n, j - 1]]}};
TiogaOps.CallWithLocks[Foo, TiogaOps.ViewerDoc[pw.viewer]];
success ← (errorMessage = NIL);
text1 ← firstLine;
text2 ← restOfLines}};