PrettyPrinter.int:
// // Simple PrettyPrinter -- Andrew C. Myers, March 1999 // For use in Cornell University Computer Science 412/413 // uses io.OutputStream interface PrettyPrinter { // A pretty-printer formats text onto an // output stream "o" while keeping the width of the output // within "width" characters if possible write(s: string) // Print the string "s" on the output stream begin(indent: int) // Start a new block with indentation increased // by "n" characters end() // Terminate the most recent outstanding "begin" allowBreak(n: int) // Allow a newline. Indentation will be preserved. newline(n: int) // Force a newline. Indentation will be preserved. flush() // Send out the current batch of text // to be formatted, closing all // outstanding "begin"'s and resetting // the indentation level to 0. } createPrettyPrinter(o: OutputStream, width: int): PrettyPrinter // create a new PrettyPrinter that writes its output to the // underlying output stream "o".
PrettyPrinter.mod:
createPrettyPrinter(o: OutputStream, width: int): PrettyPrinter = (new Impl).init(o, width) class Impl implements PrettyPrinter { init(o: OutputStream, width_: int): Impl = ( output = o; width = width_; current = input = (new Block).init(null, 0); this ) write(s: string) = current.add((new StringItem).init(s)) begin(indent: int) = ( b: Block = (new Block).init(current, indent); current.add(b); current = b ) end() = ( current = current.parent ) allowBreak(n: int) = current.add((new AllowBreak).init(n)) newline(n: int) = current.add((new Newline).init(n)) flush() = ( input.format(0, 0, width, true); input.sendOutput(output, 0, 0); output.flush(); current = input = (new Block).init(null, 0) ) output: OutputStream width: int input, current: Block } interface Item { next(): Item setNext(it: Item) format(lmargin, pos, rmargin: int, canBreak: bool): FmtResult sendOutput(o: OutputStream, lmargin, pos: int): int } interface FmtResult { success(): bool pos(): int } class Success implements FmtResult { success(): bool = true pos_: int pos(): int = pos_ } succeeded(p: int): Success = ( ret: Success = new Success; ret.pos_ = p; ret ) class Failure implements FmtResult { success(): bool = false pos(): int = 0 } failure: Failure = new Failure tryFormat(i: Item, lmargin, pos, rmargin: int, canBreak: bool): FmtResult = ( if (pos > rmargin) return failure; ret: FmtResult = i.format(lmargin, pos, rmargin, canBreak); if (!ret.success() | !i.next()) return ret; tryFormat(i.next(), lmargin, ret.pos(), rmargin, canBreak) ) class Block implements Item { parent: Block first, last: Item indent: int next_: Item next(): Item = next_ setNext(it: Item) = (next_ = it) init(parent_: Block, indent_: int): Block = ( parent = parent_; first = last = null; indent = indent_; this ) add(it: Item) = ( if (first == null) first = it else last.setNext(it); last = it ) format(lmargin, pos, rmargin: int, canBreak: bool): FmtResult = ( if (!first) return succeeded(pos); ret: FmtResult = tryFormat(first, lmargin+indent, pos, rmargin, false); if (ret.success()) return ret; if (!canBreak) failure else tryFormat(first, lmargin+indent, pos, rmargin, true) ) sendOutput(o: OutputStream, lmargin, pos: int): int = ( it: Item = first; lmargin = lmargin + indent; while (it) ( pos = it.sendOutput(o, lmargin, pos); it = it.next() ); pos ) } class StringItem implements Item { next_: Item init(s_: string): StringItem = ( s = s_; this ) next(): Item = next_ setNext(it: Item) = (next_ = it) format(lmargin, pos, rmargin: int, canBreak: bool): FmtResult = ( pos = pos + length s; if (pos > rmargin) failure else succeeded(pos) ) sendOutput(o: OutputStream, lmargin, pos: int): int = ( o.print(s); pos + length s; ) s: string } class AllowBreak implements Item { next_: Item init(n: int): AllowBreak = ( indent = n; broken = true; this ) next(): Item = next_ setNext(it: Item) = (next_ = it) format(lmargin, pos, rmargin: int, canBreak: bool): FmtResult = ( broken = canBreak; if (canBreak) succeeded(lmargin + indent) else succeeded(pos); ) sendOutput(o: OutputStream, lmargin, pos:int): int = ( if (broken) ( o.print("\N"); i: int = 0; while (i < lmargin) ( o.print(" "); i++ ); lmargin + indent ) else ( pos ) ) indent: int broken: bool } class Newline implements Item { next_: Item init(n: int): Newline = ( indent = n; this ) next(): Item = next_ setNext(it: Item) = (next_ = it) format(lmargin, pos, rmargin: int, canBreak: bool): FmtResult = ( if (canBreak) succeeded(lmargin+indent) else failure ) sendOutput(o: OutputStream, lmargin, pos:int): int = ( o.print("\N"); i: int = 0; while (i < lmargin) ( o.print(" "); i++ ); lmargin + indent ) indent: int }