JunoUnparserImpl.mesa (was OldUnparserImpl.mesa)
Last Edited by: Gnelson, November 2, 1983 11:59 am
Last edited by GNelson January 17, 1984 11:33 am
Last edited by Stolfi June 15, 1984 8:04:10 am PDT

For unparsing, the operators fall into the following classes:

infixA: Infix ops preceded by their breakpoint with offset zero: -> := cong para

infixB. Infix ops preceded by their breakpoints with negative offsets: // | and

matchA. Matchfix ops with space-padded arguments: if do

infixC. Infix ops followed by their breakpoint with zero offset: , ; :

prefix. Prefix ops: hor, ver, cc, draw, ex

matchB. Matchfix ops with un-space-padded arguments that are also Subfix ops with un-space-padded arguments: (

infixD. Infix ops preceded by their breakpoints with negative offsets, but with no space before them: , and ;

infixE. ???

DIRECTORY

Rope USING [ROPE, Length],
StructuredStreams USING [Create, Begin, End, Bp],
List,
Atom,
JunoParseUnparse,
IO USING[PutF, PutRope, PutChar, ROS, RopeFromROS,
Put, atom, real, int, STREAM, CR];

JunoUnparserImpl: PROGRAM

IMPORTS

StructuredStreams, Atom, IO, JunoParseUnparse, Rope

EXPORTS

JunoParseUnparse =

BEGIN OPEN Str: StructuredStreams, JunoParseUnparse, Rope;

Unparse: PUBLIC PROC
[expr: LIST OF Se,
table: Table,
culprit: Se ← NIL,
openCount: INTEGER𡤀,
leftMargin: INTEGER ← 0, rightMargin: INTEGER ← 69]
RETURNS [ROPE] =

BEGIN

ros: IO.STREAMIO.ROS[];
stream: IO.STREAM ← Str.Create[onTopOf: ros, margin: rightMargin];

Unp: PROC [ex, uncle: LIST OF Se, opn: INTEGER] =

BEGIN

IF ex = culprit THEN stream.PutChar[0C];
WITH ex.first SELECT FROM
fi: REF INT => stream.PutF["%g1", IO.int[fi^]];
fx: REF REAL => stream.PutF["%g1.5", IO.real[fx^]];
fa: ATOM => stream.Put [IO.atom[fa]];
fr: Rope.ROPE => {stream.PutChar['"]; stream.PutRope[fr]; stream.PutChar['"]};
fl: LIST OF REF ANY => UnpList[fl, uncle, opn];
ENDCASE => NULL;
IF ex = culprit THEN stream.PutChar[0C]

END;

UnpList: PROC [lst, uncle: LIST OF Se, opn: INTEGER] =

BEGIN

op: ATOM = NARROW[lst.first];
arg1: LIST OF Se = lst.rest;
arg2: LIST OF Se = lst.rest.rest;
opProps: REF Props = GetAtomProps[op, table].rp;
type: UnparseType ← opProps.unparseType;

SELECT TRUE FROM

type = infixA AND arg2 # NIL
=> {Str.Begin[stream];
Unp[arg1, NIL, 0];
stream.PutChar[' ];
Str.Bp[stream, TRUE, 0];
Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg2, NIL, opn];
Str.End[stream]};

type = infixC AND arg2 # NIL
=> {IF uncle = NIL OR op # uncle.first THEN Str.Begin[stream];
Unp[arg1, NIL, 0];
Unp[lst, NIL, 0];
Str.Bp[stream, FALSE, -1];
stream.PutChar[' ];
Unp[arg2, lst, opn];
IF uncle = NIL OR op # uncle.first THEN Str.End[stream]};

type = matchB AND arg2 = NIL
=> {Unp[lst, NIL, 0];
Unp[arg1, NIL, opn - 1];
IF opn <= 0 THEN stream.Put[IO.atom[opProps.closer]]};

type = matchB AND arg2 # NIL
=> {Str.Begin[stream];
Unp[arg1, NIL, 0];
Str.Bp[stream, TRUE, - 1 - Length[Atom.GetPName [op]]];
Unp[lst, NIL, 0];
Unp[arg2, NIL, opn - 1];
IF opn <= 0 THEN stream.Put[IO.atom[opProps.closer]];
Str.End[stream]};

type = infixD AND arg2 # NIL
=> {IF uncle = NIL OR op # uncle.first THEN Str.Begin[stream];
Unp[arg1, NIL, 0];
Str.Bp[stream, TRUE, - 1 - Length[Atom.GetPName [op]]];
Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg2, lst, opn];
IF uncle = NIL OR op # uncle.first THEN Str.End[stream]};

type = infixE AND arg2 # NIL
=> {Str.Begin[stream];
Unp[arg1, NIL, 0];
stream.PutChar[' ];
Unp[lst, NIL, 0];
stream.PutChar[' ];
Str.Bp[stream, FALSE, 0];
Unp[arg2, lst, opn];
Str.End[stream]};

opProps.infix AND arg2 # NIL
=> {IF uncle = NIL OR op # uncle.first THEN Str.Begin[stream];
Unp[arg1, NIL, 0];
Str.Bp[stream, TRUE, - 2 - Length[Atom.GetPName [op]]];
stream.PutChar[' ];
Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg2, lst, opn];
IF uncle = NIL OR op # uncle.first THEN Str.End[stream]};

opProps.matchfix AND arg2 = NIL
=> {Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg1, NIL, opn - 1];
IF opn <= 0 THEN
{stream.PutChar[' ]; stream.Put[IO.atom[opProps.closer]]}};

opProps.prefix AND arg2 = NIL
=> {Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg1, NIL, opn]};

opProps.postfix AND arg2 = NIL
=> {Unp[arg1, NIL, opn];
stream.PutChar[' ];
Unp[lst, NIL, 0]};

opProps.subfix AND arg2 # NIL
=> {Str.Begin[stream];
Unp[arg1, NIL, 0];
stream.PutChar[' ];
Str.Bp[stream, TRUE, - 2 - Length[Atom.GetPName [op]]];
Unp[lst, NIL, 0];
stream.PutChar[' ];
Unp[arg2, NIL, opn - 1];
stream.PutChar[' ];
IF opn <= 0 THEN stream.Put[IO.atom[opProps.closer]];
Str.End[stream]};

opProps.busfix AND arg2 # NIL
=> {Unp[lst, NIL, 0];
Str.Begin[stream];
stream.PutChar[' ];
Unp[arg1, NIL, 0];
stream.PutChar[' ];
Str.Bp[stream, TRUE, - Length[Atom.GetPName [opProps.closer]]];
stream.Put[IO.atom[opProps.closer]];
stream.PutChar[' ];
Unp[arg2, NIL, opn];
Str.End[stream]};

ENDCASE => ERROR Error

END;

stream.PutRope[" "]; -- indent two spaces
Unp[expr, NIL, openCount ! Error => CONTINUE];
stream.PutChar[IO.CR];
RETURN [IO.RopeFromROS[ros]]

END;

Error: ERROR = CODE;

END.