diff options
| author | Graydon Hoare <graydon@mozilla.com> | 2012-02-29 11:46:23 -0800 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2012-03-02 18:46:13 -0800 |
| commit | 87c14f1e3d85751bffffda0b1920be5e726172c4 (patch) | |
| tree | 371d86e9a7c65b06df5c8f5e6d499cf4730324fc /src/comp/syntax/print | |
| parent | 9228947fe15af96593abf4745d91802b56c205e8 (diff) | |
| download | rust-87c14f1e3d85751bffffda0b1920be5e726172c4.tar.gz rust-87c14f1e3d85751bffffda0b1920be5e726172c4.zip | |
Move src/comp to src/rustc
Diffstat (limited to 'src/comp/syntax/print')
| -rw-r--r-- | src/comp/syntax/print/pp.rs | 526 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 1793 |
2 files changed, 0 insertions, 2319 deletions
diff --git a/src/comp/syntax/print/pp.rs b/src/comp/syntax/print/pp.rs deleted file mode 100644 index 0b55bb8c356..00000000000 --- a/src/comp/syntax/print/pp.rs +++ /dev/null @@ -1,526 +0,0 @@ - -import std::io; -import io::writer_util; - -/* - * This pretty-printer is a direct reimplementation of Philip Karlton's - * Mesa pretty-printer, as described in appendix A of - * - * STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen. - * Stanford Department of Computer Science, 1979. - * - * The algorithm's aim is to break a stream into as few lines as possible - * while respecting the indentation-consistency requirements of the enclosing - * block, and avoiding breaking at silly places on block boundaries, for - * example, between "x" and ")" in "x)". - * - * I am implementing this algorithm because it comes with 20 pages of - * documentation explaining its theory, and because it addresses the set of - * concerns I've seen other pretty-printers fall down on. Weirdly. Even though - * it's 32 years old and not written in Haskell. What can I say? - * - * Despite some redundancies and quirks in the way it's implemented in that - * paper, I've opted to keep the implementation here as similar as I can, - * changing only what was blatantly wrong, a typo, or sufficiently - * non-idiomatic rust that it really stuck out. - * - * In particular you'll see a certain amount of churn related to INTEGER vs. - * CARDINAL in the Mesa implementation. Mesa apparently interconverts the two - * somewhat readily? In any case, I've used uint for indices-in-buffers and - * ints for character-sizes-and-indentation-offsets. This respects the need - * for ints to "go negative" while carrying a pending-calculation balance, and - * helps differentiate all the numbers flying around internally (slightly). - * - * I also inverted the indentation arithmetic used in the print stack, since - * the Mesa implementation (somewhat randomly) stores the offset on the print - * stack in terms of margin-col rather than col itself. I store col. - * - * I also implemented a small change in the STRING token, in that I store an - * explicit length for the string. For most tokens this is just the length of - * the accompanying string. But it's necessary to permit it to differ, for - * encoding things that are supposed to "go on their own line" -- certain - * classes of comment and blank-line -- where relying on adjacent - * hardbreak-like BREAK tokens with long blankness indication doesn't actually - * work. To see why, consider when there is a "thing that should be on its own - * line" between two long blocks, say functions. If you put a hardbreak after - * each function (or before each) and the breaking algorithm decides to break - * there anyways (because the functions themselves are long) you wind up with - * extra blank lines. If you don't put hardbreaks you can wind up with the - * "thing which should be on its own line" not getting its own line in the - * rare case of "really small functions" or such. This re-occurs with comments - * and explicit blank lines. So in those cases we use a string with a payload - * we want isolated to a line and an explicit length that's huge, surrounded - * by two zero-length breaks. The algorithm will try its best to fit it on a - * line (which it can't) and so naturally place the content on its own line to - * avoid combining it with other lines and making matters even worse. - */ -enum breaks { consistent, inconsistent, } - -type break_t = {offset: int, blank_space: int}; - -type begin_t = {offset: int, breaks: breaks}; - -enum token { STRING(str, int), BREAK(break_t), BEGIN(begin_t), END, EOF, } - -fn tok_str(t: token) -> str { - alt t { - STRING(s, len) { ret #fmt["STR(%s,%d)", s, len]; } - BREAK(_) { ret "BREAK"; } - BEGIN(_) { ret "BEGIN"; } - END { ret "END"; } - EOF { ret "EOF"; } - } -} - -fn buf_str(toks: [mutable token], szs: [mutable int], left: uint, right: uint, - lim: uint) -> str { - let n = vec::len(toks); - assert (n == vec::len(szs)); - let i = left; - let L = lim; - let s = "["; - while i != right && L != 0u { - L -= 1u; - if i != left { s += ", "; } - s += #fmt["%d=%s", szs[i], tok_str(toks[i])]; - i += 1u; - i %= n; - } - s += "]"; - ret s; -} - -enum print_stack_break { fits, broken(breaks), } - -type print_stack_elt = {offset: int, pbreak: print_stack_break}; - -const size_infinity: int = 0xffff; - -fn mk_printer(out: io::writer, linewidth: uint) -> printer { - // Yes 3, it makes the ring buffers big enough to never - // fall behind. - let n: uint = 3u * linewidth; - #debug("mk_printer %u", linewidth); - let token: [mutable token] = vec::to_mut(vec::init_elt(n, EOF)); - let size: [mutable int] = vec::to_mut(vec::init_elt(n, 0)); - let scan_stack: [mutable uint] = vec::to_mut(vec::init_elt(n, 0u)); - let print_stack: [print_stack_elt] = []; - @{out: out, - buf_len: n, - mutable margin: linewidth as int, - mutable space: linewidth as int, - mutable left: 0u, - mutable right: 0u, - mutable token: token, - mutable size: size, - mutable left_total: 0, - mutable right_total: 0, - mutable scan_stack: scan_stack, - mutable scan_stack_empty: true, - mutable top: 0u, - mutable bottom: 0u, - mutable print_stack: print_stack, - mutable pending_indentation: 0} -} - - -/* - * In case you do not have the paper, here is an explanation of what's going - * on. - * - * There is a stream of input tokens flowing through this printer. - * - * The printer buffers up to 3N tokens inside itself, where N is linewidth. - * Yes, linewidth is chars and tokens are multi-char, but in the worst - * case every token worth buffering is 1 char long, so it's ok. - * - * Tokens are STRING, BREAK, and BEGIN/END to delimit blocks. - * - * BEGIN tokens can carry an offset, saying "how far to indent when you break - * inside here", as well as a flag indicating "consistent" or "inconsistent" - * breaking. Consistent breaking means that after the first break, no attempt - * will be made to flow subsequent breaks together onto lines. Inconsistent - * is the opposite. Inconsistent breaking example would be, say: - * - * foo(hello, there, good, friends) - * - * breaking inconsistently to become - * - * foo(hello, there - * good, friends); - * - * whereas a consistent breaking would yield: - * - * foo(hello, - * there - * good, - * friends); - * - * That is, in the consistent-break blocks we value vertical alignment - * more than the ability to cram stuff onto a line. But in all cases if it - * can make a block a one-liner, it'll do so. - * - * Carrying on with high-level logic: - * - * The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and - * 'right' indices denote the active portion of the ring buffer as well as - * describing hypothetical points-in-the-infinite-stream at most 3N tokens - * apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch - * between using 'left' and 'right' terms to denote the wrapepd-to-ring-buffer - * and point-in-infinite-stream senses freely. - * - * There is a parallel ring buffer, 'size', that holds the calculated size of - * each token. Why calculated? Because for BEGIN/END pairs, the "size" - * includes everything betwen the pair. That is, the "size" of BEGIN is - * actually the sum of the sizes of everything between BEGIN and the paired - * END that follows. Since that is arbitrarily far in the future, 'size' is - * being rewritten regularly while the printer runs; in fact most of the - * machinery is here to work out 'size' entries on the fly (and give up when - * they're so obviously over-long that "infinity" is a good enough - * approximation for purposes of line breaking). - * - * The "input side" of the printer is managed as an abstract process called - * SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to - * manage calculating 'size'. SCAN is, in other words, the process of - * calculating 'size' entries. - * - * The "output side" of the printer is managed by an abstract process called - * PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to - * do with each token/size pair it consumes as it goes. It's trying to consume - * the entire buffered window, but can't output anything until the size is >= - * 0 (sizes are set to negative while they're pending calculation). - * - * So SCAN takeks input and buffers tokens and pending calculations, while - * PRINT gobbles up completed calculations and tokens from the buffer. The - * theory is that the two can never get more than 3N tokens apart, because - * once there's "obviously" too much data to fit on a line, in a size - * calculation, SCAN will write "infinity" to the size and let PRINT consume - * it. - * - * In this implementation (following the paper, again) the SCAN process is - * the method called 'pretty_print', and the 'PRINT' process is the method - * called 'print'. - */ -type printer = @{ - out: io::writer, - buf_len: uint, - mutable margin: int, // width of lines we're constrained to - mutable space: int, // number of spaces left on line - mutable left: uint, // index of left side of input stream - mutable right: uint, // index of right side of input stream - mutable token: [mutable token], // ring-buffr stream goes through - mutable size: [mutable int], // ring-buffer of calculated sizes - mutable left_total: int, // running size of stream "...left" - mutable right_total: int, // running size of stream "...right" - // pseudo-stack, really a ring too. Holds the - // primary-ring-buffers index of the BEGIN that started the - // current block, possibly with the most recent BREAK after that - // BEGIN (if there is any) on top of it. Stuff is flushed off the - // bottom as it becomes irrelevant due to the primary ring-buffer - // advancing. - mutable scan_stack: [mutable uint], - mutable scan_stack_empty: bool, // top==bottom disambiguator - mutable top: uint, // index of top of scan_stack - mutable bottom: uint, // index of bottom of scan_stack - // stack of blocks-in-progress being flushed by print - mutable print_stack: [print_stack_elt], - // buffered indentation to avoid writing trailing whitespace - mutable pending_indentation: int -}; - -impl printer for printer { - fn last_token() -> token { self.token[self.right] } - // be very careful with this! - fn replace_last_token(t: token) { self.token[self.right] = t; } - fn pretty_print(t: token) { - #debug("pp [%u,%u]", self.left, self.right); - alt t { - EOF { - if !self.scan_stack_empty { - self.check_stack(0); - self.advance_left(self.token[self.left], - self.size[self.left]); - } - self.indent(0); - } - BEGIN(b) { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0u; - self.right = 0u; - } else { self.advance_right(); } - #debug("pp BEGIN/buffer [%u,%u]", self.left, self.right); - self.token[self.right] = t; - self.size[self.right] = -self.right_total; - self.scan_push(self.right); - } - END { - if self.scan_stack_empty { - #debug("pp END/print [%u,%u]", self.left, self.right); - self.print(t, 0); - } else { - #debug("pp END/buffer [%u,%u]", self.left, self.right); - self.advance_right(); - self.token[self.right] = t; - self.size[self.right] = -1; - self.scan_push(self.right); - } - } - BREAK(b) { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0u; - self.right = 0u; - } else { self.advance_right(); } - #debug("pp BREAK/buffer [%u,%u]", self.left, self.right); - self.check_stack(0); - self.scan_push(self.right); - self.token[self.right] = t; - self.size[self.right] = -self.right_total; - self.right_total += b.blank_space; - } - STRING(s, len) { - if self.scan_stack_empty { - #debug("pp STRING/print [%u,%u]", self.left, self.right); - self.print(t, len); - } else { - #debug("pp STRING/buffer [%u,%u]", self.left, self.right); - self.advance_right(); - self.token[self.right] = t; - self.size[self.right] = len; - self.right_total += len; - self.check_stream(); - } - } - } - } - fn check_stream() { - #debug("check_stream [%u, %u] with left_total=%d, right_total=%d", - self.left, self.right, self.left_total, self.right_total); - if self.right_total - self.left_total > self.space { - #debug("scan window is %d, longer than space on line (%d)", - self.right_total - self.left_total, self.space); - if !self.scan_stack_empty { - if self.left == self.scan_stack[self.bottom] { - #debug("setting %u to infinity and popping", self.left); - self.size[self.scan_pop_bottom()] = size_infinity; - } - } - self.advance_left(self.token[self.left], self.size[self.left]); - if self.left != self.right { self.check_stream(); } - } - } - fn scan_push(x: uint) { - #debug("scan_push %u", x); - if self.scan_stack_empty { - self.scan_stack_empty = false; - } else { - self.top += 1u; - self.top %= self.buf_len; - assert (self.top != self.bottom); - } - self.scan_stack[self.top] = x; - } - fn scan_pop() -> uint { - assert (!self.scan_stack_empty); - let x = self.scan_stack[self.top]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { self.top += self.buf_len - 1u; self.top %= self.buf_len; } - ret x; - } - fn scan_top() -> uint { - assert (!self.scan_stack_empty); - ret self.scan_stack[self.top]; - } - fn scan_pop_bottom() -> uint { - assert (!self.scan_stack_empty); - let x = self.scan_stack[self.bottom]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { self.bottom += 1u; self.bottom %= self.buf_len; } - ret x; - } - fn advance_right() { - self.right += 1u; - self.right %= self.buf_len; - assert (self.right != self.left); - } - fn advance_left(x: token, L: int) { - #debug("advnce_left [%u,%u], sizeof(%u)=%d", self.left, self.right, - self.left, L); - if L >= 0 { - self.print(x, L); - alt x { - BREAK(b) { self.left_total += b.blank_space; } - STRING(_, len) { assert (len == L); self.left_total += len; } - _ { } - } - if self.left != self.right { - self.left += 1u; - self.left %= self.buf_len; - self.advance_left(self.token[self.left], - self.size[self.left]); - } - } - } - fn check_stack(k: int) { - if !self.scan_stack_empty { - let x = self.scan_top(); - alt self.token[x] { - BEGIN(b) { - if k > 0 { - self.size[self.scan_pop()] = self.size[x] + - self.right_total; - self.check_stack(k - 1); - } - } - END { - // paper says + not =, but that makes no sense. - self.size[self.scan_pop()] = 1; - self.check_stack(k + 1); - } - _ { - self.size[self.scan_pop()] = self.size[x] + self.right_total; - if k > 0 { self.check_stack(k); } - } - } - } - } - fn print_newline(amount: int) { - #debug("NEWLINE %d", amount); - self.out.write_str("\n"); - self.pending_indentation = 0; - self.indent(amount); - } - fn indent(amount: int) { - #debug("INDENT %d", amount); - self.pending_indentation += amount; - } - fn get_top() -> print_stack_elt { - let n = vec::len(self.print_stack); - let top: print_stack_elt = {offset: 0, pbreak: broken(inconsistent)}; - if n != 0u { top = self.print_stack[n - 1u]; } - ret top; - } - fn write_str(s: str) { - while self.pending_indentation > 0 { - self.out.write_str(" "); - self.pending_indentation -= 1; - } - self.out.write_str(s); - } - fn print(x: token, L: int) { - #debug("print %s %d (remaining line space=%d)", tok_str(x), L, - self.space); - log(debug, buf_str(self.token, self.size, self.left, self.right, 6u)); - alt x { - BEGIN(b) { - if L > self.space { - let col = self.margin - self.space + b.offset; - #debug("print BEGIN -> push broken block at col %d", col); - self.print_stack += [{offset: col, pbreak: broken(b.breaks)}]; - } else { - #debug("print BEGIN -> push fitting block"); - self.print_stack += [{offset: 0, pbreak: fits}]; - } - } - END { - #debug("print END -> pop END"); - assert (vec::len(self.print_stack) != 0u); - vec::pop(self.print_stack); - } - BREAK(b) { - let top = self.get_top(); - alt top.pbreak { - fits { - #debug("print BREAK in fitting block"); - self.space -= b.blank_space; - self.indent(b.blank_space); - } - broken(consistent) { - #debug("print BREAK in consistent block"); - self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - } - broken(inconsistent) { - if L > self.space { - #debug("print BREAK w/ newline in inconsistent"); - self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - } else { - #debug("print BREAK w/o newline in inconsistent"); - self.indent(b.blank_space); - self.space -= b.blank_space; - } - } - } - } - STRING(s, len) { - #debug("print STRING"); - assert (L == len); - // assert L <= space; - self.space -= len; - self.write_str(s); - } - EOF { - // EOF should never get here. - fail; - } - } - } -} - -// Convenience functions to talk to the printer. -fn box(p: printer, indent: uint, b: breaks) { - p.pretty_print(BEGIN({offset: indent as int, breaks: b})); -} - -fn ibox(p: printer, indent: uint) { box(p, indent, inconsistent); } - -fn cbox(p: printer, indent: uint) { box(p, indent, consistent); } - -fn break_offset(p: printer, n: uint, off: int) { - p.pretty_print(BREAK({offset: off, blank_space: n as int})); -} - -fn end(p: printer) { p.pretty_print(END); } - -fn eof(p: printer) { p.pretty_print(EOF); } - -fn word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, str::len(wrd) as int)); -} - -fn huge_word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, size_infinity)); -} - -fn zero_word(p: printer, wrd: str) { p.pretty_print(STRING(wrd, 0)); } - -fn spaces(p: printer, n: uint) { break_offset(p, n, 0); } - -fn zerobreak(p: printer) { spaces(p, 0u); } - -fn space(p: printer) { spaces(p, 1u); } - -fn hardbreak(p: printer) { spaces(p, size_infinity as uint); } - -fn hardbreak_tok_offset(off: int) -> token { - ret BREAK({offset: off, blank_space: size_infinity}); -} - -fn hardbreak_tok() -> token { ret hardbreak_tok_offset(0); } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs deleted file mode 100644 index 5f92b5d5beb..00000000000 --- a/src/comp/syntax/print/pprust.rs +++ /dev/null @@ -1,1793 +0,0 @@ - -import std::io; -import parse::lexer; -import syntax::codemap::codemap; -import pp::{break_offset, word, printer, - space, zerobreak, hardbreak, breaks, consistent, - inconsistent, eof}; -import driver::diagnostic; - -// The ps is stored here to prevent recursive type. -enum ann_node { - node_block(ps, ast::blk), - node_item(ps, @ast::item), - node_expr(ps, @ast::expr), - node_pat(ps, @ast::pat), -} -type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)}; - -fn no_ann() -> pp_ann { - fn ignore(_node: ann_node) { } - ret {pre: ignore, post: ignore}; -} - -type ps = - @{s: pp::printer, - cm: option<codemap>, - comments: option<[lexer::cmnt]>, - literals: option<[lexer::lit]>, - mutable cur_cmnt: uint, - mutable cur_lit: uint, - mutable boxes: [pp::breaks], - ann: pp_ann}; - -fn ibox(s: ps, u: uint) { s.boxes += [pp::inconsistent]; pp::ibox(s.s, u); } - -fn end(s: ps) { vec::pop(s.boxes); pp::end(s.s); } - -fn rust_printer(writer: io::writer) -> ps { - let boxes: [pp::breaks] = []; - ret @{s: pp::mk_printer(writer, default_columns), - cm: none::<codemap>, - comments: none::<[lexer::cmnt]>, - literals: none::<[lexer::lit]>, - mutable cur_cmnt: 0u, - mutable cur_lit: 0u, - mutable boxes: boxes, - ann: no_ann()}; -} - -const indent_unit: uint = 4u; -const alt_indent_unit: uint = 2u; - -const default_columns: uint = 78u; - -// Requires you to pass an input filename and reader so that -// it can scan the input text for comments and literals to -// copy forward. -fn print_crate(cm: codemap, span_diagnostic: diagnostic::span_handler, - crate: @ast::crate, filename: str, in: io::reader, - out: io::writer, ann: pp_ann) { - let boxes: [pp::breaks] = []; - let r = lexer::gather_comments_and_literals(cm, span_diagnostic, filename, - in); - let s = - @{s: pp::mk_printer(out, default_columns), - cm: some(cm), - comments: some(r.cmnts), - literals: some(r.lits), - mutable cur_cmnt: 0u, - mutable cur_lit: 0u, - mutable boxes: boxes, - ann: ann}; - print_crate_(s, crate); -} - -fn print_crate_(s: ps, &&crate: @ast::crate) { - print_mod(s, crate.node.module, crate.node.attrs); - print_remaining_comments(s); - eof(s.s); -} - -fn ty_to_str(ty: @ast::ty) -> str { be to_str(ty, print_type); } - -fn pat_to_str(pat: @ast::pat) -> str { be to_str(pat, print_pat); } - -fn expr_to_str(e: @ast::expr) -> str { be to_str(e, print_expr); } - -fn stmt_to_str(s: ast::stmt) -> str { be to_str(s, print_stmt); } - -fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); } - -fn attr_to_str(i: ast::attribute) -> str { be to_str(i, print_attribute); } - -fn typarams_to_str(tps: [ast::ty_param]) -> str { - be to_str(tps, print_type_params) -} - -fn path_to_str(&&p: @ast::path) -> str { - be to_str(p, bind print_path(_, _, false)); -} - -fn fun_to_str(decl: ast::fn_decl, name: ast::ident, - params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - print_fn(s, decl, name, params); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - io::mem_buffer_str(buffer) -} - -#[test] -fn test_fun_to_str() { - let decl: ast::fn_decl = { - inputs: [], - output: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: [] - }; - assert fun_to_str(decl, "a", []) == "fn a()"; -} - -fn res_to_str(decl: ast::fn_decl, name: ast::ident, - params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - print_res(s, decl, name, params); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - io::mem_buffer_str(buffer) -} - -#[test] -fn test_res_to_str() { - let decl: ast::fn_decl = { - inputs: [{ - mode: ast::expl(ast::by_val), - ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - ident: "b", - id: 0 - }], - output: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: [] - }; - assert res_to_str(decl, "a", []) == "resource a(b: ())"; -} - -fn block_to_str(blk: ast::blk) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-ibox, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - eof(s.s); - io::mem_buffer_str(buffer) -} - -fn meta_item_to_str(mi: ast::meta_item) -> str { - ret to_str(@mi, print_meta_item); -} - -fn attribute_to_str(attr: ast::attribute) -> str { - be to_str(attr, print_attribute); -} - -fn variant_to_str(var: ast::variant) -> str { - be to_str(var, print_variant); -} - -#[test] -fn test_variant_to_str() { - let var = ast_util::respan(ast_util::dummy_sp(), { - name: "principle_skinner", - attrs: [], - args: [], - id: 0, - disr_expr: none - }); - - let varstr = variant_to_str(var); - assert varstr == "principle_skinner"; -} - -fn cbox(s: ps, u: uint) { s.boxes += [pp::consistent]; pp::cbox(s.s, u); } - -fn box(s: ps, u: uint, b: pp::breaks) { s.boxes += [b]; pp::box(s.s, u, b); } - -fn nbsp(s: ps) { word(s.s, " "); } - -fn word_nbsp(s: ps, w: str) { word(s.s, w); nbsp(s); } - -fn word_space(s: ps, w: str) { word(s.s, w); space(s.s); } - -fn popen(s: ps) { word(s.s, "("); } - -fn pclose(s: ps) { word(s.s, ")"); } - -fn head(s: ps, w: str) { - // outer-box is consistent - cbox(s, indent_unit); - // head-box is inconsistent - ibox(s, str::len(w) + 1u); - // keyword that starts the head - word_nbsp(s, w); -} - -fn bopen(s: ps) { - word(s.s, "{"); - end(s); // close the head-box -} - -fn bclose_(s: ps, span: codemap::span, indented: uint) { - maybe_print_comment(s, span.hi); - break_offset_if_not_bol(s, 1u, -(indented as int)); - word(s.s, "}"); - end(s); // close the outer-box -} -fn bclose(s: ps, span: codemap::span) { bclose_(s, span, indent_unit); } - -fn is_begin(s: ps) -> bool { - alt s.s.last_token() { pp::BEGIN(_) { true } _ { false } } -} - -fn is_end(s: ps) -> bool { - alt s.s.last_token() { pp::END { true } _ { false } } -} - -fn is_bol(s: ps) -> bool { - ret s.s.last_token() == pp::EOF || - s.s.last_token() == pp::hardbreak_tok(); -} - -fn hardbreak_if_not_bol(s: ps) { if !is_bol(s) { hardbreak(s.s); } } -fn space_if_not_bol(s: ps) { if !is_bol(s) { space(s.s); } } -fn break_offset_if_not_bol(s: ps, n: uint, off: int) { - if !is_bol(s) { - break_offset(s.s, n, off); - } else { - if off != 0 && s.s.last_token() == pp::hardbreak_tok() { - // We do something pretty sketchy here: tuck the nonzero - // offset-adjustment we were going to deposit along with the - // break into the previous hardbreak. - s.s.replace_last_token(pp::hardbreak_tok_offset(off)); - } - } -} - -// Synthesizes a comment that was not textually present in the original source -// file. -fn synth_comment(s: ps, text: str) { - word(s.s, "/*"); - space(s.s); - word(s.s, text); - space(s.s); - word(s.s, "*/"); -} - -fn commasep<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN)) { - box(s, 0u, b); - let first = true; - for elt: IN in elts { - if first { first = false; } else { word_space(s, ","); } - op(s, elt); - } - end(s); -} - - -fn commasep_cmnt<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN), - get_span: fn(IN) -> codemap::span) { - box(s, 0u, b); - let len = vec::len::<IN>(elts); - let i = 0u; - for elt: IN in elts { - maybe_print_comment(s, get_span(elt).hi); - op(s, elt); - i += 1u; - if i < len { - word(s.s, ","); - maybe_print_trailing_comment(s, get_span(elt), - some(get_span(elts[i]).hi)); - space_if_not_bol(s); - } - } - end(s); -} - -fn commasep_exprs(s: ps, b: breaks, exprs: [@ast::expr]) { - fn expr_span(&&expr: @ast::expr) -> codemap::span { ret expr.span; } - commasep_cmnt(s, b, exprs, print_expr, expr_span); -} - -fn print_mod(s: ps, _mod: ast::_mod, attrs: [ast::attribute]) { - print_inner_attributes(s, attrs); - for vitem: @ast::view_item in _mod.view_items { - print_view_item(s, vitem); - } - for item: @ast::item in _mod.items { print_item(s, item); } -} - -fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) { - print_inner_attributes(s, attrs); - for vitem: @ast::view_item in nmod.view_items { - print_view_item(s, vitem); - } - for item: @ast::native_item in nmod.items { print_native_item(s, item); } -} - -fn print_type(s: ps, &&ty: @ast::ty) { - maybe_print_comment(s, ty.span.lo); - ibox(s, 0u); - alt ty.node { - ast::ty_nil { word(s.s, "()"); } - ast::ty_bot { word(s.s, "!"); } - ast::ty_box(mt) { word(s.s, "@"); print_mt(s, mt); } - ast::ty_uniq(mt) { word(s.s, "~"); print_mt(s, mt); } - ast::ty_vec(mt) { - word(s.s, "["); - alt mt.mutbl { - ast::m_mutbl { word_space(s, "mut"); } - ast::m_const { word_space(s, "const"); } - ast::m_imm { } - } - print_type(s, mt.ty); - word(s.s, "]"); - } - ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); } - ast::ty_rec(fields) { - word(s.s, "{"); - fn print_field(s: ps, f: ast::ty_field) { - cbox(s, indent_unit); - print_mutability(s, f.node.mt.mutbl); - word(s.s, f.node.ident); - word_space(s, ":"); - print_type(s, f.node.mt.ty); - end(s); - } - fn get_span(f: ast::ty_field) -> codemap::span { ret f.span; } - commasep_cmnt(s, consistent, fields, print_field, get_span); - word(s.s, ",}"); - } - ast::ty_tup(elts) { - popen(s); - commasep(s, inconsistent, elts, print_type); - pclose(s); - } - ast::ty_fn(proto, d) { - print_ty_fn(s, some(proto), d, none, none); - } - ast::ty_path(path, _) { print_path(s, path, false); } - ast::ty_constr(t, cs) { - print_type(s, t); - space(s.s); - word(s.s, constrs_str(cs, ty_constr_to_str)); - } - ast::ty_mac(_) { - fail "print_type doesn't know how to print a ty_mac"; - } - ast::ty_infer { - fail "print_type shouldn't see a ty_infer"; - } - - } - end(s); -} - -fn print_native_item(s: ps, item: @ast::native_item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - print_outer_attributes(s, item.attrs); - alt item.node { - ast::native_item_fn(decl, typarams) { - print_fn(s, decl, item.ident, typarams); - end(s); // end head-ibox - word(s.s, ";"); - end(s); // end the outer fn box - } - } -} - -fn print_item(s: ps, &&item: @ast::item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - print_outer_attributes(s, item.attrs); - let ann_node = node_item(s, item); - s.ann.pre(ann_node); - alt item.node { - ast::item_const(ty, expr) { - head(s, "const"); - word_space(s, item.ident + ":"); - print_type(s, ty); - space(s.s); - end(s); // end the head-ibox - - word_space(s, "="); - print_expr(s, expr); - word(s.s, ";"); - end(s); // end the outer cbox - - } - ast::item_fn(decl, typarams, body) { - print_fn(s, decl, item.ident, typarams); - word(s.s, " "); - print_block_with_attrs(s, body, item.attrs); - } - ast::item_mod(_mod) { - head(s, "mod"); - word_nbsp(s, item.ident); - bopen(s); - print_mod(s, _mod, item.attrs); - bclose(s, item.span); - } - ast::item_native_mod(nmod) { - head(s, "native"); - word_nbsp(s, "mod"); - word_nbsp(s, item.ident); - bopen(s); - print_native_mod(s, nmod, item.attrs); - bclose(s, item.span); - } - ast::item_ty(ty, params) { - ibox(s, indent_unit); - ibox(s, 0u); - word_nbsp(s, "type"); - word(s.s, item.ident); - print_type_params(s, params); - end(s); // end the inner ibox - - space(s.s); - word_space(s, "="); - print_type(s, ty); - word(s.s, ";"); - end(s); // end the outer ibox - } - ast::item_enum(variants, params) { - let newtype = - vec::len(variants) == 1u && - str::eq(item.ident, variants[0].node.name) && - vec::len(variants[0].node.args) == 1u; - if newtype { - ibox(s, indent_unit); - word_space(s, "enum"); - } else { head(s, "enum"); } - word(s.s, item.ident); - print_type_params(s, params); - space(s.s); - if newtype { - word_space(s, "="); - print_type(s, variants[0].node.args[0].ty); - word(s.s, ";"); - end(s); - } else { - bopen(s); - for v: ast::variant in variants { - space_if_not_bol(s); - maybe_print_comment(s, v.span.lo); - print_outer_attributes(s, v.node.attrs); - ibox(s, indent_unit); - print_variant(s, v); - word(s.s, ","); - end(s); - maybe_print_trailing_comment(s, v.span, none::<uint>); - } - bclose(s, item.span); - } - } - ast::item_class(tps,items,_,ctor_decl,ctor_body) { - head(s, "class"); - word_nbsp(s, item.ident); - print_type_params(s, tps); - bopen(s); - hardbreak_if_not_bol(s); - head(s, "new"); - print_fn_args_and_ret(s, ctor_decl); - space(s.s); - print_block(s, ctor_body); - for ci in items { - /* - FIXME: collect all private items and print them - in a single "priv" section - */ - hardbreak_if_not_bol(s); - alt ci.node.privacy { - ast::priv { - head(s, "priv"); - bopen(s); - hardbreak_if_not_bol(s); - } - _ {} - } - alt ci.node.decl { - ast::instance_var(nm, t, mt, _) { - word_nbsp(s, "let"); - alt mt { - ast::class_mutable { word_nbsp(s, "mutable"); } - _ {} - } - word(s.s, nm); - word_nbsp(s, ":"); - print_type(s, t); - word(s.s, ";"); - } - ast::class_method(i) { - print_item(s, i); - } - } - alt ci.node.privacy { - ast::priv { bclose(s, ci.span); } - _ {} - } - } - } - ast::item_impl(tps, ifce, ty, methods) { - head(s, "impl"); - word(s.s, item.ident); - print_type_params(s, tps); - space(s.s); - alt ifce { - some(ty) { - word_nbsp(s, "of"); - print_type(s, ty); - space(s.s); - } - _ {} - } - word_nbsp(s, "for"); - print_type(s, ty); - space(s.s); - bopen(s); - for meth in methods { - hardbreak_if_not_bol(s); - maybe_print_comment(s, meth.span.lo); - print_outer_attributes(s, meth.attrs); - print_fn(s, meth.decl, meth.ident, meth.tps); - word(s.s, " "); - print_block_with_attrs(s, meth.body, meth.attrs); - } - bclose(s, item.span); - } - ast::item_iface(tps, methods) { - head(s, "iface"); - word(s.s, item.ident); - print_type_params(s, tps); - word(s.s, " "); - bopen(s); - for meth in methods { print_ty_method(s, meth); } - bclose(s, item.span); - } - ast::item_res(decl, tps, body, dt_id, ct_id) { - print_res(s, decl, item.ident, tps); - print_block(s, body); - } - } - s.ann.post(ann_node); -} - -fn print_res(s: ps, decl: ast::fn_decl, name: ast::ident, - typarams: [ast::ty_param]) { - head(s, "resource"); - word(s.s, name); - print_type_params(s, typarams); - popen(s); - word_space(s, decl.inputs[0].ident + ":"); - print_type(s, decl.inputs[0].ty); - pclose(s); - space(s.s); -} - -fn print_variant(s: ps, v: ast::variant) { - word(s.s, v.node.name); - if vec::len(v.node.args) > 0u { - popen(s); - fn print_variant_arg(s: ps, arg: ast::variant_arg) { - print_type(s, arg.ty); - } - commasep(s, consistent, v.node.args, print_variant_arg); - pclose(s); - } - alt v.node.disr_expr { - some(d) { - space(s.s); - word_space(s, "="); - print_expr(s, d); - } - _ {} - } -} - -fn print_ty_method(s: ps, m: ast::ty_method) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, m.span.lo); - print_outer_attributes(s, m.attrs); - print_ty_fn(s, none, m.decl, some(m.ident), some(m.tps)); - word(s.s, ";"); -} - -fn print_outer_attributes(s: ps, attrs: [ast::attribute]) { - let count = 0; - for attr: ast::attribute in attrs { - alt attr.node.style { - ast::attr_outer { print_attribute(s, attr); count += 1; } - _ {/* fallthrough */ } - } - } - if count > 0 { hardbreak_if_not_bol(s); } -} - -fn print_inner_attributes(s: ps, attrs: [ast::attribute]) { - let count = 0; - for attr: ast::attribute in attrs { - alt attr.node.style { - ast::attr_inner { - print_attribute(s, attr); - word(s.s, ";"); - count += 1; - } - _ {/* fallthrough */ } - } - } - if count > 0 { hardbreak_if_not_bol(s); } -} - -fn print_attribute(s: ps, attr: ast::attribute) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, attr.span.lo); - word(s.s, "#["); - print_meta_item(s, @attr.node.value); - word(s.s, "]"); -} - - -fn print_stmt(s: ps, st: ast::stmt) { - maybe_print_comment(s, st.span.lo); - alt st.node { - ast::stmt_decl(decl, _) { - print_decl(s, decl); - } - ast::stmt_expr(expr, _) { - space_if_not_bol(s); - print_expr(s, expr); - } - ast::stmt_semi(expr, _) { - space_if_not_bol(s); - print_expr(s, expr); - word(s.s, ";"); - } - } - if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); } - maybe_print_trailing_comment(s, st.span, none::<uint>); -} - -fn print_block(s: ps, blk: ast::blk) { - print_possibly_embedded_block(s, blk, block_normal, indent_unit); -} - -fn print_block_with_attrs(s: ps, blk: ast::blk, attrs: [ast::attribute]) { - print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs); -} - -enum embed_type { block_macro, block_block_fn, block_normal, } - -fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type, - indented: uint) { - print_possibly_embedded_block_( - s, blk, embedded, indented, []); -} - -fn print_possibly_embedded_block_(s: ps, blk: ast::blk, embedded: embed_type, - indented: uint, attrs: [ast::attribute]) { - alt blk.node.rules { - ast::unchecked_blk { word(s.s, "unchecked"); } - ast::unsafe_blk { word(s.s, "unsafe"); } - ast::default_blk { } - } - maybe_print_comment(s, blk.span.lo); - let ann_node = node_block(s, blk); - s.ann.pre(ann_node); - alt embedded { - block_macro { word(s.s, "#{"); end(s); } - block_block_fn { end(s); } - block_normal { bopen(s); } - } - - print_inner_attributes(s, attrs); - - for vi in blk.node.view_items { print_view_item(s, vi); } - for st: @ast::stmt in blk.node.stmts { - print_stmt(s, *st); - } - alt blk.node.expr { - some(expr) { - space_if_not_bol(s); - print_expr(s, expr); - maybe_print_trailing_comment(s, expr.span, some(blk.span.hi)); - } - _ { } - } - bclose_(s, blk.span, indented); - s.ann.post(ann_node); -} - -// ret and fail, without arguments cannot appear is the discriminant of if, -// alt, do, & while unambiguously without being parenthesized -fn print_maybe_parens_discrim(s: ps, e: @ast::expr) { - let disambig = alt e.node { - ast::expr_ret(none) | ast::expr_fail(none) { true } - _ { false } - }; - if disambig { popen(s); } - print_expr(s, e); - if disambig { pclose(s); } -} - -fn print_if(s: ps, test: @ast::expr, blk: ast::blk, - elseopt: option<@ast::expr>, chk: bool) { - head(s, "if"); - if chk { word_nbsp(s, "check"); } - print_maybe_parens_discrim(s, test); - space(s.s); - print_block(s, blk); - fn do_else(s: ps, els: option<@ast::expr>) { - alt els { - some(_else) { - alt _else.node { - // "another else-if" - ast::expr_if(i, t, e) { - cbox(s, indent_unit - 1u); - ibox(s, 0u); - word(s.s, " else if "); - print_maybe_parens_discrim(s, i); - space(s.s); - print_block(s, t); - do_else(s, e); - } - // "final else" - ast::expr_block(b) { - cbox(s, indent_unit - 1u); - ibox(s, 0u); - word(s.s, " else "); - print_block(s, b); - } - // BLEAH, constraints would be great here - _ { - fail "print_if saw if with weird alternative"; - } - } - } - _ {/* fall through */ } - } - } - do_else(s, elseopt); -} - -fn print_mac(s: ps, m: ast::mac) { - alt m.node { - ast::mac_invoc(path, arg, body) { - word(s.s, "#"); - print_path(s, path, false); - alt arg { - some(@{node: ast::expr_vec(_, _), _}) { } - _ { word(s.s, " "); } - } - option::may(arg, bind print_expr(s, _)); - // FIXME: extension 'body' - } - ast::mac_embed_type(ty) { - word(s.s, "#<"); - print_type(s, ty); - word(s.s, ">"); - } - ast::mac_embed_block(blk) { - print_possibly_embedded_block(s, blk, block_normal, indent_unit); - } - ast::mac_ellipsis { word(s.s, "..."); } - ast::mac_var(v) { word(s.s, #fmt("$%u", v)); } - _ { /* fixme */ } - } -} - -fn print_expr(s: ps, &&expr: @ast::expr) { - maybe_print_comment(s, expr.span.lo); - ibox(s, indent_unit); - let ann_node = node_expr(s, expr); - s.ann.pre(ann_node); - alt expr.node { - ast::expr_vec(exprs, mutbl) { - ibox(s, indent_unit); - word(s.s, "["); - if mutbl == ast::m_mutbl { - word(s.s, "mutable"); - if vec::len(exprs) > 0u { nbsp(s); } - } - commasep_exprs(s, inconsistent, exprs); - word(s.s, "]"); - end(s); - } - ast::expr_rec(fields, wth) { - fn print_field(s: ps, field: ast::field) { - ibox(s, indent_unit); - if field.node.mutbl == ast::m_mutbl { word_nbsp(s, "mutable"); } - word(s.s, field.node.ident); - word_space(s, ":"); - print_expr(s, field.node.expr); - end(s); - } - fn get_span(field: ast::field) -> codemap::span { ret field.span; } - word(s.s, "{"); - commasep_cmnt(s, consistent, fields, print_field, get_span); - alt wth { - some(expr) { - if vec::len(fields) > 0u { space(s.s); } - ibox(s, indent_unit); - word_space(s, "with"); - print_expr(s, expr); - end(s); - } - _ { word(s.s, ","); } - } - word(s.s, "}"); - } - ast::expr_tup(exprs) { - popen(s); - commasep_exprs(s, inconsistent, exprs); - pclose(s); - } - ast::expr_call(func, args, has_block) { - print_expr_parens_if_not_bot(s, func); - let base_args = args, blk = none; - if has_block { blk = some(vec::pop(base_args)); } - if !has_block || vec::len(base_args) > 0u { - popen(s); - commasep_exprs(s, inconsistent, base_args); - pclose(s); - } - if has_block { - nbsp(s); - print_expr(s, option::get(blk)); - } - } - ast::expr_bind(func, args) { - fn print_opt(s: ps, expr: option<@ast::expr>) { - alt expr { - some(expr) { print_expr(s, expr); } - _ { word(s.s, "_"); } - } - } - - // "bind" keyword is only needed if there are no "_" arguments. - if !vec::any(args) {|arg| option::is_none(arg) } { - word_nbsp(s, "bind"); - } - - print_expr(s, func); - popen(s); - commasep(s, inconsistent, args, print_opt); - pclose(s); - } - ast::expr_binary(op, lhs, rhs) { - let prec = operator_prec(op); - print_op_maybe_parens(s, lhs, prec); - space(s.s); - word_space(s, ast_util::binop_to_str(op)); - print_op_maybe_parens(s, rhs, prec + 1); - } - ast::expr_unary(op, expr) { - word(s.s, ast_util::unop_to_str(op)); - print_op_maybe_parens(s, expr, parse::parser::unop_prec); - } - ast::expr_lit(lit) { print_literal(s, lit); } - ast::expr_cast(expr, ty) { - print_op_maybe_parens(s, expr, parse::parser::as_prec); - space(s.s); - word_space(s, "as"); - print_type(s, ty); - } - ast::expr_if(test, blk, elseopt) { - print_if(s, test, blk, elseopt, false); - } - ast::expr_if_check(test, blk, elseopt) { - print_if(s, test, blk, elseopt, true); - } - ast::expr_while(test, blk) { - head(s, "while"); - print_maybe_parens_discrim(s, test); - space(s.s); - print_block(s, blk); - } - ast::expr_for(decl, expr, blk) { - head(s, "for"); - print_for_decl(s, decl, expr); - space(s.s); - print_block(s, blk); - } - ast::expr_do_while(blk, expr) { - head(s, "do"); - space(s.s); - print_block(s, blk); - space(s.s); - word_space(s, "while"); - print_expr(s, expr); - } - ast::expr_alt(expr, arms, mode) { - cbox(s, alt_indent_unit); - ibox(s, 4u); - word_nbsp(s, "alt"); - if mode == ast::alt_check { word_nbsp(s, "check"); } - print_maybe_parens_discrim(s, expr); - space(s.s); - bopen(s); - for arm: ast::arm in arms { - space(s.s); - cbox(s, alt_indent_unit); - ibox(s, 0u); - let first = true; - for p: @ast::pat in arm.pats { - if first { - first = false; - } else { space(s.s); word_space(s, "|"); } - print_pat(s, p); - } - space(s.s); - alt arm.guard { - some(e) { word_space(s, "if"); print_expr(s, e); space(s.s); } - none { } - } - print_possibly_embedded_block(s, arm.body, block_normal, - alt_indent_unit); - } - bclose_(s, expr.span, alt_indent_unit); - } - ast::expr_fn(proto, decl, body, cap_clause) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block at start - ibox(s, 0u); - word(s.s, proto_to_str(proto)); - print_cap_clause(s, *cap_clause); - print_fn_args_and_ret(s, decl); - space(s.s); - print_block(s, body); - } - ast::expr_fn_block(decl, body) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block at start - ibox(s, 0u); - word(s.s, "{"); - print_fn_block_args(s, decl); - print_possibly_embedded_block(s, body, block_block_fn, indent_unit); - } - ast::expr_block(blk) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - } - ast::expr_copy(e) { word_space(s, "copy"); print_expr(s, e); } - ast::expr_move(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "<-"); - print_expr(s, rhs); - } - ast::expr_assign(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "="); - print_expr(s, rhs); - } - ast::expr_swap(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "<->"); - print_expr(s, rhs); - } - ast::expr_assign_op(op, lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word(s.s, ast_util::binop_to_str(op)); - word_space(s, "="); - print_expr(s, rhs); - } - ast::expr_field(expr, id, tys) { - // Deal with '10.x' - if ends_in_lit_int(expr) { - popen(s); print_expr(s, expr); pclose(s); - } else { - print_expr_parens_if_not_bot(s, expr); - } - word(s.s, "."); - word(s.s, id); - if vec::len(tys) > 0u { - word(s.s, "::<"); - commasep(s, inconsistent, tys, print_type); - word(s.s, ">"); - } - } - ast::expr_index(expr, index) { - print_expr_parens_if_not_bot(s, expr); - word(s.s, "["); - print_expr(s, index); - word(s.s, "]"); - } - ast::expr_path(path) { print_path(s, path, true); } - ast::expr_fail(maybe_fail_val) { - word(s.s, "fail"); - alt maybe_fail_val { - some(expr) { word(s.s, " "); print_expr(s, expr); } - _ { } - } - } - ast::expr_break { word(s.s, "break"); } - ast::expr_cont { word(s.s, "cont"); } - ast::expr_ret(result) { - word(s.s, "ret"); - alt result { - some(expr) { word(s.s, " "); print_expr(s, expr); } - _ { } - } - } - ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); } - ast::expr_log(lvl, lexp, expr) { - alt check lvl { - 1 { word_nbsp(s, "log"); print_expr(s, expr); } - 0 { word_nbsp(s, "log_err"); print_expr(s, expr); } - 2 { - word_nbsp(s, "log"); - popen(s); - print_expr(s, lexp); - word(s.s, ","); - space_if_not_bol(s); - print_expr(s, expr); - pclose(s); - } - } - } - ast::expr_check(m, expr) { - alt m { - ast::claimed_expr { word_nbsp(s, "claim"); } - ast::checked_expr { word_nbsp(s, "check"); } - } - popen(s); - print_expr(s, expr); - pclose(s); - } - ast::expr_assert(expr) { - word_nbsp(s, "assert"); - print_expr(s, expr); - } - ast::expr_mac(m) { print_mac(s, m); } - } - s.ann.post(ann_node); - end(s); -} - -fn print_expr_parens_if_not_bot(s: ps, ex: @ast::expr) { - let parens = alt ex.node { - ast::expr_fail(_) | ast::expr_ret(_) | - ast::expr_binary(_, _, _) | ast::expr_unary(_, _) | - ast::expr_move(_, _) | ast::expr_copy(_) | - ast::expr_assign(_, _) | ast::expr_be(_) | - ast::expr_assign_op(_, _, _) | ast::expr_swap(_, _) | - ast::expr_log(_, _, _) | ast::expr_assert(_) | - ast::expr_call(_, _, true) | - ast::expr_check(_, _) { true } - _ { false } - }; - if parens { popen(s); } - print_expr(s, ex); - if parens { pclose(s); } -} - -fn print_local_decl(s: ps, loc: @ast::local) { - print_pat(s, loc.node.pat); - alt loc.node.ty.node { - ast::ty_infer { } - _ { word_space(s, ":"); print_type(s, loc.node.ty); } - } -} - -fn print_decl(s: ps, decl: @ast::decl) { - maybe_print_comment(s, decl.span.lo); - alt decl.node { - ast::decl_local(locs) { - space_if_not_bol(s); - ibox(s, indent_unit); - word_nbsp(s, "let"); - fn print_local(s: ps, &&loc: @ast::local) { - ibox(s, indent_unit); - print_local_decl(s, loc); - end(s); - alt loc.node.init { - some(init) { - nbsp(s); - alt init.op { - ast::init_assign { word_space(s, "="); } - ast::init_move { word_space(s, "<-"); } - } - print_expr(s, init.expr); - } - _ { } - } - } - commasep(s, consistent, locs, print_local); - end(s); - } - ast::decl_item(item) { print_item(s, item); } - } -} - -fn print_ident(s: ps, ident: ast::ident) { word(s.s, ident); } - -fn print_for_decl(s: ps, loc: @ast::local, coll: @ast::expr) { - print_local_decl(s, loc); - space(s.s); - word_space(s, "in"); - print_expr(s, coll); -} - -fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) { - maybe_print_comment(s, path.span.lo); - if path.node.global { word(s.s, "::"); } - let first = true; - for id: ast::ident in path.node.idents { - if first { first = false; } else { word(s.s, "::"); } - word(s.s, id); - } - if vec::len(path.node.types) > 0u { - if colons_before_params { word(s.s, "::"); } - word(s.s, "<"); - commasep(s, inconsistent, path.node.types, print_type); - word(s.s, ">"); - } -} - -fn print_pat(s: ps, &&pat: @ast::pat) { - maybe_print_comment(s, pat.span.lo); - let ann_node = node_pat(s, pat); - s.ann.pre(ann_node); - /* Pat isn't normalized, but the beauty of it - is that it doesn't matter */ - alt pat.node { - ast::pat_wild { word(s.s, "_"); } - ast::pat_ident(path, sub) { - print_path(s, path, true); - alt sub { - some(p) { word(s.s, "@"); print_pat(s, p); } - _ {} - } - } - ast::pat_enum(path, args) { - print_path(s, path, true); - if vec::len(args) > 0u { - popen(s); - commasep(s, inconsistent, args, print_pat); - pclose(s); - } else { } - } - ast::pat_rec(fields, etc) { - word(s.s, "{"); - fn print_field(s: ps, f: ast::field_pat) { - cbox(s, indent_unit); - word(s.s, f.ident); - word_space(s, ":"); - print_pat(s, f.pat); - end(s); - } - fn get_span(f: ast::field_pat) -> codemap::span { ret f.pat.span; } - commasep_cmnt(s, consistent, fields, print_field, get_span); - if etc { - if vec::len(fields) != 0u { word_space(s, ","); } - word(s.s, "_"); - } - word(s.s, "}"); - } - ast::pat_tup(elts) { - popen(s); - commasep(s, inconsistent, elts, print_pat); - pclose(s); - } - ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); } - ast::pat_uniq(inner) { word(s.s, "~"); print_pat(s, inner); } - ast::pat_lit(e) { print_expr(s, e); } - ast::pat_range(begin, end) { - print_expr(s, begin); - space(s.s); - word_space(s, "to"); - print_expr(s, end); - } - } - s.ann.post(ann_node); -} - -fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident, - typarams: [ast::ty_param]) { - alt decl.purity { - ast::impure_fn { head(s, "fn"); } - ast::unsafe_fn { head(s, "unsafe fn"); } - ast::pure_fn { head(s, "pure fn"); } - ast::crust_fn { head(s, "crust fn"); } - } - word(s.s, name); - print_type_params(s, typarams); - print_fn_args_and_ret(s, decl); -} - -fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) { - fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) { - word(s.s, cap_item.name); - } - - let has_copies = vec::is_not_empty(cap_clause.copies); - let has_moves = vec::is_not_empty(cap_clause.moves); - if !has_copies && !has_moves { ret; } - - word(s.s, "["); - - if has_copies { - word_nbsp(s, "copy"); - commasep(s, inconsistent, cap_clause.copies, print_cap_item); - if has_moves { - word_space(s, ";"); - } - } - - if has_moves { - word_nbsp(s, "move"); - commasep(s, inconsistent, cap_clause.moves, print_cap_item); - } - - word(s.s, "]"); -} - -fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) { - popen(s); - fn print_arg(s: ps, x: ast::arg) { - ibox(s, indent_unit); - print_arg_mode(s, x.mode); - word_space(s, x.ident + ":"); - print_type(s, x.ty); - end(s); - } - commasep(s, inconsistent, decl.inputs, print_arg); - pclose(s); - word(s.s, constrs_str(decl.constraints, {|c| - ast_fn_constr_to_str(decl, c) - })); - - maybe_print_comment(s, decl.output.span.lo); - if decl.output.node != ast::ty_nil { - space_if_not_bol(s); - word_space(s, "->"); - print_type(s, decl.output); - } -} - -fn print_fn_block_args(s: ps, decl: ast::fn_decl) { - word(s.s, "|"); - fn print_arg(s: ps, x: ast::arg) { - ibox(s, indent_unit); - print_arg_mode(s, x.mode); - word(s.s, x.ident); - end(s); - } - commasep(s, inconsistent, decl.inputs, print_arg); - word(s.s, "|"); - if decl.output.node != ast::ty_infer { - space_if_not_bol(s); - word_space(s, "->"); - print_type(s, decl.output); - } - maybe_print_comment(s, decl.output.span.lo); -} - -fn mode_to_str(m: ast::mode) -> str { - alt m { - ast::expl(ast::by_mutbl_ref) { "&" } - ast::expl(ast::by_move) { "-" } - ast::expl(ast::by_ref) { "&&" } - ast::expl(ast::by_val) { "++" } - ast::expl(ast::by_copy) { "+" } - ast::infer(_) { "" } - } -} - -fn print_arg_mode(s: ps, m: ast::mode) { - let ms = mode_to_str(m); - if ms != "" { word(s.s, ms); } -} - -fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) { - if vec::len(*bounds) > 0u { - word(s.s, ":"); - for bound in *bounds { - nbsp(s); - alt bound { - ast::bound_copy { word(s.s, "copy"); } - ast::bound_send { word(s.s, "send"); } - ast::bound_iface(t) { print_type(s, t); } - } - } - } -} - -fn print_type_params(s: ps, &¶ms: [ast::ty_param]) { - if vec::len(params) > 0u { - word(s.s, "<"); - fn printParam(s: ps, param: ast::ty_param) { - word(s.s, param.ident); - print_bounds(s, param.bounds); - } - commasep(s, inconsistent, params, printParam); - word(s.s, ">"); - } -} - -fn print_meta_item(s: ps, &&item: @ast::meta_item) { - ibox(s, indent_unit); - alt item.node { - ast::meta_word(name) { word(s.s, name); } - ast::meta_name_value(name, value) { - word_space(s, name); - word_space(s, "="); - print_literal(s, @value); - } - ast::meta_list(name, items) { - word(s.s, name); - popen(s); - commasep(s, consistent, items, print_meta_item); - pclose(s); - } - } - end(s); -} - -fn print_simple_path(s: ps, path: ast::simple_path) { - let first = true; - for id in path { - if first { first = false; } else { word(s.s, "::"); } - word(s.s, id); - } -} - -fn print_view_path(s: ps, &&vp: @ast::view_path) { - alt vp.node { - ast::view_path_simple(ident, path, _) { - if path[vec::len(*path)-1u] != ident { - word_space(s, ident); - word_space(s, "="); - } - print_simple_path(s, *path); - } - - ast::view_path_glob(path, _) { - print_simple_path(s, *path); - word(s.s, "::*"); - } - - ast::view_path_list(path, idents, _) { - print_simple_path(s, *path); - word(s.s, "::{"); - commasep(s, inconsistent, idents) {|s, w| - word(s.s, w.node.name) - } - word(s.s, "}"); - } - } -} - -fn print_view_paths(s: ps, vps: [@ast::view_path]) { - commasep(s, inconsistent, vps, print_view_path); -} - -fn print_view_item(s: ps, item: @ast::view_item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - alt item.node { - ast::view_item_use(id, mta, _) { - head(s, "use"); - word(s.s, id); - if vec::len(mta) > 0u { - popen(s); - commasep(s, consistent, mta, print_meta_item); - pclose(s); - } - } - - ast::view_item_import(vps) { - head(s, "import"); - print_view_paths(s, vps); - } - - ast::view_item_export(vps) { - head(s, "export"); - print_view_paths(s, vps); - } - } - word(s.s, ";"); - end(s); // end inner head-block - end(s); // end outer head-block -} - - -// FIXME: The fact that this builds up the table anew for every call is -// not good. Eventually, table should be a const. -fn operator_prec(op: ast::binop) -> int { - for spec: parse::parser::op_spec in *parse::parser::prec_table() { - if spec.op == op { ret spec.prec; } - } - fail; -} - -fn need_parens(expr: @ast::expr, outer_prec: int) -> bool { - alt expr.node { - ast::expr_binary(op, _, _) { operator_prec(op) < outer_prec } - ast::expr_cast(_, _) { parse::parser::as_prec < outer_prec } - // This may be too conservative in some cases - ast::expr_assign(_, _) { true } - ast::expr_move(_, _) { true } - ast::expr_swap(_, _) { true } - ast::expr_assign_op(_, _, _) { true } - ast::expr_ret(_) { true } - ast::expr_be(_) { true } - ast::expr_assert(_) { true } - ast::expr_check(_, _) { true } - ast::expr_log(_, _, _) { true } - _ { !parse::parser::expr_requires_semi_to_be_stmt(expr) } - } -} - -fn print_op_maybe_parens(s: ps, expr: @ast::expr, outer_prec: int) { - let add_them = need_parens(expr, outer_prec); - if add_them { popen(s); } - print_expr(s, expr); - if add_them { pclose(s); } -} - -fn print_mutability(s: ps, mutbl: ast::mutability) { - alt mutbl { - ast::m_mutbl { word_nbsp(s, "mutable"); } - ast::m_const { word_nbsp(s, "const"); } - ast::m_imm {/* nothing */ } - } -} - -fn print_mt(s: ps, mt: ast::mt) { - print_mutability(s, mt.mutbl); - print_type(s, mt.ty); -} - -fn print_ty_fn(s: ps, opt_proto: option<ast::proto>, - decl: ast::fn_decl, id: option<ast::ident>, - tps: option<[ast::ty_param]>) { - ibox(s, indent_unit); - word(s.s, opt_proto_to_str(opt_proto)); - alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } } - alt tps { some(tps) { print_type_params(s, tps); } _ { } } - zerobreak(s.s); - popen(s); - fn print_arg(s: ps, input: ast::arg) { - print_arg_mode(s, input.mode); - if str::len(input.ident) > 0u { - word_space(s, input.ident + ":"); - } - print_type(s, input.ty); - } - commasep(s, inconsistent, decl.inputs, print_arg); - pclose(s); - maybe_print_comment(s, decl.output.span.lo); - if decl.output.node != ast::ty_nil { - space_if_not_bol(s); - ibox(s, indent_unit); - word_space(s, "->"); - if decl.cf == ast::noreturn { word_nbsp(s, "!"); } - else { print_type(s, decl.output); } - end(s); - } - word(s.s, constrs_str(decl.constraints, ast_ty_fn_constr_to_str)); - end(s); -} - -fn maybe_print_trailing_comment(s: ps, span: codemap::span, - next_pos: option<uint>) { - let cm; - alt s.cm { some(ccm) { cm = ccm; } _ { ret; } } - alt next_comment(s) { - some(cmnt) { - if cmnt.style != lexer::trailing { ret; } - let span_line = codemap::lookup_char_pos(cm, span.hi); - let comment_line = codemap::lookup_char_pos(cm, cmnt.pos); - let next = cmnt.pos + 1u; - alt next_pos { none { } some(p) { next = p; } } - if span.hi < cmnt.pos && cmnt.pos < next && - span_line.line == comment_line.line { - print_comment(s, cmnt); - s.cur_cmnt += 1u; - } - } - _ { } - } -} - -fn print_remaining_comments(s: ps) { - // If there aren't any remaining comments, then we need to manually - // make sure there is a line break at the end. - if option::is_none(next_comment(s)) { hardbreak(s.s); } - while true { - alt next_comment(s) { - some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; } - _ { break; } - } - } -} - -fn in_cbox(s: ps) -> bool { - let len = vec::len(s.boxes); - if len == 0u { ret false; } - ret s.boxes[len - 1u] == pp::consistent; -} - -fn print_literal(s: ps, &&lit: @ast::lit) { - maybe_print_comment(s, lit.span.lo); - alt next_lit(s, lit.span.lo) { - some(lt) { - word(s.s, lt.lit); - ret; - } - _ {} - } - alt lit.node { - ast::lit_str(st) { print_string(s, st); } - ast::lit_int(ch, ast::ty_char) { - word(s.s, "'" + escape_str(str::from_char(ch as char), '\'') + "'"); - } - ast::lit_int(i, t) { - if i < 0_i64 { - word(s.s, - "-" + u64::to_str(-i as u64, 10u) - + ast_util::int_ty_to_str(t)); - } else { - word(s.s, - u64::to_str(i as u64, 10u) - + ast_util::int_ty_to_str(t)); - } - } - ast::lit_uint(u, t) { - word(s.s, - u64::to_str(u, 10u) - + ast_util::uint_ty_to_str(t)); - } - ast::lit_float(f, t) { - word(s.s, f + ast_util::float_ty_to_str(t)); - } - ast::lit_nil { word(s.s, "()"); } - ast::lit_bool(val) { - if val { word(s.s, "true"); } else { word(s.s, "false"); } - } - } -} - -fn lit_to_str(l: @ast::lit) -> str { be to_str(l, print_literal); } - -fn next_lit(s: ps, pos: uint) -> option<lexer::lit> { - alt s.literals { - some(lits) { - while s.cur_lit < vec::len(lits) { - let lt = lits[s.cur_lit]; - if lt.pos > pos { ret none; } - s.cur_lit += 1u; - if lt.pos == pos { ret some(lt); } - } - ret none; - } - _ { ret none; } - } -} - -fn maybe_print_comment(s: ps, pos: uint) { - while true { - alt next_comment(s) { - some(cmnt) { - if cmnt.pos < pos { - print_comment(s, cmnt); - s.cur_cmnt += 1u; - } else { break; } - } - _ { break; } - } - } -} - -fn print_comment(s: ps, cmnt: lexer::cmnt) { - alt cmnt.style { - lexer::mixed { - assert (vec::len(cmnt.lines) == 1u); - zerobreak(s.s); - word(s.s, cmnt.lines[0]); - zerobreak(s.s); - } - lexer::isolated { - pprust::hardbreak_if_not_bol(s); - for line: str in cmnt.lines { - // Don't print empty lines because they will end up as trailing - // whitespace - if str::is_not_empty(line) { word(s.s, line); } - hardbreak(s.s); - } - } - lexer::trailing { - word(s.s, " "); - if vec::len(cmnt.lines) == 1u { - word(s.s, cmnt.lines[0]); - hardbreak(s.s); - } else { - ibox(s, 0u); - for line: str in cmnt.lines { - if str::is_not_empty(line) { word(s.s, line); } - hardbreak(s.s); - } - end(s); - } - } - lexer::blank_line { - // We need to do at least one, possibly two hardbreaks. - let is_semi = - alt s.s.last_token() { - pp::STRING(s, _) { s == ";" } - _ { false } - }; - if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); } - hardbreak(s.s); - } - } -} - -fn print_string(s: ps, st: str) { - word(s.s, "\""); - word(s.s, escape_str(st, '"')); - word(s.s, "\""); -} - -fn escape_str(st: str, to_escape: char) -> str { - let out: str = ""; - let len = str::len(st); - let i = 0u; - while i < len { - alt st[i] as char { - '\n' { out += "\\n"; } - '\t' { out += "\\t"; } - '\r' { out += "\\r"; } - '\\' { out += "\\\\"; } - cur { - if cur == to_escape { out += "\\"; } - // FIXME some (or all?) non-ascii things should be escaped - - str::push_char(out, cur); - } - } - i += 1u; - } - ret out; -} - -fn to_str<T>(t: T, f: fn@(ps, T)) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - f(s, t); - eof(s.s); - io::mem_buffer_str(buffer) -} - -fn next_comment(s: ps) -> option<lexer::cmnt> { - alt s.comments { - some(cmnts) { - if s.cur_cmnt < vec::len(cmnts) { - ret some(cmnts[s.cur_cmnt]); - } else { ret none::<lexer::cmnt>; } - } - _ { ret none::<lexer::cmnt>; } - } -} - -fn constr_args_to_str<T>(f: fn@(T) -> str, args: [@ast::sp_constr_arg<T>]) -> - str { - let comma = false; - let s = "("; - for a: @ast::sp_constr_arg<T> in args { - if comma { s += ", "; } else { comma = true; } - s += constr_arg_to_str::<T>(f, a.node); - } - s += ")"; - ret s; -} - -fn constr_arg_to_str<T>(f: fn@(T) -> str, c: ast::constr_arg_general_<T>) -> - str { - alt c { - ast::carg_base { ret "*"; } - ast::carg_ident(i) { ret f(i); } - ast::carg_lit(l) { ret lit_to_str(l); } - } -} - -// needed b/c constr_args_to_str needs -// something that takes an alias -// (argh) -fn uint_to_str(&&i: uint) -> str { ret uint::str(i); } - -fn ast_ty_fn_constr_to_str(&&c: @ast::constr) -> str { - ret path_to_str(c.node.path) + - constr_args_to_str(uint_to_str, c.node.args); -} - -fn ast_fn_constr_to_str(decl: ast::fn_decl, &&c: @ast::constr) -> str { - let arg_to_str = bind fn_arg_idx_to_str(decl, _); - ret path_to_str(c.node.path) + - constr_args_to_str(arg_to_str, c.node.args); -} - -fn ty_constr_to_str(&&c: @ast::ty_constr) -> str { - fn ty_constr_path_to_str(&&p: @ast::path) -> str { "*." + path_to_str(p) } - - ret path_to_str(c.node.path) + - constr_args_to_str::<@ast::path>(ty_constr_path_to_str, - c.node.args); -} - -fn constrs_str<T>(constrs: [T], elt: fn(T) -> str) -> str { - let s = "", colon = true; - for c in constrs { - if colon { s += " : "; colon = false; } else { s += ", "; } - s += elt(c); - } - ret s; -} - -fn fn_arg_idx_to_str(decl: ast::fn_decl, &&idx: uint) -> str { - decl.inputs[idx].ident -} - -fn opt_proto_to_str(opt_p: option<ast::proto>) -> str { - alt opt_p { - none { "fn" } - some(p) { proto_to_str(p) } - } -} - -fn proto_to_str(p: ast::proto) -> str { - ret alt p { - ast::proto_bare { "native fn" } - ast::proto_any { "fn" } - ast::proto_block { "fn&" } - ast::proto_uniq { "fn~" } - ast::proto_box { "fn@" } - }; -} - -fn ends_in_lit_int(ex: @ast::expr) -> bool { - alt ex.node { - ast::expr_lit(@{node: ast::lit_int(_, ast::ty_i), _}) { true } - ast::expr_binary(_, _, sub) | ast::expr_unary(_, sub) | - ast::expr_move(_, sub) | ast::expr_copy(sub) | - ast::expr_assign(_, sub) | ast::expr_be(sub) | - ast::expr_assign_op(_, _, sub) | ast::expr_swap(_, sub) | - ast::expr_log(_, _, sub) | ast::expr_assert(sub) | - ast::expr_check(_, sub) { ends_in_lit_int(sub) } - ast::expr_fail(osub) | ast::expr_ret(osub) { - alt osub { - some(ex) { ends_in_lit_int(ex) } - _ { false } - } - } - _ { false } - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// |
