DIRECTORY Atom, IO, Rope, TiogaAccess, UnparserBuffer; UnparserBufferImpl: CEDAR PROGRAM IMPORTS Atom, IO, Rope, TiogaAccess EXPORTS UnparserBuffer = BEGIN OPEN UnparserBuffer; 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; 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: BOOL _ TRUE; 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. ZUnparserBufferImpl.mesa Gnelson, December 6, 1983 2:05 am Spreitzer, February 24, 1986 4:32:12 pm PST 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. now do a setb Κ ˜codešœ™Kšœ!™!K™+—K˜KšΟk œœ%˜7K˜šΠbxœœ˜!Kšœœ˜#Kšœ˜Kšœœœ˜K˜Kšœ'™'K˜Kšœ?™?K˜Kšœ.™.K˜Kšœ8™8K™Mšœ4™4Kšœ#™#Kšœ2™2Kšœ4™4Kšœ3™3—Kšœ7™7K˜Kšœ=™=Kšœ;™;KšœE™EKšœ>™>KšœF™FKšœ ™ K˜Kšœ™K˜Kšœ™K˜Kšœ™K˜Kšœ™K˜Kšœ/™/K™™K™‰—K˜š Οn œœœ œœ ˜Vš œ œ'œœœ˜UKšœ˜ —K˜—šŸœœœ˜˜NKšœ ™ K˜ ˜ K˜———š Ÿœœœœœ˜3Kš œœ œœœœ ˜3—K˜š Ÿœœœœœ˜2š œœœœ œœ ˜3K˜——šŸœœœ ˜šœœ˜Kšœ œ˜šœ˜K˜ KšœœœΟc˜1—šœœ ˜#K˜Kšœ œœ  ˜9———K˜šŸœœœ ˜šœœ˜Kšœ œ˜/Kšœœ˜Kšœ ˜ Kšœ˜šœœ ˜Kšœœ˜Kšœ˜ Kšœœ ˜(šœœ œ˜%K˜————˜šŸ œœ˜šœœ˜šœ œ˜Kšœ˜š œœ œœœ'˜BKšœ˜—Kšœ˜šœœ œœ*˜Bšœ˜Kšœ ˜ K˜ Kšœ˜Kšœ œ˜Kšœ œ˜K˜ K˜——Kšœœ˜—K˜)K˜)K˜Kšœ œ ˜Kšœ#œ˜-—K˜—šŸ œœœ˜1šœœ˜šœ œ˜Kšœœ&˜CKšœC˜CKšœœ˜———K˜šŸ œœ&œœ˜_šœ ˜ šœœœ˜&Kšœœ˜šœœ˜&Kšœ˜Kšœ ˜"Kšœœ˜Kšœœ˜—šœœ˜Kšœœœ˜Kšœœ˜Kšœœ˜—Kšœ˜ ——K˜——š Ÿœœœœ œ˜;šœœ˜K˜)K˜Kšœ œœ  ˜7K˜ K˜——šŸœœœœ˜3šœœ˜šœœ˜Kšœ!˜!Kšœ)˜0———K˜šŸœœœœ˜*šœœ˜K˜ K˜Kšœ œœ ˜-Kšœ œ˜ K˜&K˜ —K˜šŸœœœœ˜-šœœœœ˜$Kšœœ˜'——K˜KšŸœœœœ!˜FK˜šŸœœ˜šœœ˜Kšœœœ˜˜Kšœœ œ"˜9K˜Kšœœ œœ˜;˜K˜ Kšœœœ ˜-K˜—K˜Kšœœ œœ˜AKšœ œœ$˜EK˜EK˜Kšœœ œœ˜AKšœœ˜5Kšœœœœ˜-K˜—K˜Kšœœœ˜—šœœœ˜K˜—šŸ œœœ˜-šœ œ ˜šœ œ˜Kšœ˜šœœœœ˜!š œœœœœ ˜=Kšœœ˜(Kšœ œœœ˜>Kšœ*˜*Kšœ˜—K˜—Kšœ˜˜Kšœ œœ#˜<˜K˜ Kšœœœ˜Kšœœœ˜Kšœ˜Kšœ œ˜Kšœ œ˜Kšœ˜K˜—Kšœ˜Kšœ)˜)š œœœœœ ˜=Kšœœ˜(šœ ˜˜K˜ Kšœ˜Kšœ˜Kšœœ˜ Kšœ œ˜Kšœ œ˜Kšœ ˜ K˜—Kšœ˜—Kšœ*˜*Kšœ˜—K˜—Kšœœ˜—Kšœ˜K˜————šŸœœœœ˜4šœœ ˜Kšœœ ˜K˜K˜ ˜K˜———Kšœ˜——…—Š#