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
}