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 extends 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 extends FmtResult { success(): bool = true pos_: int pos(): int = pos_ } succeeded(p: int): Success = { ret: Success = (new Success); ret.pos_ = p; ret; } class Failure extends 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, pos, rmargin, canBreak); } class Block extends 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, pos+indent, pos, rmargin, true); if (ret.success()) return ret; if (!canBreak) failure; else tryFormat(first, pos+indent, pos, rmargin, true); } sendOutput(o: OutputStream, lmargin, pos: int): int = { it: Item = first; lmargin = pos + indent; while (it) { pos = it.sendOutput(o, lmargin, pos); it = it.next(); } pos; } } class StringItem extends 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 extends Item { next_: Item; init(n: int): AllowBreak = { indent = n; 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 failure; } 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 extends 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 }