UnparserBufferImpl.mesa
Gnelson, December 6, 1983 2:05 am
Spreitzer, February 24, 1986 4:32:12 pm PST
DIRECTORY Atom, IO, Rope, TiogaAccess, UnparserBuffer;
UnparserBufferImpl: CEDAR PROGRAM
IMPORTS Atom, IO, Rope, TiogaAccess
EXPORTS UnparserBuffer
= BEGIN OPEN UnparserBuffer;
The comments here apply to any handle.
n : INT = 256; both queues and the stack will have n elements
bl, cl, br, cr, sr, srx: INTEGER; in [0, n).
c: ARRAY [0 .. n) OF CHAR; a queue with pointers cl, cr
dl: ARRAY [0 .. n) OF ROPE; dl[i] is the looks change between c[i-1] and c[i]
b: ARRAY [0 .. n) OF a queue with pointers bl, br
RECORD [type: {setb, breakpoint},
united: BOOL, relevant only if type = breakpoint
offset: INTEGER, relevant only if type = breakpoint
p: [0 .. n)]; index in c of following buffer char
s: ARRAY [0 .. n) OF INTEGER; a stack with pointer sr
The indentations of the setbs that have been removed from the
buffer but whose matching endbs have not yet been processed
are stored in s[0], s[1], ... s[sr-1]. Furthermore, for i < srx, the
setb whose indentation is stored in s[i] has been broken; for
srx <= i < sr, s[i] is the indentation of a setb on the "current line"
that may or may not be broken.
indentation: INTEGER;
margin: PUBLIC INTEGER;
bufferWidth: INTEGER;
output: PUBLIC BufferOutput;
Width: PUBLIC PROC [c: CHAR] RETURNS [INTEGER];
depth: INTEGER;
Used only when output is a TiogaAccess.Writer; this tracks the depth of the current node in the Writer. 0 corresponds to no indentation.
NewHandle: PUBLIC PROC [output: BufferOutput, margin: INTEGER ← 80] RETURNS [Handle] =
{h: Handle ← NEW[HandleRec ← [output: output, spacers: LIST[IO.SP], margin: margin]];
RETURN [h]};
Init: PUBLIC PROC [h: Handle] =
{h.bufferWidth ← h.bl ← h.cl ← h.br ← h.cr ← h.sr ← h.srx ← h.indentation ← 0;
now do a setb
h.s[0] ← 0;
h.sr ← 1};
Right: PROC [m: INTEGER] RETURNS [INTEGER] = INLINE
{IF m + 1 = n THEN RETURN [0] ELSE RETURN [m + 1]};
Left: PROC [m: INTEGER] RETURNS [INTEGER] = INLINE
{IF m = 0 THEN RETURN [n - 1] ELSE RETURN [m - 1]};
Setb: PUBLIC PROC[h: Handle] =
{OPEN h;
IF bl = br AND cl = cr
THEN {s[sr] ← indentation;
sr ← sr + 1;
IF sr = n THEN ERROR} -- Setb's too deeply nested
ELSE {b[br] ← [setb, FALSE, 0, cr];
br ← Right[br];
IF br = bl THEN ERROR}}; -- Too many active Setbs and Bps
Endb: PUBLIC PROC[h: Handle] =
{OPEN h;
WHILE bl # br AND b[Left[br]].type = breakpoint
DO br ← Left[br] ENDLOOP;
IF bl # br
THEN br ← Left[br]
ELSE {WHILE cl # cr
DO OutputChar[h] ENDLOOP;
IF sr = 0
THEN ERROR -- Endb with no matching Setb
ELSE {IF srx = sr THEN srx ← srx - 1;
sr ← sr - 1}}};
OutputChar: PROC [h: Handle] =
{OPEN h;
WITH h.output SELECT FROM
so: BufferOutput.stream
=> {IF dl[cl] # NIL THEN IO.PutF[so.stream, "%l", [rope[dl[cl]]]];
IO.PutChar[so.stream, c[cl]]};
ao: BufferOutput.access
=> {IF dl[cl] # NIL THEN curLooks ← ChangeLooks[curLooks, dl[cl]];
TiogaAccess.Put[ao.access, [
charSet: 0,
char: c[cl],
looks: curLooks,
comment: FALSE,
endOfNode: FALSE,
deltaLevel: 0
]]};
ENDCASE => ERROR;
indentation ← indentation + width[c[cl]];
bufferWidth ← bufferWidth - width[c[cl]];
cl ← Right[cl];
IF cl = cr AND dl[cr] # NIL
THEN {OutputLooks[h, dl[cr]]; dl[cr] ← NIL}};
OutputLooks: PROC [h: Handle, looks: Rope.ROPE] =
{OPEN h;
WITH h.output SELECT FROM
so: BufferOutput.stream => IO.PutF[so.stream, "%l", [rope[looks]]];
ao: BufferOutput.access => curLooks ← ChangeLooks[curLooks, looks];
ENDCASE => ERROR};
ChangeLooks: PROC [old: TiogaAccess.Looks, delta: Rope.ROPE] RETURNS [new: TiogaAccess.Looks] =
{new ← old;
FOR i: INT IN [0 .. delta.Length[]) DO
c: CHAR = delta.Fetch[i];
look: TiogaAccess.Look = SELECT c FROM
IN ['a .. 'a + 32) => c,
IN ['A .. 'A + 32) => c - 'A + 'a,
' => FIRST[TiogaAccess.Look],
ENDCASE => ERROR;
SELECT TRUE FROM
c = ' => new ← ALL[FALSE];
c = look => new[look] ← TRUE;
ENDCASE => new[look] ← FALSE;
ENDLOOP};
Bp: PUBLIC PROC[h: Handle, united: BOOL, offset: INTEGER] =
{OPEN h;
b[br] ← [breakpoint, united, offset, cr];
br ← Right[br];
IF br = bl THEN ERROR; -- Too many active Setbs and Bps
LeftLoop[h]};
Looksb: PUBLIC PROC [h: Handle, looks: Rope.ROPE] =
{OPEN h;
SELECT TRUE FROM
cl = cr => OutputLooks[h, looks];
ENDCASE => dl[cr] ← Rope.Concat[dl[cr], looks]};
Charb: PUBLIC PROC [h: Handle, ch: CHAR] =
{OPEN h;
c[cr] ← ch;
cr ← Right[cr];
IF cr = cl THEN ERROR; -- Too many characters
dl[cr] ← NIL;
bufferWidth ← bufferWidth + width[ch];
LeftLoop[h]};
Ropeb: PUBLIC PROC[h: Handle, r: Rope.ROPE] =
{FOR i: INT IN [0 .. Rope.Length[r])
DO Charb[h, Rope.Fetch[r, i]] ENDLOOP};
Atomb: PUBLIC PROC[h: Handle, a: ATOM] = {Ropeb[h, Atom.GetPName[a]]};
LeftLoop: PROC[h: Handle] =
{OPEN h;
DO SELECT TRUE FROM
cl # cr AND (bl = br OR b[bl].p # cl) => OutputChar[h];
bl # br AND (cl = cr OR b[bl].p = cl) AND b[bl].type = setb
=> {s[sr] ← indentation;
sr ← sr + 1;
IF sr = n THEN ERROR; -- Too many nested Setb
bl ← Right[bl]};
bl # br AND (cl = cr OR b[bl].p = cl) AND b[bl].type = breakpoint
AND (srx = sr AND b[bl].united OR indentation + bufferWidth > margin)
=> {Breakline[h, s[sr-1] + b[bl].offset]; srx ← sr; bl ← Right[bl]}; 
bl # br AND (cl = cr OR b[bl].p = cl) AND b[bl].type = breakpoint
AND Right[bl] # br AND b[Right[bl]].type = breakpoint
AND ~ b[IF fix THEN bl ELSE Right[bl]].united
=> bl ← Right[bl]
ENDCASE => EXIT ENDLOOP};
fix: BOOLTRUE;
Breakline: PROC[h: Handle, indent: INTEGER] =
{goalIndent: INTEGER = indent;
WITH h.output SELECT FROM
so: BufferOutput.stream
=> {IO.PutChar[so.stream, IO.CR];
FOR sl: LIST OF CHAR ← h.spacers, sl.rest WHILE indent # 0 DO
rep: INTEGER ← indent/h.width[sl.first];
THROUGH [0 .. rep) DO IO.PutChar[so.stream, sl.first] ENDLOOP;
indent ← indent - rep * h.width[sl.first];
ENDLOOP;
};
ao: BufferOutput.access
=> {
deltaLevel: INTEGER = MIN[1, indent/ao.nestWidth - h.depth];
TiogaAccess.Put[ao.access, [
charSet: 0,
char: FIRST[CHAR],
looks: ALL[FALSE],
format: ao.format,
comment: FALSE,
endOfNode: TRUE,
deltaLevel: deltaLevel
]];
h.depth ← h.depth + deltaLevel;
indent ← indent - h.depth * ao.nestWidth;
FOR sl: LIST OF CHAR ← h.spacers, sl.rest WHILE indent # 0 DO
rep: INTEGER ← indent/h.width[sl.first];
THROUGH [0 .. rep) DO
TiogaAccess.Put[ao.access, [
charSet: 0,
char: sl.first,
looks: h.curLooks,
format: NIL,
comment: FALSE,
endOfNode: FALSE,
deltaLevel: 0
]];
ENDLOOP;
indent ← indent - rep * h.width[sl.first];
ENDLOOP;
};
ENDCASE => ERROR;
h.indentation ← goalIndent};
Newlineb: PUBLIC PROC[h: Handle, offset: INTEGER] =
{m: INTEGER = h.margin;
Bp[h, TRUE, offset];
h.margin ← -1;
LeftLoop[h];
h.margin ← m};
END.