diff options
Diffstat (limited to 'src/libsyntax/print/pprust.rs')
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 1861 |
1 files changed, 1861 insertions, 0 deletions
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs new file mode 100644 index 00000000000..8206bfd2a4a --- /dev/null +++ b/src/libsyntax/print/pprust.rs @@ -0,0 +1,1861 @@ +import parse::classify::*; +import parse::comments; +import parse::lexer; +import codemap::codemap; +import pp::{break_offset, word, printer, + space, zerobreak, hardbreak, breaks, consistent, + inconsistent, eof}; +import diagnostic; +import ast_util::operator_prec; +import dvec::{dvec, extensions}; + +// 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<[comments::cmnt]>, + literals: option<[comments::lit]>, + mut cur_cmnt: uint, + mut cur_lit: uint, + boxes: dvec<pp::breaks>, + ann: pp_ann}; + +fn ibox(s: ps, u: uint) { + s.boxes.push(pp::inconsistent); + pp::ibox(s.s, u); +} + +fn end(s: ps) { + s.boxes.pop(); + pp::end(s.s); +} + +fn rust_printer(writer: io::writer) -> ps { + ret @{s: pp::mk_printer(writer, default_columns), + cm: none::<codemap>, + comments: none::<[comments::cmnt]>, + literals: none::<[comments::lit]>, + mut cur_cmnt: 0u, + mut cur_lit: 0u, + boxes: dvec(), + 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 r = comments::gather_comments_and_literals(span_diagnostic, + filename, in); + let s = + @{s: pp::mk_printer(out, default_columns), + cm: some(cm), + comments: some(r.cmnts), + literals: some(r.lits), + mut cur_cmnt: 0u, + mut cur_lit: 0u, + boxes: dvec(), + 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 { ret to_str(ty, print_type); } + +fn pat_to_str(pat: @ast::pat) -> str { ret to_str(pat, print_pat); } + +fn expr_to_str(e: @ast::expr) -> str { ret to_str(e, print_expr); } + +fn stmt_to_str(s: ast::stmt) -> str { ret to_str(s, print_stmt); } + +fn item_to_str(i: @ast::item) -> str { ret to_str(i, print_item); } + +fn attr_to_str(i: ast::attribute) -> str { ret to_str(i, print_attribute); } + +fn typarams_to_str(tps: [ast::ty_param]) -> str { + ret to_str(tps, print_type_params) +} + +fn path_to_str(&&p: @ast::path) -> str { + ret 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::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: @{id: 0, + node: ast::ty_nil, + span: ast_util::dummy_sp()}, + 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], rp: ast::region_param) -> str { + let buffer = io::mem_buffer(); + let s = rust_printer(io::mem_buffer_writer(buffer)); + print_res(s, decl, name, params, rp); + 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: @{id: 0, + node: ast::ty_nil, + span: ast_util::dummy_sp()}, + ident: "b", + id: 0 + }], + output: @{id: 0, + node: ast::ty_nil, + span: ast_util::dummy_sp()}, + 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::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 { + ret to_str(attr, print_attribute); +} + +fn variant_to_str(var: ast::variant) -> str { + ret 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.push(pp::consistent); + pp::cbox(s.s, u); +} + +fn box(s: ps, u: uint, b: pp::breaks) { + s.boxes.push(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 in_cbox(s: ps) -> bool { + let len = s.boxes.len(); + if len == 0u { ret false; } + ret s.boxes[len - 1u] == pp::consistent; +} + +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 mut first = true; + for elts.each {|elt| + 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 mut i = 0u; + for elts.each {|elt| + 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 _mod.view_items.each {|vitem| + print_view_item(s, vitem); + } + for _mod.items.each {|item| print_item(s, item); } +} + +fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) { + print_inner_attributes(s, attrs); + for nmod.view_items.each {|vitem| + print_view_item(s, vitem); + } + for nmod.items.each {|item| print_native_item(s, item); } +} + +fn print_region(s: ps, region: @ast::region) { + alt region.node { + ast::re_anon { word_space(s, "&"); } + ast::re_named(name) { + word(s.s, "&"); + word_space(s, name); + } + } +} + +fn print_type(s: ps, &&ty: @ast::ty) { + print_type_ex(s, ty, false); +} + +fn print_type_ex(s: ps, &&ty: @ast::ty, print_colons: bool) { + 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_rptr(region, mt) { + alt region.node { + ast::re_anon { word(s.s, "&"); } + _ { print_region(s, region); 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, print_colons); } + ast::ty_constr(t, cs) { + print_type(s, t); + space(s.s); + word(s.s, constrs_str(cs, ty_constr_to_str)); + } + ast::ty_vstore(t, v) { + print_type(s, t); + print_vstore(s, v); + } + 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, rp) { + ibox(s, indent_unit); + ibox(s, 0u); + word_nbsp(s, "type"); + word(s.s, item.ident); + print_region_param(s, rp); + 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, rp) { + 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_region_param(s, rp); + 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 variants.each {|v| + 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, ifaces, items, ctor, m_dtor, rp) { + head(s, "class"); + word_nbsp(s, item.ident); + print_region_param(s, rp); + print_type_params(s, tps); + word_space(s, "implements"); + commasep(s, inconsistent, ifaces, {|s, p| + print_path(s, p.path, false)}); + bopen(s); + hardbreak_if_not_bol(s); + maybe_print_comment(s, ctor.span.lo); + head(s, "new"); + print_fn_args_and_ret(s, ctor.node.dec, []); + space(s.s); + print_block(s, ctor.node.body); + option::iter(m_dtor) {|dtor| + hardbreak_if_not_bol(s); + head(s, "drop"); + print_block(s, dtor.node.body); + } + for items.each {|ci| + /* + FIXME: collect all private items and print them + in a single "priv" section + + tjc: I'm not going to fix this yet b/c we might + change how exports work, including for class items + (see #1893) + */ + hardbreak_if_not_bol(s); + maybe_print_comment(s, ci.span.lo); + let pr = ast_util::class_member_visibility(ci); + alt pr { + ast::private { + head(s, "priv"); + bopen(s); + hardbreak_if_not_bol(s); + } + _ {} + } + alt ci.node { + ast::instance_var(nm, t, mt, _,_) { + word_nbsp(s, "let"); + alt mt { + ast::class_mutable { word_nbsp(s, "mut"); } + _ {} + } + word(s.s, nm); + word_nbsp(s, ":"); + print_type(s, t); + word(s.s, ";"); + } + ast::class_method(m) { + print_method(s, m); + } + } + alt pr { + ast::private { bclose(s, ci.span); } + _ {} + } + } + bclose(s, item.span); + } + ast::item_impl(tps, rp, ifce, ty, methods) { + head(s, "impl"); + word(s.s, item.ident); + print_region_param(s, rp); + print_type_params(s, tps); + space(s.s); + option::iter(ifce, {|p| + word_nbsp(s, "of"); + print_path(s, p.path, false); + space(s.s); + }); + word_nbsp(s, "for"); + print_type(s, ty); + space(s.s); + bopen(s); + for methods.each {|meth| + print_method(s, meth); + } + bclose(s, item.span); + } + ast::item_iface(tps, rp, methods) { + head(s, "iface"); + word(s.s, item.ident); + print_region_param(s, rp); + print_type_params(s, tps); + word(s.s, " "); + bopen(s); + for methods.each {|meth| print_ty_method(s, meth); } + bclose(s, item.span); + } + ast::item_res(decl, tps, body, dt_id, ct_id, rp) { + print_res(s, decl, item.ident, tps, rp); + 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], rp: ast::region_param) { + head(s, "resource"); + word(s.s, name); + print_region_param(s, rp); + 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_method(s: ps, meth: @ast::method) { + 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); +} + +fn print_outer_attributes(s: ps, attrs: [ast::attribute]) { + let mut count = 0; + for attrs.each {|attr| + 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 mut count = 0; + for attrs.each {|attr| + 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::classify::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 blk.node.view_items.each {|vi| print_view_item(s, vi); } + for blk.node.stmts.each {|st| + 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::iter(arg, bind print_expr(s, _)); + // FIXME: extension 'body' (#2339) + } + 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_vstore(s: ps, t: ast::vstore) { + alt t { + ast::vstore_fixed(some(i)) { word_space(s, #fmt("/%u", i)); } + ast::vstore_fixed(none) { word_space(s, "/_"); } + ast::vstore_uniq { word_space(s, "/~"); } + ast::vstore_box { word_space(s, "/@"); } + ast::vstore_slice(r) { word(s.s, "/"); print_region(s, r); } + } +} + +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_vstore(e, v) { + print_expr(s, e); + print_vstore(s, v); + } + ast::expr_vec(exprs, mutbl) { + ibox(s, indent_unit); + word(s.s, "["); + if mutbl == ast::m_mutbl { + word(s.s, "mut"); + 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, "mut"); } + 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) { + let mut base_args = args; + let blk = if has_block { + let blk_arg = vec::pop(base_args); + alt blk_arg.node { + ast::expr_loop_body(_) { word_nbsp(s, "for"); } + _ {} + } + some(blk_arg) + } else { none }; + print_expr_parens_if_not_bot(s, func); + 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 + 1u); + } + ast::expr_unary(op, expr) { + word(s.s, ast_util::unop_to_str(op)); + print_op_maybe_parens(s, expr, parse::prec::unop_prec); + } + ast::expr_addr_of(m, expr) { + word(s.s, "&"); + print_mutability(s, m); + print_expr(s, expr); + } + ast::expr_lit(lit) { print_literal(s, lit); } + ast::expr_cast(expr, ty) { + print_op_maybe_parens(s, expr, parse::prec::as_prec); + space(s.s); + word_space(s, "as"); + print_type_ex(s, ty, true); + } + 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_loop(blk) { + head(s, "loop"); + space(s.s); + print_block(s, blk); + } + 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 arms.each {|arm| + space(s.s); + cbox(s, alt_indent_unit); + ibox(s, 0u); + let mut first = true; + for arm.pats.each {|p| + 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); + print_purity(s, decl.purity); + word(s.s, proto_to_str(proto)); + print_fn_args_and_ret(s, decl, *cap_clause); + space(s.s); + print_block(s, body); + } + ast::expr_fn_block(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, "{"); + print_fn_block_args(s, decl, *cap_clause); + print_possibly_embedded_block(s, body, block_block_fn, indent_unit); + } + ast::expr_loop_body(body) { + print_expr(s, body); + } + 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_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_new(p, _, v) { + word_nbsp(s, "new"); + popen(s); + print_expr(s, p); + pclose(s); + print_expr(s, v); + } + 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_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"); + + // if any are mut, all are mut + if vec::any(locs) {|l| l.node.is_mutbl } { + assert vec::all(locs) {|l| l.node.is_mutbl }; + word_nbsp(s, "mut"); + } + + 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.global { word(s.s, "::"); } + let mut first = true; + for path.idents.each {|id| + if first { first = false; } else { word(s.s, "::"); } + word(s.s, id); + } + if path.rp.is_some() || !path.types.is_empty() { + if colons_before_params { word(s.s, "::"); } + + alt path.rp { + none { /* ok */ } + some(r) { + word(s.s, "/"); + print_region(s, r); + } + } + + if !path.types.is_empty() { + word(s.s, "<"); + commasep(s, inconsistent, path.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); } + none {} + } + } + ast::pat_enum(path, args_) { + print_path(s, path, true); + alt args_ { + none { word(s.s, "(*)"); } + some(args) { + 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") } + _ { head(s, purity_to_str(decl.purity) + " fn") } + } + word(s.s, name); + print_type_params(s, typarams); + print_fn_args_and_ret(s, decl, []); +} + +fn print_fn_args(s: ps, decl: ast::fn_decl, + cap_items: [ast::capture_item]) { + commasep(s, inconsistent, decl.inputs, print_arg); + if cap_items.is_not_empty() { + let mut first = decl.inputs.is_empty(); + for cap_items.each { |cap_item| + if first { first = false; } else { word_space(s, ","); } + if cap_item.is_move { word_nbsp(s, "move") } + else { word_nbsp(s, "copy") } + word(s.s, cap_item.name); + } + } +} + +fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl, + cap_items: [ast::capture_item]) { + popen(s); + print_fn_args(s, decl, cap_items); + 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, + cap_items: [ast::capture_item]) { + word(s.s, "|"); + print_fn_args(s, decl, cap_items); + 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 vec::each(*bounds) {|bound| + nbsp(s); + alt bound { + ast::bound_copy { word(s.s, "copy"); } + ast::bound_send { word(s.s, "send"); } + ast::bound_const { word(s.s, "const"); } + ast::bound_iface(t) { print_type(s, t); } + } + } + } +} + +fn print_region_param(s: ps, rp: ast::region_param) { + alt rp { + ast::rp_self { word(s.s, "/&") } + ast::rp_none { } + } +} + +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_view_path(s: ps, &&vp: @ast::view_path) { + alt vp.node { + ast::view_path_simple(ident, path, _) { + if path.idents[vec::len(path.idents)-1u] != ident { + word_space(s, ident); + word_space(s, "="); + } + print_path(s, path, false); + } + + ast::view_path_glob(path, _) { + print_path(s, path, false); + word(s.s, "::*"); + } + + ast::view_path_list(path, idents, _) { + print_path(s, path, false); + 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 +} + +fn print_op_maybe_parens(s: ps, expr: @ast::expr, outer_prec: uint) { + 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, "mut"); } + 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_arg(s: ps, input: ast::arg) { + ibox(s, indent_unit); + print_arg_mode(s, input.mode); + alt input.ty.node { + ast::ty_infer { + word(s.s, input.ident); + } + _ { + if str::len(input.ident) > 0u { + word_space(s, input.ident + ":"); + } + print_type(s, input.ty); + } + } + end(s); +} + +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); + 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 mut cm; + alt s.cm { some(ccm) { cm = ccm; } _ { ret; } } + alt next_comment(s) { + some(cmnt) { + if cmnt.style != comments::trailing { ret; } + let span_line = codemap::lookup_char_pos(cm, span.hi); + let comment_line = codemap::lookup_char_pos(cm, cmnt.pos); + let mut 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); } + loop { + alt next_comment(s) { + some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; } + _ { break; } + } + } +} + +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 { ret to_str(l, print_literal); } + +fn next_lit(s: ps, pos: uint) -> option<comments::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) { + loop { + 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: comments::cmnt) { + alt cmnt.style { + comments::mixed { + assert (vec::len(cmnt.lines) == 1u); + zerobreak(s.s); + word(s.s, cmnt.lines[0]); + zerobreak(s.s); + } + comments::isolated { + pprust::hardbreak_if_not_bol(s); + for cmnt.lines.each {|line| + // 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); + } + } + comments::trailing { + word(s.s, " "); + if vec::len(cmnt.lines) == 1u { + word(s.s, cmnt.lines[0]); + hardbreak(s.s); + } else { + ibox(s, 0u); + for cmnt.lines.each {|line| + if str::is_not_empty(line) { word(s.s, line); } + hardbreak(s.s); + } + end(s); + } + } + comments::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 mut out: str = ""; + let len = str::len(st); + let mut 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 + // (See #2306) + str::push_char(out, cur); + } + } + i += 1u; + } + ret out; +} + +fn to_str<T>(t: T, f: fn@(ps, T)) -> str { + let buffer = io::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<comments::cmnt> { + alt s.comments { + some(cmnts) { + if s.cur_cmnt < vec::len(cmnts) { + ret some(cmnts[s.cur_cmnt]); + } else { ret none::<comments::cmnt>; } + } + _ { ret none::<comments::cmnt>; } + } +} + +fn constr_args_to_str<T>(f: fn@(T) -> str, args: [@ast::sp_constr_arg<T>]) -> + str { + let mut comma = false; + let mut s = "("; + for args.each {|a| + 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 mut s = "", colon = true; + for constrs.each {|c| + 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 purity_to_str(p: ast::purity) -> str { + alt p { + ast::impure_fn {"impure"} + ast::unsafe_fn {"unsafe"} + ast::pure_fn {"pure"} + ast::crust_fn {"crust"} + } +} + +fn print_purity(s: ps, p: ast::purity) { + alt p { + ast::impure_fn {} + _ { word_nbsp(s, purity_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@" } + }; +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: +// |
