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
}