Files
rust/src/comp/pretty/pp.rs

208 lines
5.2 KiB
Rust
Raw Normal View History

import std.io;
import std._vec;
import std._str;
tag boxtype {box_h; box_v; box_hv; box_align;}
tag contexttype {cx_h; cx_v;}
tag token {
brk(uint);
word(str);
cword(str); // closing token
open(boxtype, uint);
close;
}
type context = rec(contexttype tp, uint indent);
type ps = @rec(mutable vec[context] context,
uint width,
mutable vec[token] buffered,
mutable uint scandepth,
mutable uint bufferedcol,
mutable uint col,
mutable bool start_of_line);
fn mkstate(uint width) -> ps {
let vec[context] stack = vec(rec(tp=cx_v, indent=0u));
let vec[token] buff = vec();
ret @rec(mutable context=stack,
width=width,
mutable buffered=buff,
mutable scandepth=0u,
mutable bufferedcol=0u,
mutable col=0u,
mutable start_of_line=true);
}
impure fn push_context(ps p, contexttype tp, uint indent) {
before_print(p, false);
p.context = _vec.push[context](p.context, rec(tp=tp, indent=base_indent(p)
+ indent));
}
impure fn pop_context(ps p) {
p.context = _vec.pop[context](p.context);
}
impure fn add_token(ps p, token tok) {
if (p.scandepth == 0u) {do_token(p, tok);}
else {buffer_token(p, tok);}
}
impure fn buffer_token(ps p, token tok) {
p.buffered += vec(tok);
p.bufferedcol += token_size(tok);
alt (p.buffered.(0)) {
case (brk(_)) {
alt (tok) {
case (brk(_)) {
if (p.scandepth == 1u) {finish_break_scan(p);}
}
case (open(box_h,_)) {p.scandepth += 1u;}
case (open(_,_)) {finish_break_scan(p);}
case (close) {
p.scandepth -= 1u;
if (p.scandepth == 0u) {finish_break_scan(p);}
}
case (_) {}
}
}
case (open(_,_)) {
if (p.bufferedcol > p.width) {finish_block_scan(p, cx_v);}
else {
alt (tok) {
case (open(_,_)) {p.scandepth += 1u;}
case (close) {
p.scandepth -= 1u;
if (p.scandepth == 0u) {finish_block_scan(p, cx_h);}
}
case (_) {}
}
}
}
}
}
impure fn finish_block_scan(ps p, contexttype tp) {
auto indent;
alt (p.buffered.(0)){
case (open(box_hv,?ind)) {
indent = ind;
}
case (open(box_align, _)) {
indent = p.col - base_indent(p);
}
}
p.scandepth = 0u;
push_context(p, tp, indent);
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
}
impure fn finish_break_scan(ps p) {
if (p.bufferedcol > p.width) {
write_str("\n");
p.col = 0u;
}
else {
auto width;
alt (p.buffered.(0)) {case(brk(?w)) {width = w;}}
auto i = 0u;
while (i < width) {write_str(" "); i+=1u;}
p.col += width;
}
p.scandepth = 0u;
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
}
impure fn start_scan(ps p, token tok) {
p.buffered = vec(tok);
p.scandepth = 1u;
p.bufferedcol = p.col;
}
fn cur_context(ps p) -> context {
ret p.context.(_vec.len[context](p.context)-1u);
}
fn base_indent(ps p) -> uint {
auto i = _vec.len[context](p.context);
while (i > 0u) {
i -= 1u;
auto cx = p.context.(i);
if (cx.tp == cx_v) {ret cx.indent;}
}
}
impure fn do_token(ps p, token tok) {
alt (tok) {
case (brk(?sz)) {
alt (cur_context(p).tp) {
case (cx_h) {
before_print(p, false);
start_scan(p, tok);
}
case (cx_v) {
write_str("\n");
p.col = 0u;
p.start_of_line = true;
}
}
}
case (word(?w)) {
before_print(p, false);
write_str(w);
p.col += _str.byte_len(w); // TODO char_len
}
case (cword(?w)) {
before_print(p, true);
write_str(w);
p.col += _str.byte_len(w); // TODO char_len
}
case (open(?tp, ?indent)) {
alt (tp) {
case (box_hv) {start_scan(p, tok);}
case (box_align) {start_scan(p, tok);}
case (box_h) {push_context(p, cx_h, indent);}
case (box_v) {push_context(p, cx_v, indent);}
}
}
case (close) {pop_context(p);}
}
}
impure fn before_print(ps p, bool closing) {
if (p.start_of_line) {
p.start_of_line = false;
auto ind;
if (closing) {ind = base_indent(p);}
else {ind = cur_context(p).indent;}
p.col = ind;
while (ind > 0u) {write_str(" "); ind -= 1u;}
}
}
fn write_str(str s) {
io.writefd(1, _str.bytes(s));
}
fn token_size(token tok) -> uint {
alt (tok) {
case (brk(?sz)) {ret sz;}
case (word(?w)) {ret _str.byte_len(w);}
case (cword(?w)) {ret _str.byte_len(w);}
case (open(_, _)) {ret 0u;} // TODO exception for V blocks?
case (close) {ret 0u;}
}
}
impure fn box(ps p, uint indent) {add_token(p, open(box_hv, indent));}
impure fn abox(ps p) {add_token(p, open(box_align, 0u));}
impure fn vbox(ps p, uint indent) {add_token(p, open(box_v, indent));}
impure fn hbox(ps p, uint indent) {add_token(p, open(box_h, indent));}
impure fn end(ps p) {add_token(p, close);}
impure fn wrd(ps p, str wrd) {add_token(p, word(wrd));}
impure fn cwrd(ps p, str wrd) {add_token(p, cword(wrd));}
impure fn space(ps p) {add_token(p, brk(1u));}
impure fn spaces(ps p, uint n) {add_token(p, brk(n));}
impure fn line(ps p) {add_token(p, brk(0u));}