2 import core::{vec, int, str, uint, option};
5 import syntax::codemap::codemap;
8 import option::{some, none};
9 import pp::{break_offset, word,
10 space, zerobreak, hardbreak, breaks, consistent,
13 // The ps is stored here to prevent recursive type.
14 // FIXME use a nominal tag instead
16 node_block(ps, ast::blk);
17 node_item(ps, @ast::item);
18 node_expr(ps, @ast::expr);
19 node_pat(ps, @ast::pat);
21 type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)};
23 fn no_ann() -> pp_ann {
24 fn ignore(_node: ann_node) { }
25 ret {pre: ignore, post: ignore};
30 cm: option::t<codemap>,
31 comments: option::t<[lexer::cmnt]>,
32 literals: option::t<[lexer::lit]>,
33 mutable cur_cmnt: uint,
34 mutable cur_lit: uint,
35 mutable boxes: [pp::breaks],
38 fn ibox(s: ps, u: uint) { s.boxes += [pp::inconsistent]; pp::ibox(s.s, u); }
40 fn end(s: ps) { vec::pop(s.boxes); pp::end(s.s); }
42 fn rust_printer(writer: io::writer) -> ps {
43 let boxes: [pp::breaks] = [];
44 ret @{s: pp::mk_printer(writer, default_columns),
46 comments: none::<[lexer::cmnt]>,
47 literals: none::<[lexer::lit]>,
54 const indent_unit: uint = 4u;
55 const alt_indent_unit: uint = 2u;
57 const default_columns: uint = 78u;
59 // Requires you to pass an input filename and reader so that
60 // it can scan the input text for comments and literals to
62 fn print_crate(cm: codemap, crate: @ast::crate, filename: str, in: io::reader,
63 out: io::writer, ann: pp_ann) {
64 let boxes: [pp::breaks] = [];
65 let r = lexer::gather_comments_and_literals(cm, filename, in);
67 @{s: pp::mk_printer(out, default_columns),
69 comments: some(r.cmnts),
70 literals: some(r.lits),
75 print_mod(s, crate.node.module, crate.node.attrs);
76 print_remaining_comments(s);
80 fn ty_to_str(ty: @ast::ty) -> str { be to_str(ty, print_type); }
82 fn pat_to_str(pat: @ast::pat) -> str { be to_str(pat, print_pat); }
84 fn expr_to_str(e: @ast::expr) -> str { be to_str(e, print_expr); }
86 fn stmt_to_str(s: ast::stmt) -> str { be to_str(s, print_stmt); }
88 fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); }
90 fn path_to_str(&&p: @ast::path) -> str {
91 be to_str(p, bind print_path(_, _, false));
94 fn fun_to_str(decl: ast::fn_decl, name: ast::ident,
95 params: [ast::ty_param]) -> str {
96 let writer = io::string_writer();
97 let s = rust_printer(writer.get_writer());
98 print_fn(s, decl, name, params);
100 ret writer.get_str();
103 fn block_to_str(blk: ast::blk) -> str {
104 let writer = io::string_writer();
105 let s = rust_printer(writer.get_writer());
106 // containing cbox, will be closed by print-block at }
108 cbox(s, indent_unit);
109 // head-ibox, will be closed by print-block after {
114 ret writer.get_str();
117 fn meta_item_to_str(mi: ast::meta_item) -> str {
118 ret to_str(@mi, print_meta_item);
121 fn attribute_to_str(attr: ast::attribute) -> str {
122 be to_str(attr, print_attribute);
125 fn cbox(s: ps, u: uint) { s.boxes += [pp::consistent]; pp::cbox(s.s, u); }
127 fn box(s: ps, u: uint, b: pp::breaks) { s.boxes += [b]; pp::box(s.s, u, b); }
129 fn nbsp(s: ps) { word(s.s, " "); }
131 fn word_nbsp(s: ps, w: str) { word(s.s, w); nbsp(s); }
133 fn word_space(s: ps, w: str) { word(s.s, w); space(s.s); }
135 fn popen(s: ps) { word(s.s, "("); }
137 fn pclose(s: ps) { word(s.s, ")"); }
139 fn head(s: ps, w: str) {
140 // outer-box is consistent
141 cbox(s, indent_unit);
142 // head-box is inconsistent
143 ibox(s, str::char_len(w) + 1u);
144 // keyword that starts the head
150 end(s); // close the head-box
153 fn bclose_(s: ps, span: codemap::span, indented: uint) {
154 maybe_print_comment(s, span.hi);
155 break_offset_if_not_bol(s, 1u, -(indented as int));
157 end(s); // close the outer-box
159 fn bclose(s: ps, span: codemap::span) { bclose_(s, span, indent_unit); }
161 fn is_begin(s: ps) -> bool {
162 alt s.s.last_token() { pp::BEGIN(_) { true } _ { false } }
165 fn is_end(s: ps) -> bool {
166 alt s.s.last_token() { pp::END. { true } _ { false } }
169 fn is_bol(s: ps) -> bool {
170 ret s.s.last_token() == pp::EOF ||
171 s.s.last_token() == pp::hardbreak_tok();
174 fn hardbreak_if_not_bol(s: ps) { if !is_bol(s) { hardbreak(s.s); } }
175 fn space_if_not_bol(s: ps) { if !is_bol(s) { space(s.s); } }
176 fn break_offset_if_not_bol(s: ps, n: uint, off: int) {
178 break_offset(s.s, n, off);
180 if off != 0 && s.s.last_token() == pp::hardbreak_tok() {
181 // We do something pretty sketchy here: tuck the nonzero
182 // offset-adjustment we were going to deposit along with the
183 // break into the previous hardbreak.
184 s.s.replace_last_token(pp::hardbreak_tok_offset(off));
189 // Synthesizes a comment that was not textually present in the original source
191 fn synth_comment(s: ps, text: str) {
199 fn commasep<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN)) {
202 for elt: IN in elts {
203 if first { first = false; } else { word_space(s, ","); }
210 fn commasep_cmnt<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN),
211 get_span: fn(IN) -> codemap::span) {
213 let len = vec::len::<IN>(elts);
215 for elt: IN in elts {
216 maybe_print_comment(s, get_span(elt).hi);
221 maybe_print_trailing_comment(s, get_span(elt),
222 some(get_span(elts[i]).hi));
229 fn commasep_exprs(s: ps, b: breaks, exprs: [@ast::expr]) {
230 fn expr_span(&&expr: @ast::expr) -> codemap::span { ret expr.span; }
231 commasep_cmnt(s, b, exprs, print_expr, expr_span);
234 fn print_mod(s: ps, _mod: ast::_mod, attrs: [ast::attribute]) {
235 print_inner_attributes(s, attrs);
236 for vitem: @ast::view_item in _mod.view_items {
237 print_view_item(s, vitem);
239 for item: @ast::item in _mod.items { print_item(s, item); }
242 fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
243 print_inner_attributes(s, attrs);
244 for vitem: @ast::view_item in nmod.view_items {
245 print_view_item(s, vitem);
247 for item: @ast::native_item in nmod.items { print_native_item(s, item); }
250 fn print_type(s: ps, &&ty: @ast::ty) {
251 maybe_print_comment(s, ty.span.lo);
254 ast::ty_nil. { word(s.s, "()"); }
255 ast::ty_bool. { word(s.s, "bool"); }
256 ast::ty_bot. { word(s.s, "!"); }
257 ast::ty_int(ast::ty_i.) { word(s.s, "int"); }
258 ast::ty_int(ast::ty_char.) { word(s.s, "char"); }
259 ast::ty_int(t) { word(s.s, ast_util::int_ty_to_str(t)); }
260 ast::ty_uint(ast::ty_u.) { word(s.s, "uint"); }
261 ast::ty_uint(t) { word(s.s, ast_util::uint_ty_to_str(t)); }
262 ast::ty_float(ast::ty_f.) { word(s.s, "float"); }
263 ast::ty_float(t) { word(s.s, ast_util::float_ty_to_str(t)); }
264 ast::ty_str. { word(s.s, "str"); }
265 ast::ty_box(mt) { word(s.s, "@"); print_mt(s, mt); }
266 ast::ty_uniq(mt) { word(s.s, "~"); print_mt(s, mt); }
270 ast::mut. { word_space(s, "mutable"); }
271 ast::maybe_mut. { word_space(s, "const"); }
274 print_type(s, mt.ty);
277 ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); }
278 ast::ty_task. { word(s.s, "task"); }
289 ast::ty_rec(fields) {
291 fn print_field(s: ps, f: ast::ty_field) {
292 cbox(s, indent_unit);
293 print_mutability(s, f.node.mt.mut);
294 word(s.s, f.node.ident);
296 print_type(s, f.node.mt.ty);
299 fn get_span(f: ast::ty_field) -> codemap::span { ret f.span; }
300 commasep_cmnt(s, consistent, fields, print_field, get_span);
305 commasep(s, inconsistent, elts, print_type);
308 ast::ty_fn(proto, d) {
309 print_ty_fn(s, proto, d, none, none);
311 ast::ty_obj(methods) {
314 for m in methods { print_ty_method(s, m); }
317 ast::ty_path(path, _) { print_path(s, path, false); }
318 ast::ty_type. { word(s.s, "type"); }
319 ast::ty_constr(t, cs) {
322 word(s.s, ast_ty_constrs_str(cs));
328 fn print_native_item(s: ps, item: @ast::native_item) {
329 hardbreak_if_not_bol(s);
330 maybe_print_comment(s, item.span.lo);
331 print_outer_attributes(s, item.attrs);
333 ast::native_item_ty. {
334 ibox(s, indent_unit);
336 word_nbsp(s, "type");
337 word(s.s, item.ident);
338 end(s); // end the inner ibox
340 end(s); // end the outer ibox
343 ast::native_item_fn(decl, typarams) {
344 print_fn(s, decl, item.ident, typarams);
345 end(s); // end head-ibox
347 end(s); // end the outer fn box
352 fn print_item(s: ps, &&item: @ast::item) {
353 hardbreak_if_not_bol(s);
354 maybe_print_comment(s, item.span.lo);
355 print_outer_attributes(s, item.attrs);
356 let ann_node = node_item(s, item);
359 ast::item_const(ty, expr) {
361 word_space(s, item.ident + ":");
364 end(s); // end the head-ibox
369 end(s); // end the outer cbox
372 ast::item_fn(decl, typarams, body) {
373 print_fn(s, decl, item.ident, typarams);
375 print_block(s, body);
377 ast::item_mod(_mod) {
379 word_nbsp(s, item.ident);
381 print_mod(s, _mod, item.attrs);
382 bclose(s, item.span);
384 ast::item_native_mod(nmod) {
387 word_nbsp(s, item.ident);
389 print_native_mod(s, nmod, item.attrs);
390 bclose(s, item.span);
392 ast::item_ty(ty, params) {
393 ibox(s, indent_unit);
395 word_nbsp(s, "type");
396 word(s.s, item.ident);
397 print_type_params(s, params);
398 end(s); // end the inner ibox
404 end(s); // end the outer ibox
406 ast::item_tag(variants, params) {
408 vec::len(variants) == 1u &&
409 str::eq(item.ident, variants[0].node.name) &&
410 vec::len(variants[0].node.args) == 1u;
412 ibox(s, indent_unit);
413 word_space(s, "tag");
414 } else { head(s, "tag"); }
415 word(s.s, item.ident);
416 print_type_params(s, params);
420 print_type(s, variants[0].node.args[0].ty);
425 for v: ast::variant in variants {
427 maybe_print_comment(s, v.span.lo);
428 word(s.s, v.node.name);
429 if vec::len(v.node.args) > 0u {
431 fn print_variant_arg(s: ps, arg: ast::variant_arg) {
432 print_type(s, arg.ty);
434 commasep(s, consistent, v.node.args, print_variant_arg);
438 maybe_print_trailing_comment(s, v.span, none::<uint>);
440 bclose(s, item.span);
443 ast::item_obj(_obj, params, _) {
445 word(s.s, item.ident);
446 print_type_params(s, params);
448 fn print_field(s: ps, field: ast::obj_field) {
449 ibox(s, indent_unit);
450 print_mutability(s, field.mut);
451 word_space(s, field.ident + ":");
452 print_type(s, field.ty);
455 fn get_span(f: ast::obj_field) -> codemap::span { ret f.ty.span; }
456 commasep_cmnt(s, consistent, _obj.fields, print_field, get_span);
460 for meth: @ast::method in _obj.methods {
461 hardbreak_if_not_bol(s);
462 maybe_print_comment(s, meth.span.lo);
463 print_fn(s, meth.decl, meth.ident, meth.tps);
465 print_block(s, meth.body);
467 bclose(s, item.span);
469 ast::item_impl(tps, ifce, ty, methods) {
471 word(s.s, item.ident);
472 print_type_params(s, tps);
486 for meth in methods {
487 hardbreak_if_not_bol(s);
488 maybe_print_comment(s, meth.span.lo);
489 print_fn(s, meth.decl, meth.ident, meth.tps);
491 print_block(s, meth.body);
493 bclose(s, item.span);
495 ast::item_iface(tps, methods) {
497 word(s.s, item.ident);
498 print_type_params(s, tps);
500 for meth in methods { print_ty_method(s, meth); }
501 bclose(s, item.span);
503 ast::item_res(decl, tps, body, dt_id, ct_id) {
505 word(s.s, item.ident);
506 print_type_params(s, tps);
508 word_space(s, decl.inputs[0].ident + ":");
509 print_type(s, decl.inputs[0].ty);
512 print_block(s, body);
515 s.ann.post(ann_node);
518 fn print_ty_method(s: ps, m: ast::ty_method) {
519 hardbreak_if_not_bol(s);
520 cbox(s, indent_unit);
521 maybe_print_comment(s, m.span.lo);
522 print_ty_fn(s, ast::proto_bare, m.decl, some(m.ident), some(m.tps));
527 fn print_outer_attributes(s: ps, attrs: [ast::attribute]) {
529 for attr: ast::attribute in attrs {
530 alt attr.node.style {
531 ast::attr_outer. { print_attribute(s, attr); count += 1; }
532 _ {/* fallthrough */ }
535 if count > 0 { hardbreak_if_not_bol(s); }
538 fn print_inner_attributes(s: ps, attrs: [ast::attribute]) {
540 for attr: ast::attribute in attrs {
541 alt attr.node.style {
543 print_attribute(s, attr);
547 _ {/* fallthrough */ }
550 if count > 0 { hardbreak_if_not_bol(s); }
553 fn print_attribute(s: ps, attr: ast::attribute) {
554 hardbreak_if_not_bol(s);
555 maybe_print_comment(s, attr.span.lo);
557 print_meta_item(s, @attr.node.value);
562 fn print_stmt(s: ps, st: ast::stmt) {
563 maybe_print_comment(s, st.span.lo);
565 ast::stmt_decl(decl, _) {
568 ast::stmt_expr(expr, _) {
572 ast::stmt_semi(expr, _) {
578 if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); }
579 maybe_print_trailing_comment(s, st.span, none::<uint>);
582 fn print_block(s: ps, blk: ast::blk) {
583 print_possibly_embedded_block(s, blk, block_normal, indent_unit);
586 tag embed_type { block_macro; block_block_fn; block_normal; }
588 fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
591 ast::unchecked_blk. { word(s.s, "unchecked"); }
592 ast::unsafe_blk. { word(s.s, "unsafe"); }
593 ast::default_blk. { }
596 maybe_print_comment(s, blk.span.lo);
597 let ann_node = node_block(s, blk);
600 block_macro. { word(s.s, "#{"); end(s); }
601 block_block_fn. { end(s); }
602 block_normal. { bopen(s); }
605 for vi in blk.node.view_items { print_view_item(s, vi); }
606 for st: @ast::stmt in blk.node.stmts {
613 maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
617 bclose_(s, blk.span, indented);
618 s.ann.post(ann_node);
621 // ret and fail, without arguments cannot appear is the discriminant of if,
622 // alt, do, & while unambiguously without being parenthesized
623 fn print_maybe_parens_discrim(s: ps, e: @ast::expr) {
624 let disambig = alt e.node {
625 ast::expr_ret(none.) | ast::expr_fail(none.) { true }
628 if disambig { popen(s); }
630 if disambig { pclose(s); }
633 fn print_if(s: ps, test: @ast::expr, blk: ast::blk,
634 elseopt: option::t<@ast::expr>, chk: bool) {
636 if chk { word_nbsp(s, "check"); }
637 print_maybe_parens_discrim(s, test);
640 fn do_else(s: ps, els: option::t<@ast::expr>) {
650 ast::expr_if(i, t, e) {
651 cbox(s, indent_unit - 1u);
653 word(s.s, " else if ");
654 print_maybe_parens_discrim(s, i);
666 cbox(s, indent_unit - 1u);
673 _ {/* fall through */ }
679 fn print_mac(s: ps, m: ast::mac) {
681 ast::mac_invoc(path, arg, body) {
683 print_path(s, path, false);
684 alt arg.node { ast::expr_vec(_, _) { } _ { word(s.s, " "); } }
686 // FIXME: extension 'body'
688 ast::mac_embed_type(ty) {
693 ast::mac_embed_block(blk) {
694 print_possibly_embedded_block(s, blk, block_normal, indent_unit);
696 ast::mac_ellipsis. { word(s.s, "..."); }
700 fn print_expr(s: ps, &&expr: @ast::expr) {
701 maybe_print_comment(s, expr.span.lo);
702 ibox(s, indent_unit);
703 let ann_node = node_expr(s, expr);
706 ast::expr_vec(exprs, mut) {
707 ibox(s, indent_unit);
710 word(s.s, "mutable");
711 if vec::len(exprs) > 0u { nbsp(s); }
713 commasep_exprs(s, inconsistent, exprs);
717 ast::expr_rec(fields, wth) {
718 fn print_field(s: ps, field: ast::field) {
719 ibox(s, indent_unit);
720 if field.node.mut == ast::mut { word_nbsp(s, "mutable"); }
721 word(s.s, field.node.ident);
723 print_expr(s, field.node.expr);
726 fn get_span(field: ast::field) -> codemap::span { ret field.span; }
728 commasep_cmnt(s, consistent, fields, print_field, get_span);
731 if vec::len(fields) > 0u { space(s.s); }
732 ibox(s, indent_unit);
733 word_space(s, "with");
737 _ { word(s.s, ","); }
741 ast::expr_tup(exprs) {
743 commasep_exprs(s, inconsistent, exprs);
746 ast::expr_call(func, args, has_block) {
747 print_expr_parens_if_not_bot(s, func);
748 let base_args = args, blk = none;
749 if has_block { blk = some(vec::pop(base_args)); }
750 if !has_block || vec::len(base_args) > 0u {
752 commasep_exprs(s, inconsistent, base_args);
757 print_expr(s, option::get(blk));
760 ast::expr_bind(func, args) {
761 fn print_opt(s: ps, expr: option::t<@ast::expr>) {
763 some(expr) { print_expr(s, expr); }
764 _ { word(s.s, "_"); }
767 word_nbsp(s, "bind");
770 commasep(s, inconsistent, args, print_opt);
773 ast::expr_binary(op, lhs, rhs) {
774 let prec = operator_prec(op);
775 print_op_maybe_parens(s, lhs, prec);
777 word_space(s, ast_util::binop_to_str(op));
778 print_op_maybe_parens(s, rhs, prec + 1);
780 ast::expr_unary(op, expr) {
781 word(s.s, ast_util::unop_to_str(op));
782 print_op_maybe_parens(s, expr, parse::parser::unop_prec);
784 ast::expr_lit(lit) { print_literal(s, lit); }
785 ast::expr_cast(expr, ty) {
786 print_op_maybe_parens(s, expr, parse::parser::as_prec);
791 ast::expr_if(test, blk, elseopt) {
792 print_if(s, test, blk, elseopt, false);
794 ast::expr_if_check(test, blk, elseopt) {
795 print_if(s, test, blk, elseopt, true);
797 ast::expr_ternary(test, then, els) {
806 ast::expr_while(test, blk) {
808 print_maybe_parens_discrim(s, test);
812 ast::expr_for(decl, expr, blk) {
814 print_for_decl(s, decl, expr);
818 ast::expr_do_while(blk, expr) {
823 word_space(s, "while");
826 ast::expr_alt(expr, arms) {
827 cbox(s, alt_indent_unit);
830 print_maybe_parens_discrim(s, expr);
833 for arm: ast::arm in arms {
835 cbox(s, alt_indent_unit);
838 for p: @ast::pat in arm.pats {
841 } else { space(s.s); word_space(s, "|"); }
846 some(e) { word_space(s, "if"); print_expr(s, e); space(s.s); }
849 print_possibly_embedded_block(s, arm.body, block_normal,
852 bclose_(s, expr.span, alt_indent_unit);
854 ast::expr_fn(proto, decl, body, cap_clause) {
855 // containing cbox, will be closed by print-block at }
856 cbox(s, indent_unit);
857 // head-box, will be closed by print-block at start
859 word(s.s, proto_to_str(proto));
860 print_cap_clause(s, *cap_clause);
861 print_fn_args_and_ret(s, decl);
863 print_block(s, body);
865 ast::expr_fn_block(decl, body) {
866 // containing cbox, will be closed by print-block at }
867 cbox(s, indent_unit);
868 // head-box, will be closed by print-block at start
871 print_fn_block_args(s, decl);
872 print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
874 ast::expr_block(blk) {
875 // containing cbox, will be closed by print-block at }
876 cbox(s, indent_unit);
877 // head-box, will be closed by print-block after {
881 ast::expr_copy(e) { word_space(s, "copy"); print_expr(s, e); }
882 ast::expr_move(lhs, rhs) {
888 ast::expr_assign(lhs, rhs) {
894 ast::expr_swap(lhs, rhs) {
897 word_space(s, "<->");
900 ast::expr_assign_op(op, lhs, rhs) {
903 word(s.s, ast_util::binop_to_str(op));
907 ast::expr_field(expr, id, tys) {
909 if ends_in_lit_int(expr) {
910 popen(s); print_expr(s, expr); pclose(s);
912 print_expr_parens_if_not_bot(s, expr);
916 if vec::len(tys) > 0u {
918 commasep(s, inconsistent, tys, print_type);
922 ast::expr_index(expr, index) {
923 print_expr_parens_if_not_bot(s, expr);
925 print_expr(s, index);
928 ast::expr_path(path) { print_path(s, path, true); }
929 ast::expr_fail(maybe_fail_val) {
932 some(expr) { word(s.s, " "); print_expr(s, expr); }
936 ast::expr_break. { word(s.s, "break"); }
937 ast::expr_cont. { word(s.s, "cont"); }
938 ast::expr_ret(result) {
941 some(expr) { word(s.s, " "); print_expr(s, expr); }
945 ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); }
946 ast::expr_log(lvl, lexp, expr) {
948 1 { word_nbsp(s, "log"); print_expr(s, expr); }
949 0 { word_nbsp(s, "log_err"); print_expr(s, expr); }
961 ast::expr_check(m, expr) {
963 ast::claimed_expr. { word_nbsp(s, "claim"); }
964 ast::checked_expr. { word_nbsp(s, "check"); }
970 ast::expr_assert(expr) {
971 word_nbsp(s, "assert");
976 ast::expr_mac(m) { print_mac(s, m); }
977 ast::expr_anon_obj(anon_obj) {
982 fn print_field(s: ps, field: ast::anon_obj_field) {
983 ibox(s, indent_unit);
984 print_mutability(s, field.mut);
985 word_space(s, field.ident + ":");
986 print_type(s, field.ty);
989 print_expr(s, field.expr);
992 fn get_span(f: ast::anon_obj_field) -> codemap::span {
995 alt anon_obj.fields {
998 commasep_cmnt(s, consistent, fields, print_field, get_span);
1006 for meth: @ast::method in anon_obj.methods {
1007 hardbreak_if_not_bol(s);
1008 maybe_print_comment(s, meth.span.lo);
1009 print_fn(s, meth.decl, meth.ident, meth.tps);
1011 print_block(s, meth.body);
1015 alt anon_obj.inner_obj {
1017 some(e) { space(s.s); word_space(s, "with"); print_expr(s, e); }
1019 bclose(s, expr.span);
1022 s.ann.post(ann_node);
1026 fn print_expr_parens_if_not_bot(s: ps, ex: @ast::expr) {
1027 let parens = alt ex.node {
1028 ast::expr_fail(_) | ast::expr_ret(_) |
1029 ast::expr_binary(_, _, _) | ast::expr_unary(_, _) |
1030 ast::expr_ternary(_, _, _) | ast::expr_move(_, _) |
1031 ast::expr_copy(_) | ast::expr_assign(_, _) | ast::expr_be(_) |
1032 ast::expr_assign_op(_, _, _) | ast::expr_swap(_, _) |
1033 ast::expr_log(_, _, _) | ast::expr_assert(_) |
1034 ast::expr_call(_, _, true) |
1035 ast::expr_check(_, _) { true }
1038 if parens { popen(s); }
1040 if parens { pclose(s); }
1043 fn print_local_decl(s: ps, loc: @ast::local) {
1044 print_pat(s, loc.node.pat);
1045 alt loc.node.ty.node {
1047 _ { word_space(s, ":"); print_type(s, loc.node.ty); }
1051 fn print_decl(s: ps, decl: @ast::decl) {
1052 maybe_print_comment(s, decl.span.lo);
1054 ast::decl_local(locs) {
1055 space_if_not_bol(s);
1056 ibox(s, indent_unit);
1057 word_nbsp(s, "let");
1058 fn print_local(s: ps, loc_st: (ast::let_style, @ast::local)) {
1059 let (st, loc) = loc_st;
1060 ibox(s, indent_unit);
1061 if st == ast::let_ref { word(s.s, "&"); }
1062 print_local_decl(s, loc);
1068 ast::init_assign. { word_space(s, "="); }
1069 ast::init_move. { word_space(s, "<-"); }
1071 print_expr(s, init.expr);
1076 commasep(s, consistent, locs, print_local);
1079 ast::decl_item(item) { print_item(s, item); }
1083 fn print_ident(s: ps, ident: ast::ident) { word(s.s, ident); }
1085 fn print_for_decl(s: ps, loc: @ast::local, coll: @ast::expr) {
1086 print_local_decl(s, loc);
1088 word_space(s, "in");
1089 print_expr(s, coll);
1092 fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) {
1093 maybe_print_comment(s, path.span.lo);
1094 if path.node.global { word(s.s, "::"); }
1096 for id: ast::ident in path.node.idents {
1097 if first { first = false; } else { word(s.s, "::"); }
1100 if vec::len(path.node.types) > 0u {
1101 if colons_before_params { word(s.s, "::"); }
1103 commasep(s, inconsistent, path.node.types, print_type);
1108 fn print_pat(s: ps, &&pat: @ast::pat) {
1109 maybe_print_comment(s, pat.span.lo);
1110 let ann_node = node_pat(s, pat);
1111 s.ann.pre(ann_node);
1113 ast::pat_wild. { word(s.s, "_"); }
1114 ast::pat_bind(id, sub) {
1117 some(p) { word(s.s, "@"); print_pat(s, p); }
1121 ast::pat_tag(path, args) {
1122 print_path(s, path, true);
1123 if vec::len(args) > 0u {
1125 commasep(s, inconsistent, args, print_pat);
1127 } else { word(s.s, "."); }
1129 ast::pat_rec(fields, etc) {
1131 fn print_field(s: ps, f: ast::field_pat) {
1132 cbox(s, indent_unit);
1135 print_pat(s, f.pat);
1138 fn get_span(f: ast::field_pat) -> codemap::span { ret f.pat.span; }
1139 commasep_cmnt(s, consistent, fields, print_field, get_span);
1141 if vec::len(fields) != 0u { word_space(s, ","); }
1146 ast::pat_tup(elts) {
1148 commasep(s, inconsistent, elts, print_pat);
1151 ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); }
1152 ast::pat_uniq(inner) { word(s.s, "~"); print_pat(s, inner); }
1153 ast::pat_lit(e) { print_expr(s, e); }
1154 ast::pat_range(begin, end) {
1155 print_expr(s, begin);
1157 word_space(s, "to");
1161 s.ann.post(ann_node);
1164 fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
1165 typarams: [ast::ty_param]) {
1167 ast::impure_fn. { head(s, "fn"); }
1168 ast::unsafe_fn. { head(s, "unsafe fn"); }
1169 ast::pure_fn. { head(s, "pure fn"); }
1172 print_type_params(s, typarams);
1173 print_fn_args_and_ret(s, decl);
1176 fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
1177 fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) {
1178 word(s.s, cap_item.name);
1181 let has_copies = vec::is_not_empty(cap_clause.copies);
1182 let has_moves = vec::is_not_empty(cap_clause.moves);
1183 if !has_copies && !has_moves { ret; }
1188 word_nbsp(s, "copy");
1189 commasep(s, inconsistent, cap_clause.copies, print_cap_item);
1196 word_nbsp(s, "move");
1197 commasep(s, inconsistent, cap_clause.moves, print_cap_item);
1203 fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
1205 fn print_arg(s: ps, x: ast::arg) {
1206 ibox(s, indent_unit);
1207 print_arg_mode(s, x.mode);
1208 word_space(s, x.ident + ":");
1209 print_type(s, x.ty);
1212 commasep(s, inconsistent, decl.inputs, print_arg);
1214 word(s.s, ast_fn_constrs_str(decl, decl.constraints));
1215 maybe_print_comment(s, decl.output.span.lo);
1216 if decl.output.node != ast::ty_nil {
1217 space_if_not_bol(s);
1218 word_space(s, "->");
1219 print_type(s, decl.output);
1223 fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
1225 fn print_arg(s: ps, x: ast::arg) {
1226 ibox(s, indent_unit);
1227 print_arg_mode(s, x.mode);
1231 commasep(s, inconsistent, decl.inputs, print_arg);
1233 if decl.output.node != ast::ty_infer {
1234 space_if_not_bol(s);
1235 word_space(s, "->");
1236 print_type(s, decl.output);
1238 maybe_print_comment(s, decl.output.span.lo);
1241 fn print_arg_mode(s: ps, m: ast::mode) {
1243 ast::by_mut_ref. { word(s.s, "&"); }
1244 ast::by_move. { word(s.s, "-"); }
1245 ast::by_ref. { word(s.s, "&&"); }
1246 ast::by_val. { word(s.s, "++"); }
1247 ast::by_copy. { word(s.s, "+"); }
1252 fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) {
1253 if vec::len(*bounds) > 0u {
1255 for bound in *bounds {
1258 ast::bound_copy. { word(s.s, "copy"); }
1259 ast::bound_send. { word(s.s, "send"); }
1260 ast::bound_iface(t) { print_type(s, t); }
1266 fn print_type_params(s: ps, params: [ast::ty_param]) {
1267 if vec::len(params) > 0u {
1269 fn printParam(s: ps, param: ast::ty_param) {
1270 word(s.s, param.ident);
1271 print_bounds(s, param.bounds);
1273 commasep(s, inconsistent, params, printParam);
1278 fn print_meta_item(s: ps, &&item: @ast::meta_item) {
1279 ibox(s, indent_unit);
1281 ast::meta_word(name) { word(s.s, name); }
1282 ast::meta_name_value(name, value) {
1283 word_space(s, name);
1285 print_literal(s, @value);
1287 ast::meta_list(name, items) {
1290 commasep(s, consistent, items, print_meta_item);
1297 fn print_view_item(s: ps, item: @ast::view_item) {
1298 hardbreak_if_not_bol(s);
1299 maybe_print_comment(s, item.span.lo);
1301 ast::view_item_use(id, mta, _) {
1304 if vec::len(mta) > 0u {
1306 commasep(s, consistent, mta, print_meta_item);
1310 ast::view_item_import(id, ids, _) {
1312 if !str::eq(id, ids[vec::len(*ids) - 1u]) {
1317 for elt: ast::ident in *ids {
1318 if first { first = false; } else { word(s.s, "::"); }
1322 ast::view_item_import_from(mod_path, idents, _) {
1324 for elt: ast::ident in *mod_path { word(s.s, elt); word(s.s, "::"); }
1326 commasep(s, inconsistent, idents,
1327 fn (s: ps, w: ast::import_ident) { word(s.s, w.node.name) });
1330 ast::view_item_import_glob(ids, _) {
1333 for elt: ast::ident in *ids {
1334 if first { first = false; } else { word(s.s, "::"); }
1339 ast::view_item_export(ids, _) {
1341 commasep(s, inconsistent, ids,
1342 fn (s: ps, &&w: ast::ident) { word(s.s, w) });
1346 end(s); // end inner head-block
1348 end(s); // end outer head-block
1353 // FIXME: The fact that this builds up the table anew for every call is
1354 // not good. Eventually, table should be a const.
1355 fn operator_prec(op: ast::binop) -> int {
1356 for spec: parse::parser::op_spec in *parse::parser::prec_table() {
1357 if spec.op == op { ret spec.prec; }
1362 fn need_parens(expr: @ast::expr, outer_prec: int) -> bool {
1364 ast::expr_binary(op, _, _) { operator_prec(op) < outer_prec }
1365 ast::expr_cast(_, _) { parse::parser::as_prec < outer_prec }
1366 ast::expr_ternary(_, _, _) { parse::parser::ternary_prec < outer_prec }
1367 // This may be too conservative in some cases
1368 ast::expr_assign(_, _) { true }
1369 ast::expr_move(_, _) { true }
1370 ast::expr_swap(_, _) { true }
1371 ast::expr_assign_op(_, _, _) { true }
1372 ast::expr_ret(_) { true }
1373 ast::expr_be(_) { true }
1374 ast::expr_assert(_) { true }
1375 ast::expr_check(_, _) { true }
1376 ast::expr_log(_, _, _) { true }
1377 _ { !parse::parser::expr_requires_semi_to_be_stmt(expr) }
1381 fn print_op_maybe_parens(s: ps, expr: @ast::expr, outer_prec: int) {
1382 let add_them = need_parens(expr, outer_prec);
1383 if add_them { popen(s); }
1384 print_expr(s, expr);
1385 if add_them { pclose(s); }
1388 fn print_mutability(s: ps, mut: ast::mutability) {
1390 ast::mut. { word_nbsp(s, "mutable"); }
1391 ast::maybe_mut. { word_nbsp(s, "const"); }
1392 ast::imm. {/* nothing */ }
1396 fn print_mt(s: ps, mt: ast::mt) {
1397 print_mutability(s, mt.mut);
1398 print_type(s, mt.ty);
1401 fn print_ty_fn(s: ps, proto: ast::proto,
1402 decl: ast::fn_decl, id: option::t<ast::ident>,
1403 tps: option::t<[ast::ty_param]>) {
1404 ibox(s, indent_unit);
1405 word(s.s, proto_to_str(proto));
1406 alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } }
1407 alt tps { some(tps) { print_type_params(s, tps); } _ { } }
1410 fn print_arg(s: ps, input: ast::arg) {
1411 print_arg_mode(s, input.mode);
1412 if str::byte_len(input.ident) > 0u {
1413 word_space(s, input.ident + ":");
1415 print_type(s, input.ty);
1417 commasep(s, inconsistent, decl.inputs, print_arg);
1419 maybe_print_comment(s, decl.output.span.lo);
1420 if decl.output.node != ast::ty_nil {
1421 space_if_not_bol(s);
1422 ibox(s, indent_unit);
1423 word_space(s, "->");
1424 if decl.cf == ast::noreturn { word_nbsp(s, "!"); }
1425 else { print_type(s, decl.output); }
1428 word(s.s, ast_ty_fn_constrs_str(decl.constraints));
1432 fn maybe_print_trailing_comment(s: ps, span: codemap::span,
1433 next_pos: option::t<uint>) {
1435 alt s.cm { some(ccm) { cm = ccm; } _ { ret; } }
1436 alt next_comment(s) {
1438 if cmnt.style != lexer::trailing { ret; }
1439 let span_line = codemap::lookup_char_pos(cm, span.hi);
1440 let comment_line = codemap::lookup_char_pos(cm, cmnt.pos);
1441 let next = cmnt.pos + 1u;
1442 alt next_pos { none. { } some(p) { next = p; } }
1443 if span.hi < cmnt.pos && cmnt.pos < next &&
1444 span_line.line == comment_line.line {
1445 print_comment(s, cmnt);
1453 fn print_remaining_comments(s: ps) {
1454 // If there aren't any remaining comments, then we need to manually
1455 // make sure there is a line break at the end.
1456 if option::is_none(next_comment(s)) { hardbreak(s.s); }
1458 alt next_comment(s) {
1459 some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; }
1465 fn in_cbox(s: ps) -> bool {
1466 let len = vec::len(s.boxes);
1467 if len == 0u { ret false; }
1468 ret s.boxes[len - 1u] == pp::consistent;
1471 fn print_literal(s: ps, &&lit: @ast::lit) {
1472 maybe_print_comment(s, lit.span.lo);
1475 if lt.pos == lit.span.lo { word(s.s, lt.lit); s.cur_lit += 1u; ret; }
1480 ast::lit_str(st) { print_string(s, st); }
1481 ast::lit_int(ch, ast::ty_char.) {
1482 word(s.s, "'" + escape_str(str::from_char(ch as char), '\'') + "'");
1484 ast::lit_int(i, t) {
1485 word(s.s, int::str(i as int) + ast_util::int_ty_to_str(t));
1487 ast::lit_uint(u, t) {
1488 word(s.s, uint::str(u as uint) + ast_util::uint_ty_to_str(t));
1490 ast::lit_float(f, t) {
1491 word(s.s, f + ast_util::float_ty_to_str(t));
1493 ast::lit_nil. { word(s.s, "()"); }
1494 ast::lit_bool(val) {
1495 if val { word(s.s, "true"); } else { word(s.s, "false"); }
1500 fn lit_to_str(l: @ast::lit) -> str { be to_str(l, print_literal); }
1502 fn next_lit(s: ps) -> option::t<lexer::lit> {
1505 if s.cur_lit < vec::len(lits) {
1506 ret some(lits[s.cur_lit]);
1507 } else { ret none::<lexer::lit>; }
1509 _ { ret none::<lexer::lit>; }
1513 fn maybe_print_comment(s: ps, pos: uint) {
1515 alt next_comment(s) {
1518 print_comment(s, cmnt);
1527 fn print_comment(s: ps, cmnt: lexer::cmnt) {
1530 assert (vec::len(cmnt.lines) == 1u);
1532 word(s.s, cmnt.lines[0]);
1536 pprust::hardbreak_if_not_bol(s);
1537 for line: str in cmnt.lines {
1538 // Don't print empty lines because they will end up as trailing
1540 if str::is_not_empty(line) { word(s.s, line); }
1546 if vec::len(cmnt.lines) == 1u {
1547 word(s.s, cmnt.lines[0]);
1551 for line: str in cmnt.lines {
1552 if str::is_not_empty(line) { word(s.s, line); }
1558 lexer::blank_line. {
1559 // We need to do at least one, possibly two hardbreaks.
1561 alt s.s.last_token() {
1562 pp::STRING(s, _) { s == ";" }
1565 if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); }
1571 fn print_string(s: ps, st: str) {
1573 word(s.s, escape_str(st, '"'));
1577 fn escape_str(st: str, to_escape: char) -> str {
1579 let len = str::byte_len(st);
1583 '\n' { out += "\\n"; }
1584 '\t' { out += "\\t"; }
1585 '\r' { out += "\\r"; }
1586 '\\' { out += "\\\\"; }
1588 if cur == to_escape { out += "\\"; }
1589 // FIXME some (or all?) non-ascii things should be escaped
1591 str::push_char(out, cur);
1599 fn to_str<T>(t: T, f: fn@(ps, T)) -> str {
1600 let writer = io::string_writer();
1601 let s = rust_printer(writer.get_writer());
1604 ret writer.get_str();
1607 fn next_comment(s: ps) -> option::t<lexer::cmnt> {
1610 if s.cur_cmnt < vec::len(cmnts) {
1611 ret some(cmnts[s.cur_cmnt]);
1612 } else { ret none::<lexer::cmnt>; }
1614 _ { ret none::<lexer::cmnt>; }
1618 // Removing the aliases from the type of f in the next two functions
1619 // triggers memory corruption, but I haven't isolated the bug yet. FIXME
1620 fn constr_args_to_str<T>(f: fn@(T) -> str, args: [@ast::sp_constr_arg<T>]) ->
1624 for a: @ast::sp_constr_arg<T> in args {
1625 if comma { s += ", "; } else { comma = true; }
1626 s += constr_arg_to_str::<T>(f, a.node);
1632 fn constr_arg_to_str<T>(f: fn@(T) -> str, c: ast::constr_arg_general_<T>) ->
1635 ast::carg_base. { ret "*"; }
1636 ast::carg_ident(i) { ret f(i); }
1637 ast::carg_lit(l) { ret lit_to_str(l); }
1641 // needed b/c constr_args_to_str needs
1642 // something that takes an alias
1644 fn uint_to_str(&&i: uint) -> str { ret uint::str(i); }
1646 fn ast_ty_fn_constr_to_str(c: @ast::constr) -> str {
1647 ret path_to_str(c.node.path) +
1648 constr_args_to_str(uint_to_str, c.node.args);
1651 // FIXME: fix repeated code
1652 fn ast_ty_fn_constrs_str(constrs: [@ast::constr]) -> str {
1655 for c: @ast::constr in constrs {
1656 if colon { s += " : "; colon = false; } else { s += ", "; }
1657 s += ast_ty_fn_constr_to_str(c);
1662 fn fn_arg_idx_to_str(decl: ast::fn_decl, &&idx: uint) -> str {
1663 decl.inputs[idx].ident
1666 fn ast_fn_constr_to_str(decl: ast::fn_decl, c: @ast::constr) -> str {
1667 let arg_to_str = bind fn_arg_idx_to_str(decl, _);
1668 ret path_to_str(c.node.path) +
1669 constr_args_to_str(arg_to_str, c.node.args);
1672 // FIXME: fix repeated code
1673 fn ast_fn_constrs_str(decl: ast::fn_decl, constrs: [@ast::constr]) -> str {
1676 for c: @ast::constr in constrs {
1677 if colon { s += " : "; colon = false; } else { s += ", "; }
1678 s += ast_fn_constr_to_str(decl, c);
1683 fn proto_to_str(p: ast::proto) -> str {
1685 ast::proto_bare. { "fn" }
1686 ast::proto_block. { "block" }
1687 ast::proto_send. { "sendfn" }
1688 ast::proto_shared. { "fn@" }
1692 fn ty_constr_to_str(c: @ast::ty_constr) -> str {
1693 fn ty_constr_path_to_str(&&p: @ast::path) -> str { "*." + path_to_str(p) }
1695 ret path_to_str(c.node.path) +
1696 constr_args_to_str::<@ast::path>(ty_constr_path_to_str,
1701 fn ast_ty_constrs_str(constrs: [@ast::ty_constr]) -> str {
1704 for c: @ast::ty_constr in constrs {
1705 if colon { s += " : "; colon = false; } else { s += ", "; }
1706 s += ty_constr_to_str(c);
1711 fn ends_in_lit_int(ex: @ast::expr) -> bool {
1713 ast::expr_lit(@{node: ast::lit_int(_, ast::ty_i.), _}) { true }
1714 ast::expr_binary(_, _, sub) | ast::expr_unary(_, sub) |
1715 ast::expr_ternary(_, _, sub) | ast::expr_move(_, sub) |
1716 ast::expr_copy(sub) | ast::expr_assign(_, sub) | ast::expr_be(sub) |
1717 ast::expr_assign_op(_, _, sub) | ast::expr_swap(_, sub) |
1718 ast::expr_log(_, _, sub) | ast::expr_assert(sub) |
1719 ast::expr_check(_, sub) { ends_in_lit_int(sub) }
1720 ast::expr_fail(osub) | ast::expr_ret(osub) {
1722 some(ex) { ends_in_lit_int(ex) }
1734 // indent-tabs-mode: nil
1735 // c-basic-offset: 4
1736 // buffer-file-coding-system: utf-8-unix