-- September 6, 1982 12:26 am
-- ParseWindowImpl.mesa
-- Last Edited by: Gnelson, November 3, 1983 3:17 pm
DIRECTORY Atom, ParseWindow, ParseTable, ViewerClasses, Rope, TiogaOps, Parser, Lexer, IO, Unparser, ParserGen;
ParseWindowImpl: MONITOR
IMPORTS Rope, TiogaOps, Parser, Lexer, Unparser, IO, ParserGen
EXPORTS ParseWindow
= BEGIN OPEN ParseWindow;
ROPE: TYPE = Rope.ROPE;
NewHandle: PUBLIC PROC [v: ViewerClasses.Viewer]
RETURNS [h: Handle] =
{ h ← NEW[HandleRep]
; h.ph ← Parser.NewHandle[]
; h.ph.in ← Lexer.NewHandle[]
; h.viewer ← v
; h.content ← NIL
; h.contentValid ← FALSE};
GenerateParser: PUBLIC PROC [h: Handle] =
{l: Lexer.Handle;
ph: ParseTable.Handle;
o: ParserGen.OpList;
p: ParserGen.ProdList;
c: ParserGen.Culprit;
[l, ph, o, p, c] ← ParserGen.GenParser[h.grammerfilename];
h.productions ← p;
h.ph.table ← ph;
h.ph.in ← l};
TiogaNode: TYPE = TiogaOps.Ref;
NodeProc: TYPE = PROC [n: TiogaNode, pw: Handle]
RETURNS [keepgoing: BOOL];
NodeMap: PROC [ p: NodeProc, pw: Handle] RETURNS [didAllNodes: BOOL] =
{ --! should lock the selection & the document
root: TiogaNode ← TiogaOps.ViewerDoc[pw.viewer];
RETURN[NM2[p, TiogaOps.FirstChild[root], pw]]} ;
NM2: PROC [p: NodeProc, n: TiogaNode, pw: Handle]
RETURNS [didAllNodes: BOOL]
= {RETURN [n = NIL OR
(p[n, pw] AND NM2[p, TiogaOps.FirstChild[n], pw]
AND NM2[p, TiogaOps.Next[n], pw])]};
ParseViewer: PUBLIC PROC [pw: Handle] =
{newContent: LIST OF NodeContent ← NIL;
success: BOOL;
tree: REF;
text1: ROPE;
text2: ROPE;
n: TiogaNode ← TiogaOps.FirstChild[TiogaOps.ViewerDoc[pw.viewer]];
pw.contentValid ← TRUE;
WHILE n # NIL DO
[success, tree, text1, text2] ← PN2[n, pw];
IF success THEN newContent ← CONS[[text1, text2, tree], newContent];
n ← TiogaOps.Next[n];
ENDLOOP;
pw.content ← newContent};
PN2: PROC [n: TiogaNode, pw: Handle]
RETURNS [success: BOOL, tree: REF ANY, text1: ROPE, text2: ROPE]
=
{r: ROPE;
vc: ParserGen.VerdictAndCulprit;
errorMessage: ROPE ← NIL;
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 (l.first.text1 # text1 OR 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 IsGeneratedBy and Unparse work on the CAR of their argument
-- and ignore the cdr.
IF pw.ph.error = NIL AND pw.ph.eof
THEN {vc ← ParserGen.IsGeneratedBy[pw.productions, $S, 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, 60, pw.ph.table, pw.ph.openCount];
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}};
AddTree: PUBLIC PROC[pw: Handle, tree: REF]
= {r: ROPE ← Unparser.Unparse[LIST[tree], NIL, 60, pw.ph.table, 0];
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];
nd: TiogaNode ← TiogaOps.LastWithin[TiogaOps.ViewerDoc[pw.viewer]];
Foo: SAFE PROC[root: TiogaOps.Ref] = CHECKED
{TiogaOps.SelectNodes[pw.viewer, nd, nd, node, FALSE];
TiogaOps.Break[];
TiogaOps.UnNest[];
TiogaOps.InsertRope[firstLine];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.InsertRope[restOfLines]};
TiogaOps.CallWithLocks[Foo, TiogaOps.ViewerDoc[pw.viewer]];
pw.content ← CONS[[firstLine, restOfLines, tree], pw.content]};
AddText: PUBLIC PROC[pw: Handle, text1, text2: ROPE] =
{nd: TiogaNode ← TiogaOps.LastWithin[TiogaOps.ViewerDoc[pw.viewer]];
Foo: SAFE PROC[root: TiogaOps.Ref] = CHECKED
{TiogaOps.SelectNodes[pw.viewer, nd, nd, node, FALSE];
TiogaOps.Break[];
TiogaOps.UnNest[];
TiogaOps.InsertRope[text1];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.InsertRope[text2]};
TiogaOps.CallWithLocks[Foo, TiogaOps.ViewerDoc[pw.viewer]]};
END.