1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use ast::{RegionTyParamBound, TraitTyParamBound, required, provided};
16 use ast_util::{operator_prec};
18 use codemap::{CodeMap, BytePos};
21 use parse::classify::{expr_is_simple_block, expr_requires_semi_to_be_stmt};
22 use parse::classify::{stmt_ends_with_semi};
23 use parse::token::ident_interner;
24 use parse::{comments, lexer, token};
26 use print::pp::{break_offset, word, Printer, space, zerobreak, hardbreak};
27 use print::pp::{breaks, consistent, inconsistent, eof};
35 use core::str::{push_str, push_char};
40 // The @ps is stored here to prevent recursive type.
42 node_block(@ps, ast::blk),
43 node_item(@ps, @ast::item),
44 node_expr(@ps, @ast::expr),
45 node_pat(@ps, @ast::pat),
52 pub fn no_ann() -> pp_ann {
53 fn ignore(_node: ann_node) { }
54 return pp_ann {pre: ignore, post: ignore};
57 pub struct CurrentCommentAndLiteral {
65 intr: @token::ident_interner,
66 comments: Option<~[comments::cmnt]>,
67 literals: Option<~[comments::lit]>,
68 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
69 boxes: DVec<pp::breaks>,
73 pub fn ibox(s: @ps, u: uint) {
74 s.boxes.push(pp::inconsistent);
83 pub fn rust_printer(writer: io::Writer, intr: @ident_interner) -> @ps {
85 s: pp::mk_printer(writer, default_columns),
88 comments: None::<~[comments::cmnt]>,
89 literals: None::<~[comments::lit]>,
90 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
99 pub const indent_unit: uint = 4u;
100 pub const match_indent_unit: uint = 2u;
102 pub const default_columns: uint = 78u;
104 // Requires you to pass an input filename and reader so that
105 // it can scan the input text for comments and literals to
107 pub fn print_crate(cm: @CodeMap, intr: @ident_interner,
108 span_diagnostic: diagnostic::span_handler,
109 crate: @ast::crate, filename: ~str, in: io::Reader,
110 out: io::Writer, ann: pp_ann, is_expanded: bool) {
112 comments::gather_comments_and_literals(span_diagnostic,
115 s: pp::mk_printer(out, default_columns),
118 comments: Some(cmnts),
119 // If the code is post expansion, don't use the table of
120 // literals, since it doesn't correspond with the literals
121 // in the AST anymore.
122 literals: if is_expanded { None } else { Some(lits) },
123 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
130 print_crate_(s, crate);
133 pub fn print_crate_(s: @ps, &&crate: @ast::crate) {
134 print_mod(s, crate.node.module, crate.node.attrs);
135 print_remaining_comments(s);
139 pub fn ty_to_str(ty: @ast::Ty, intr: @ident_interner) -> ~str {
140 to_str(ty, print_type, intr)
143 pub fn pat_to_str(pat: @ast::pat, intr: @ident_interner) -> ~str {
144 to_str(pat, print_irrefutable_pat, intr)
147 pub fn expr_to_str(e: @ast::expr, intr: @ident_interner) -> ~str {
148 to_str(e, print_expr, intr)
151 pub fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str {
152 to_str(tt, print_tt, intr)
155 pub fn tts_to_str(tts: &[ast::token_tree], intr: @ident_interner) -> ~str {
156 to_str(tts, print_tts, intr)
159 pub fn stmt_to_str(s: ast::stmt, intr: @ident_interner) -> ~str {
160 to_str(s, print_stmt, intr)
163 pub fn item_to_str(i: @ast::item, intr: @ident_interner) -> ~str {
164 to_str(i, print_item, intr)
167 pub fn typarams_to_str(tps: ~[ast::ty_param], intr: @ident_interner) -> ~str {
168 to_str(tps, print_type_params, intr)
171 pub fn path_to_str(&&p: @ast::path, intr: @ident_interner) -> ~str {
172 to_str(p, |a,b| print_path(a, b, false), intr)
175 pub fn fun_to_str(decl: ast::fn_decl, name: ast::ident,
176 params: ~[ast::ty_param], intr: @ident_interner) -> ~str {
177 do io::with_str_writer |wr| {
178 let s = rust_printer(wr, intr);
179 print_fn(s, decl, None, name, params, None, ast::inherited);
180 end(s); // Close the head box
181 end(s); // Close the outer box
186 pub fn block_to_str(blk: ast::blk, intr: @ident_interner) -> ~str {
187 do io::with_str_writer |wr| {
188 let s = rust_printer(wr, intr);
189 // containing cbox, will be closed by print-block at }
190 cbox(s, indent_unit);
191 // head-ibox, will be closed by print-block after {
198 pub fn meta_item_to_str(mi: @ast::meta_item, intr: @ident_interner) -> ~str {
199 to_str(mi, print_meta_item, intr)
202 pub fn attribute_to_str(attr: ast::attribute, intr: @ident_interner) -> ~str {
203 to_str(attr, print_attribute, intr)
206 pub fn variant_to_str(var: ast::variant, intr: @ident_interner) -> ~str {
207 to_str(var, print_variant, intr)
210 pub fn cbox(s: @ps, u: uint) {
211 s.boxes.push(pp::consistent);
215 pub fn box(s: @ps, u: uint, b: pp::breaks) {
220 pub fn nbsp(s: @ps) { word(s.s, ~" "); }
222 pub fn word_nbsp(s: @ps, w: ~str) { word(s.s, w); nbsp(s); }
224 pub fn word_space(s: @ps, w: ~str) { word(s.s, w); space(s.s); }
226 pub fn popen(s: @ps) { word(s.s, ~"("); }
228 pub fn pclose(s: @ps) { word(s.s, ~")"); }
230 pub fn head(s: @ps, w: ~str) {
231 // outer-box is consistent
232 cbox(s, indent_unit);
233 // head-box is inconsistent
234 ibox(s, str::len(w) + 1);
235 // keyword that starts the head
241 pub fn bopen(s: @ps) {
243 end(s); // close the head-box
246 pub fn bclose_(s: @ps, span: codemap::span, indented: uint) {
247 bclose_maybe_open(s, span, indented, true);
249 pub fn bclose_maybe_open (s: @ps, span: codemap::span, indented: uint,
251 maybe_print_comment(s, span.hi);
252 break_offset_if_not_bol(s, 1u, -(indented as int));
255 end(s); // close the outer-box
258 pub fn bclose(s: @ps, span: codemap::span) { bclose_(s, span, indent_unit); }
260 pub fn is_begin(s: @ps) -> bool {
261 match s.s.last_token() { pp::BEGIN(_) => true, _ => false }
264 pub fn is_end(s: @ps) -> bool {
265 match s.s.last_token() { pp::END => true, _ => false }
268 pub fn is_bol(s: @ps) -> bool {
269 return s.s.last_token().is_eof() || s.s.last_token().is_hardbreak_tok();
272 pub fn in_cbox(s: @ps) -> bool {
273 let len = s.boxes.len();
274 if len == 0u { return false; }
275 return s.boxes[len - 1u] == pp::consistent;
278 pub fn hardbreak_if_not_bol(s: @ps) { if !is_bol(s) { hardbreak(s.s); } }
279 pub fn space_if_not_bol(s: @ps) { if !is_bol(s) { space(s.s); } }
280 pub fn break_offset_if_not_bol(s: @ps, n: uint, off: int) {
282 break_offset(s.s, n, off);
284 if off != 0 && s.s.last_token().is_hardbreak_tok() {
285 // We do something pretty sketchy here: tuck the nonzero
286 // offset-adjustment we were going to deposit along with the
287 // break into the previous hardbreak.
288 s.s.replace_last_token(pp::hardbreak_tok_offset(off));
293 // Synthesizes a comment that was not textually present in the original source
295 pub fn synth_comment(s: @ps, text: ~str) {
303 pub fn commasep<IN>(s: @ps, b: breaks, elts: ~[IN], op: fn(@ps, IN)) {
305 let mut first = true;
306 for elts.each |elt| {
307 if first { first = false; } else { word_space(s, ~","); }
314 pub fn commasep_cmnt<IN>(s: @ps, b: breaks, elts: ~[IN], op: fn(@ps, IN),
315 get_span: fn(IN) -> codemap::span) {
317 let len = vec::len::<IN>(elts);
319 for elts.each |elt| {
320 maybe_print_comment(s, get_span(*elt).hi);
325 maybe_print_trailing_comment(s, get_span(*elt),
326 Some(get_span(elts[i]).hi));
333 pub fn commasep_exprs(s: @ps, b: breaks, exprs: ~[@ast::expr]) {
334 fn expr_span(&&expr: @ast::expr) -> codemap::span { return expr.span; }
335 commasep_cmnt(s, b, exprs, print_expr, expr_span);
338 pub fn print_mod(s: @ps, _mod: ast::_mod, attrs: ~[ast::attribute]) {
339 print_inner_attributes(s, attrs);
340 for _mod.view_items.each |vitem| {
341 print_view_item(s, *vitem);
343 for _mod.items.each |item| { print_item(s, *item); }
346 pub fn print_foreign_mod(s: @ps, nmod: ast::foreign_mod,
347 attrs: ~[ast::attribute]) {
348 print_inner_attributes(s, attrs);
349 for nmod.view_items.each |vitem| {
350 print_view_item(s, *vitem);
352 for nmod.items.each |item| { print_foreign_item(s, *item); }
355 pub fn print_region(s: @ps, prefix: ~str, region: @ast::region, sep: ~str) {
362 word_space(s, ~"static")
365 word_space(s, ~"self")
367 ast::re_named(name) => {
368 print_ident(s, name);
374 pub fn print_type(s: @ps, &&ty: @ast::Ty) {
375 print_type_ex(s, ty, false);
378 pub fn print_type_ex(s: @ps, &&ty: @ast::Ty, print_colons: bool) {
379 maybe_print_comment(s, ty.span.lo);
382 ast::ty_nil => word(s.s, ~"()"),
383 ast::ty_bot => word(s.s, ~"!"),
384 ast::ty_box(mt) => { word(s.s, ~"@"); print_mt(s, mt); }
385 ast::ty_uniq(mt) => { word(s.s, ~"~"); print_mt(s, mt); }
389 ast::m_mutbl => word_space(s, ~"mut"),
390 ast::m_const => word_space(s, ~"const"),
393 print_type(s, mt.ty);
396 ast::ty_ptr(mt) => { word(s.s, ~"*"); print_mt(s, mt); }
397 ast::ty_rptr(region, mt) => {
398 print_region(s, ~"&", region, ~"/");
401 ast::ty_rec(ref fields) => {
403 fn print_field(s: @ps, f: ast::ty_field) {
404 cbox(s, indent_unit);
405 print_mutability(s, f.node.mt.mutbl);
406 print_ident(s, f.node.ident);
408 print_type(s, f.node.mt.ty);
411 fn get_span(f: ast::ty_field) -> codemap::span { return f.span; }
412 commasep_cmnt(s, consistent, (*fields), print_field, get_span);
415 ast::ty_tup(elts) => {
417 commasep(s, inconsistent, elts, print_type);
423 ast::ty_bare_fn(f) => {
424 print_ty_fn(s, Some(f.abi), None, None,
425 f.purity, ast::Many, f.decl, None,
428 ast::ty_closure(f) => {
429 print_ty_fn(s, None, Some(f.sigil), f.region,
430 f.purity, f.onceness, f.decl, None,
433 ast::ty_path(path, _) => print_path(s, path, print_colons),
434 ast::ty_fixed_length_vec(mt, v) => {
437 ast::m_mutbl => word_space(s, ~"mut"),
438 ast::m_const => word_space(s, ~"const"),
441 print_type(s, mt.ty);
443 word(s.s, fmt!("%u", v));
447 fail!(~"print_type doesn't know how to print a ty_mac");
450 fail!(~"print_type shouldn't see a ty_infer");
457 pub fn print_foreign_item(s: @ps, item: @ast::foreign_item) {
458 hardbreak_if_not_bol(s);
459 maybe_print_comment(s, item.span.lo);
460 print_outer_attributes(s, item.attrs);
462 ast::foreign_item_fn(decl, purity, typarams) => {
463 print_fn(s, decl, Some(purity), item.ident, typarams, None,
465 end(s); // end head-ibox
467 end(s); // end the outer fn box
469 ast::foreign_item_const(t) => {
471 print_ident(s, item.ident);
475 end(s); // end the head-ibox
476 end(s); // end the outer cbox
481 pub fn print_item(s: @ps, &&item: @ast::item) {
482 hardbreak_if_not_bol(s);
483 maybe_print_comment(s, item.span.lo);
484 print_outer_attributes(s, item.attrs);
485 let ann_node = node_item(s, item);
486 (s.ann.pre)(ann_node);
488 ast::item_const(ty, expr) => {
489 head(s, visibility_qualified(item.vis, ~"const"));
490 print_ident(s, item.ident);
494 end(s); // end the head-ibox
499 end(s); // end the outer cbox
502 ast::item_fn(ref decl, purity, ref typarams, ref body) => {
505 /* FIXME (#2543) */ copy *decl,
508 /* FIXME (#2543) */ copy *typarams,
513 print_block_with_attrs(s, (*body), item.attrs);
515 ast::item_mod(_mod) => {
516 head(s, visibility_qualified(item.vis, ~"mod"));
517 print_ident(s, item.ident);
520 print_mod(s, _mod, item.attrs);
521 bclose(s, item.span);
523 ast::item_foreign_mod(nmod) => {
524 head(s, visibility_qualified(item.vis, ~"extern"));
525 print_string(s, *s.intr.get(nmod.abi));
529 word_nbsp(s, ~"mod");
530 print_ident(s, item.ident);
536 print_foreign_mod(s, nmod, item.attrs);
537 bclose(s, item.span);
539 ast::item_ty(ty, params) => {
540 ibox(s, indent_unit);
542 word_nbsp(s, visibility_qualified(item.vis, ~"type"));
543 print_ident(s, item.ident);
544 print_type_params(s, params);
545 end(s); // end the inner ibox
551 end(s); // end the outer ibox
553 ast::item_enum(ref enum_definition, ref params) => {
557 /* FIXME (#2543) */ copy *params,
563 ast::item_struct(struct_def, tps) => {
564 head(s, visibility_qualified(item.vis, ~"struct"));
565 print_struct(s, struct_def, tps, item.ident, item.span);
568 ast::item_impl(tps, opt_trait, ty, methods) => {
569 head(s, visibility_qualified(item.vis, ~"impl"));
571 print_type_params(s, tps);
577 print_path(s, t.path, false);
579 word_space(s, ~"for");
587 if methods.len() == 0 {
591 for methods.each |meth| {
592 print_method(s, *meth);
594 bclose(s, item.span);
597 ast::item_trait(ref tps, ref traits, ref methods) => {
598 head(s, visibility_qualified(item.vis, ~"trait"));
599 print_ident(s, item.ident);
600 print_type_params(s, /* FIXME (#2543) */ copy *tps);
601 if traits.len() != 0u {
603 for traits.each |trait_| {
605 print_path(s, trait_.path, false);
610 for (*methods).each |meth| {
611 print_trait_method(s, *meth);
613 bclose(s, item.span);
615 ast::item_mac(codemap::spanned { node: ast::mac_invoc_tt(pth, ref tts),
617 print_visibility(s, item.vis);
618 print_path(s, pth, false);
620 print_ident(s, item.ident);
621 cbox(s, indent_unit);
628 (s.ann.post)(ann_node);
631 pub fn print_enum_def(s: @ps, enum_definition: ast::enum_def,
632 params: ~[ast::ty_param], ident: ast::ident,
633 span: codemap::span, visibility: ast::visibility) {
635 vec::len(enum_definition.variants) == 1u &&
636 ident == enum_definition.variants[0].node.name;
638 match enum_definition.variants[0].node.kind {
639 ast::tuple_variant_kind(ref args) if args.len() == 1 => {}
644 ibox(s, indent_unit);
645 word_space(s, visibility_qualified(visibility, ~"enum"));
647 head(s, visibility_qualified(visibility, ~"enum"));
650 print_ident(s, ident);
651 print_type_params(s, params);
655 match enum_definition.variants[0].node.kind {
656 ast::tuple_variant_kind(args) => print_type(s, args[0].ty),
657 _ => fail!(~"newtype syntax with struct?")
662 print_variants(s, enum_definition.variants, span);
666 pub fn print_variants(s: @ps,
667 variants: ~[ast::variant],
668 span: codemap::span) {
670 for variants.each |v| {
672 maybe_print_comment(s, v.span.lo);
673 print_outer_attributes(s, v.node.attrs);
674 ibox(s, indent_unit);
675 print_variant(s, *v);
678 maybe_print_trailing_comment(s, v.span, None);
683 pub fn visibility_to_str(vis: ast::visibility) -> ~str {
685 ast::private => ~"priv",
686 ast::public => ~"pub",
687 ast::inherited => ~""
691 pub fn visibility_qualified(vis: ast::visibility, s: ~str) -> ~str {
693 ast::private | ast::public =>
694 visibility_to_str(vis) + " " + s,
699 pub fn print_visibility(s: @ps, vis: ast::visibility) {
701 ast::private | ast::public =>
702 word_nbsp(s, visibility_to_str(vis)),
707 pub fn print_struct(s: @ps,
708 struct_def: @ast::struct_def,
709 tps: ~[ast::ty_param],
711 span: codemap::span) {
712 print_ident(s, ident);
714 print_type_params(s, tps);
715 if ast_util::struct_def_is_tuple_like(struct_def) {
717 let mut first = true;
718 for struct_def.fields.each |field| {
725 match field.node.kind {
726 ast::named_field(*) => fail!(~"unexpected named field"),
727 ast::unnamed_field => {
728 maybe_print_comment(s, field.span.lo);
729 print_type(s, field.node.ty);
735 end(s); // close the outer-box
738 hardbreak_if_not_bol(s);
739 do struct_def.dtor.iter |dtor| {
740 hardbreak_if_not_bol(s);
741 maybe_print_comment(s, dtor.span.lo);
742 print_outer_attributes(s, dtor.node.attrs);
744 print_block(s, dtor.node.body);
747 for struct_def.fields.each |field| {
748 match field.node.kind {
749 ast::unnamed_field => fail!(~"unexpected unnamed field"),
750 ast::named_field(ident, mutability, visibility) => {
751 hardbreak_if_not_bol(s);
752 maybe_print_comment(s, field.span.lo);
753 print_visibility(s, visibility);
754 if mutability == ast::struct_mutable {
755 word_nbsp(s, ~"mut");
757 print_ident(s, ident);
759 print_type(s, field.node.ty);
769 /// This doesn't deserve to be called "pretty" printing, but it should be
770 /// meaning-preserving. A quick hack that might help would be to look at the
771 /// spans embedded in the TTs to decide where to put spaces and newlines.
772 /// But it'd be better to parse these according to the grammar of the
773 /// appropriate macro, transcribe back into the grammar we just parsed from,
774 /// and then pretty-print the resulting AST nodes (so, e.g., we print
775 /// expression arguments as expressions). It can be done! I think.
776 pub fn print_tt(s: @ps, tt: ast::token_tree) {
778 ast::tt_delim(ref tts) => print_tts(s, *tts),
779 ast::tt_tok(_, ref tk) => {
780 word(s.s, parse::token::to_str(s.intr, (*tk)));
782 ast::tt_seq(_, ref tts, ref sep, zerok) => {
784 for (*tts).each() |tt_elt| { print_tt(s, *tt_elt); }
787 Some(ref tk) => word(s.s, parse::token::to_str(s.intr, (*tk))),
790 word(s.s, if zerok { ~"*" } else { ~"+" });
792 ast::tt_nonterminal(_, name) => {
794 print_ident(s, name);
799 pub fn print_tts(s: @ps, &&tts: &[ast::token_tree]) {
801 for tts.eachi |i, tt| {
810 pub fn print_variant(s: @ps, v: ast::variant) {
811 print_visibility(s, v.node.vis);
813 ast::tuple_variant_kind(args) => {
814 print_ident(s, v.node.name);
815 if !args.is_empty() {
817 fn print_variant_arg(s: @ps, arg: ast::variant_arg) {
818 print_type(s, arg.ty);
820 commasep(s, consistent, args, print_variant_arg);
824 ast::struct_variant_kind(struct_def) => {
826 print_struct(s, struct_def, ~[], v.node.name, v.span);
828 ast::enum_variant_kind(ref enum_definition) => {
829 print_variants(s, (*enum_definition).variants, v.span);
832 match v.node.disr_expr {
842 pub fn print_ty_method(s: @ps, m: ast::ty_method) {
843 hardbreak_if_not_bol(s);
844 maybe_print_comment(s, m.span.lo);
845 print_outer_attributes(s, m.attrs);
846 print_ty_fn(s, None, None, None, m.purity, ast::Many,
847 m.decl, Some(m.ident), Some(m.tps),
848 Some(m.self_ty.node));
852 pub fn print_trait_method(s: @ps, m: ast::trait_method) {
854 required(ref ty_m) => print_ty_method(s, (*ty_m)),
855 provided(m) => print_method(s, m)
859 pub fn print_method(s: @ps, meth: @ast::method) {
860 hardbreak_if_not_bol(s);
861 maybe_print_comment(s, meth.span.lo);
862 print_outer_attributes(s, meth.attrs);
863 print_fn(s, meth.decl, Some(meth.purity),
864 meth.ident, meth.tps, Some(meth.self_ty.node),
867 print_block_with_attrs(s, meth.body, meth.attrs);
870 pub fn print_outer_attributes(s: @ps, attrs: ~[ast::attribute]) {
872 for attrs.each |attr| {
873 match attr.node.style {
874 ast::attr_outer => { print_attribute(s, *attr); count += 1; }
875 _ => {/* fallthrough */ }
878 if count > 0 { hardbreak_if_not_bol(s); }
881 pub fn print_inner_attributes(s: @ps, attrs: ~[ast::attribute]) {
883 for attrs.each |attr| {
884 match attr.node.style {
886 print_attribute(s, *attr);
887 if !attr.node.is_sugared_doc {
892 _ => {/* fallthrough */ }
895 if count > 0 { hardbreak_if_not_bol(s); }
898 pub fn print_attribute(s: @ps, attr: ast::attribute) {
899 hardbreak_if_not_bol(s);
900 maybe_print_comment(s, attr.span.lo);
901 if attr.node.is_sugared_doc {
902 let meta = attr::attr_meta(attr);
903 let comment = attr::get_meta_item_value_str(meta).get();
907 print_meta_item(s, @attr.node.value);
913 pub fn print_stmt(s: @ps, st: ast::stmt) {
914 maybe_print_comment(s, st.span.lo);
916 ast::stmt_decl(decl, _) => {
919 ast::stmt_expr(expr, _) => {
923 ast::stmt_semi(expr, _) => {
928 ast::stmt_mac(ref mac, semi) => {
930 print_mac(s, (*mac));
931 if semi { word(s.s, ~";"); }
934 if parse::classify::stmt_ends_with_semi(st) { word(s.s, ~";"); }
935 maybe_print_trailing_comment(s, st.span, None);
938 pub fn print_block(s: @ps, blk: ast::blk) {
939 print_possibly_embedded_block(s, blk, block_normal, indent_unit);
942 pub fn print_block_unclosed(s: @ps, blk: ast::blk) {
943 print_possibly_embedded_block_(s, blk, block_normal, indent_unit, ~[],
947 pub fn print_block_unclosed_indent(s: @ps, blk: ast::blk, indented: uint) {
948 print_possibly_embedded_block_(s, blk, block_normal, indented, ~[],
952 pub fn print_block_with_attrs(s: @ps,
954 attrs: ~[ast::attribute]) {
955 print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
959 pub enum embed_type { block_block_fn, block_normal, }
961 pub fn print_possibly_embedded_block(s: @ps,
963 embedded: embed_type,
965 print_possibly_embedded_block_(
966 s, blk, embedded, indented, ~[], true);
969 pub fn print_possibly_embedded_block_(s: @ps,
971 embedded: embed_type,
973 attrs: ~[ast::attribute],
975 match blk.node.rules {
976 ast::unsafe_blk => word_space(s, ~"unsafe"),
977 ast::default_blk => ()
979 maybe_print_comment(s, blk.span.lo);
980 let ann_node = node_block(s, blk);
981 (s.ann.pre)(ann_node);
983 block_block_fn => end(s),
984 block_normal => bopen(s)
987 print_inner_attributes(s, attrs);
989 for blk.node.view_items.each |vi| { print_view_item(s, *vi); }
990 for blk.node.stmts.each |st| {
993 match blk.node.expr {
997 maybe_print_trailing_comment(s, expr.span, Some(blk.span.hi));
1001 bclose_maybe_open(s, blk.span, indented, close_box);
1002 (s.ann.post)(ann_node);
1005 pub fn print_if(s: @ps, test: @ast::expr, blk: ast::blk,
1006 elseopt: Option<@ast::expr>, chk: bool) {
1008 if chk { word_nbsp(s, ~"check"); }
1009 print_expr(s, test);
1011 print_block(s, blk);
1012 fn do_else(s: @ps, els: Option<@ast::expr>) {
1016 // "another else-if"
1017 ast::expr_if(i, ref t, e) => {
1018 cbox(s, indent_unit - 1u);
1020 word(s.s, ~" else if ");
1023 print_block(s, (*t));
1027 ast::expr_block(ref b) => {
1028 cbox(s, indent_unit - 1u);
1030 word(s.s, ~" else ");
1031 print_block(s, (*b));
1033 // BLEAH, constraints would be great here
1035 fail!(~"print_if saw if with weird alternative");
1039 _ => {/* fall through */ }
1042 do_else(s, elseopt);
1045 pub fn print_mac(s: @ps, m: ast::mac) {
1047 ast::mac_invoc_tt(pth, ref tts) => {
1048 print_path(s, pth, false);
1057 pub fn print_vstore(s: @ps, t: ast::vstore) {
1059 ast::vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
1060 ast::vstore_fixed(None) => word(s.s, ~"_"),
1061 ast::vstore_uniq => word(s.s, ~"~"),
1062 ast::vstore_box => word(s.s, ~"@"),
1063 ast::vstore_slice(r) => print_region(s, ~"&", r, ~"/")
1067 pub fn print_expr_vstore(s: @ps, t: ast::expr_vstore) {
1069 ast::expr_vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
1070 ast::expr_vstore_fixed(None) => word(s.s, ~"_"),
1071 ast::expr_vstore_uniq => word(s.s, ~"~"),
1072 ast::expr_vstore_box => word(s.s, ~"@"),
1073 ast::expr_vstore_mut_box => {
1077 ast::expr_vstore_slice => word(s.s, ~"&"),
1078 ast::expr_vstore_mut_slice => {
1085 pub fn print_call_pre(s: @ps,
1086 sugar: ast::CallSugar,
1087 base_args: &mut ~[@ast::expr])
1088 -> Option<@ast::expr> {
1092 Some(base_args.pop())
1096 Some(base_args.pop())
1098 ast::NoSugar => None
1102 pub fn print_call_post(s: @ps,
1103 sugar: ast::CallSugar,
1104 blk: &Option<@ast::expr>,
1105 base_args: &mut ~[@ast::expr]) {
1106 if sugar == ast::NoSugar || !base_args.is_empty() {
1108 commasep_exprs(s, inconsistent, *base_args);
1111 if sugar != ast::NoSugar {
1113 match blk.get().node {
1114 // need to handle closures specifically
1115 ast::expr_do_body(e) | ast::expr_loop_body(e) => {
1116 end(s); // we close our head box; closure
1117 // will create it's own.
1119 end(s); // close outer box, as closures don't
1122 // not sure if this can happen.
1123 print_expr(s, blk.get());
1129 pub fn print_expr(s: @ps, &&expr: @ast::expr) {
1130 fn print_field(s: @ps, field: ast::field) {
1131 ibox(s, indent_unit);
1132 if field.node.mutbl == ast::m_mutbl { word_nbsp(s, ~"mut"); }
1133 print_ident(s, field.node.ident);
1134 word_space(s, ~":");
1135 print_expr(s, field.node.expr);
1138 fn get_span(field: ast::field) -> codemap::span { return field.span; }
1140 maybe_print_comment(s, expr.span.lo);
1141 ibox(s, indent_unit);
1142 let ann_node = node_expr(s, expr);
1143 (s.ann.pre)(ann_node);
1145 ast::expr_vstore(e, v) => match v {
1146 ast::expr_vstore_fixed(_) => {
1149 print_expr_vstore(s, v);
1152 print_expr_vstore(s, v);
1156 ast::expr_vec(exprs, mutbl) => {
1157 ibox(s, indent_unit);
1159 if mutbl == ast::m_mutbl {
1161 if vec::len(exprs) > 0u { nbsp(s); }
1163 commasep_exprs(s, inconsistent, exprs);
1168 ast::expr_repeat(element, count, mutbl) => {
1169 ibox(s, indent_unit);
1171 if mutbl == ast::m_mutbl {
1175 print_expr(s, element);
1178 print_expr(s, count);
1183 ast::expr_rec(ref fields, wth) => {
1185 commasep_cmnt(s, consistent, (*fields), print_field, get_span);
1188 ibox(s, indent_unit);
1192 print_expr(s, expr);
1195 _ => word(s.s, ~",")
1199 ast::expr_struct(path, ref fields, wth) => {
1200 print_path(s, path, true);
1202 commasep_cmnt(s, consistent, (*fields), print_field, get_span);
1205 ibox(s, indent_unit);
1209 print_expr(s, expr);
1212 _ => word(s.s, ~",")
1216 ast::expr_tup(exprs) => {
1218 commasep_exprs(s, inconsistent, exprs);
1219 if exprs.len() == 1 {
1224 ast::expr_call(func, args, sugar) => {
1225 let mut base_args = copy args;
1226 let blk = print_call_pre(s, sugar, &mut base_args);
1227 print_expr(s, func);
1228 print_call_post(s, sugar, &blk, &mut base_args);
1230 ast::expr_method_call(func, ident, tys, args, sugar) => {
1231 let mut base_args = copy args;
1232 let blk = print_call_pre(s, sugar, &mut base_args);
1233 print_expr(s, func);
1235 print_ident(s, ident);
1236 if vec::len(tys) > 0u {
1238 commasep(s, inconsistent, tys, print_type);
1241 print_call_post(s, sugar, &blk, &mut base_args);
1243 ast::expr_binary(op, lhs, rhs) => {
1246 word_space(s, ast_util::binop_to_str(op));
1249 ast::expr_unary(op, expr) => {
1250 word(s.s, ast_util::unop_to_str(op));
1251 print_expr(s, expr);
1253 ast::expr_addr_of(m, expr) => {
1255 print_mutability(s, m);
1256 print_expr(s, expr);
1258 ast::expr_lit(lit) => print_literal(s, lit),
1259 ast::expr_cast(expr, ty) => {
1260 print_expr(s, expr);
1262 word_space(s, ~"as");
1263 print_type_ex(s, ty, true);
1265 ast::expr_if(test, ref blk, elseopt) => {
1266 print_if(s, test, (*blk), elseopt, false);
1268 ast::expr_while(test, ref blk) => {
1270 print_expr(s, test);
1272 print_block(s, (*blk));
1274 ast::expr_loop(ref blk, opt_ident) => {
1277 opt_ident.iter(|ident| {
1278 print_ident(s, *ident);
1279 word_space(s, ~":");
1281 print_block(s, (*blk));
1283 ast::expr_match(expr, ref arms) => {
1284 cbox(s, match_indent_unit);
1286 word_nbsp(s, ~"match");
1287 print_expr(s, expr);
1290 let len = (*arms).len();
1291 for (*arms).eachi |i, arm| {
1293 cbox(s, match_indent_unit);
1295 let mut first = true;
1296 for arm.pats.each |p| {
1299 } else { space(s.s); word_space(s, ~"|"); }
1300 print_refutable_pat(s, *p);
1305 word_space(s, ~"if");
1311 word_space(s, ~"=>");
1313 // Extract the expression from the extra block the parser adds
1314 // in the case of foo => expr
1315 if arm.body.node.view_items.is_empty() &&
1316 arm.body.node.stmts.is_empty() &&
1317 arm.body.node.rules == ast::default_blk &&
1318 arm.body.node.expr.is_some()
1320 match arm.body.node.expr {
1323 ast::expr_block(ref blk) => {
1324 // the block will close the pattern's ibox
1325 print_block_unclosed_indent(
1326 s, (*blk), match_indent_unit);
1329 end(s); // close the ibox for the pattern
1330 print_expr(s, expr);
1333 if !expr_is_simple_block(expr)
1337 end(s); // close enclosing cbox
1342 // the block will close the pattern's ibox
1343 print_block_unclosed_indent(s, arm.body, match_indent_unit);
1346 bclose_(s, expr.span, match_indent_unit);
1348 ast::expr_fn(sigil, ref decl, ref body, _) => {
1349 // containing cbox, will be closed by print-block at }
1350 cbox(s, indent_unit);
1351 // head-box, will be closed by print-block at start
1353 print_fn_header_info(s, None, None, ast::Many,
1354 Some(sigil), ast::inherited);
1355 print_fn_args_and_ret(s, /* FIXME (#2543) */ copy *decl, None);
1357 print_block(s, (*body));
1359 ast::expr_fn_block(ref decl, ref body) => {
1360 // in do/for blocks we don't want to show an empty
1361 // argument list, but at this point we don't know which
1364 // if !decl.inputs.is_empty() {
1365 print_fn_block_args(s, /* FIXME (#2543) */ copy *decl);
1368 assert (*body).node.stmts.is_empty();
1369 assert (*body).node.expr.is_some();
1370 // we extract the block, so as not to create another set of boxes
1371 match (*body).node.expr.get().node {
1372 ast::expr_block(ref blk) => {
1373 print_block_unclosed(s, (*blk));
1376 // this is a bare expression
1377 print_expr(s, (*body).node.expr.get());
1378 end(s); // need to close a box
1381 // a box will be closed by print_expr, but we didn't want an overall
1382 // wrapper so we closed the corresponding opening. so create an
1383 // empty box to satisfy the close.
1386 ast::expr_loop_body(body) => {
1387 print_expr(s, body);
1389 ast::expr_do_body(body) => {
1390 print_expr(s, body);
1392 ast::expr_block(ref blk) => {
1393 // containing cbox, will be closed by print-block at }
1394 cbox(s, indent_unit);
1395 // head-box, will be closed by print-block after {
1397 print_block(s, (*blk));
1399 ast::expr_copy(e) => { word_space(s, ~"copy"); print_expr(s, e); }
1400 ast::expr_assign(lhs, rhs) => {
1403 word_space(s, ~"=");
1406 ast::expr_swap(lhs, rhs) => {
1409 word_space(s, ~"<->");
1412 ast::expr_assign_op(op, lhs, rhs) => {
1415 word(s.s, ast_util::binop_to_str(op));
1416 word_space(s, ~"=");
1419 ast::expr_field(expr, id, tys) => {
1420 print_expr(s, expr);
1423 if vec::len(tys) > 0u {
1425 commasep(s, inconsistent, tys, print_type);
1429 ast::expr_index(expr, index) => {
1430 print_expr(s, expr);
1432 print_expr(s, index);
1435 ast::expr_path(path) => print_path(s, path, true),
1436 ast::expr_break(opt_ident) => {
1437 word(s.s, ~"break");
1439 opt_ident.iter(|ident| {print_ident(s, *ident); space(s.s)});
1441 ast::expr_again(opt_ident) => {
1444 opt_ident.iter(|ident| {print_ident(s, *ident); space(s.s)});
1446 ast::expr_ret(result) => {
1447 word(s.s, ~"return");
1449 Some(expr) => { word(s.s, ~" "); print_expr(s, expr); }
1453 ast::expr_log(lvl, lexp, expr) => {
1455 ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); }
1456 ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); }
1458 word_nbsp(s, ~"log");
1460 print_expr(s, lexp);
1462 space_if_not_bol(s);
1463 print_expr(s, expr);
1468 ast::expr_assert(expr) => {
1469 word_nbsp(s, ~"assert");
1470 print_expr(s, expr);
1472 ast::expr_mac(ref m) => print_mac(s, (*m)),
1473 ast::expr_paren(e) => {
1479 (s.ann.post)(ann_node);
1483 pub fn print_local_decl(s: @ps, loc: @ast::local) {
1484 print_irrefutable_pat(s, loc.node.pat);
1485 match loc.node.ty.node {
1486 ast::ty_infer => (),
1487 _ => { word_space(s, ~":"); print_type(s, loc.node.ty); }
1491 pub fn print_decl(s: @ps, decl: @ast::decl) {
1492 maybe_print_comment(s, decl.span.lo);
1494 ast::decl_local(locs) => {
1495 space_if_not_bol(s);
1496 ibox(s, indent_unit);
1497 word_nbsp(s, ~"let");
1499 // if any are mut, all are mut
1500 if vec::any(locs, |l| l.node.is_mutbl) {
1501 assert vec::all(locs, |l| l.node.is_mutbl);
1502 word_nbsp(s, ~"mut");
1505 fn print_local(s: @ps, &&loc: @ast::local) {
1506 ibox(s, indent_unit);
1507 print_local_decl(s, loc);
1509 match loc.node.init {
1512 word_space(s, ~"=");
1513 print_expr(s, init);
1518 commasep(s, consistent, locs, print_local);
1521 ast::decl_item(item) => print_item(s, item)
1525 pub fn print_ident(s: @ps, ident: ast::ident) {
1526 word(s.s, *s.intr.get(ident));
1529 pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
1530 print_local_decl(s, loc);
1532 word_space(s, ~"in");
1533 print_expr(s, coll);
1536 pub fn print_path(s: @ps, &&path: @ast::path, colons_before_params: bool) {
1537 maybe_print_comment(s, path.span.lo);
1538 if path.global { word(s.s, ~"::"); }
1539 let mut first = true;
1540 for path.idents.each |id| {
1541 if first { first = false; } else { word(s.s, ~"::"); }
1542 print_ident(s, *id);
1544 if path.rp.is_some() || !path.types.is_empty() {
1545 if colons_before_params { word(s.s, ~"::"); }
1548 None => { /* ok */ }
1551 print_region(s, ~"&", r, ~"");
1555 if !path.types.is_empty() {
1557 commasep(s, inconsistent, path.types, print_type);
1563 pub fn print_irrefutable_pat(s: @ps, &&pat: @ast::pat) {
1564 print_pat(s, pat, false)
1567 pub fn print_refutable_pat(s: @ps, &&pat: @ast::pat) {
1568 print_pat(s, pat, true)
1571 pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) {
1572 maybe_print_comment(s, pat.span.lo);
1573 let ann_node = node_pat(s, pat);
1574 (s.ann.pre)(ann_node);
1575 /* Pat isn't normalized, but the beauty of it
1576 is that it doesn't matter */
1578 ast::pat_wild => word(s.s, ~"_"),
1579 ast::pat_ident(binding_mode, path, sub) => {
1581 match binding_mode {
1582 ast::bind_by_ref(mutbl) => {
1583 word_nbsp(s, ~"ref");
1584 print_mutability(s, mutbl);
1586 ast::bind_by_copy => {
1587 word_nbsp(s, ~"copy");
1589 ast::bind_infer => {}
1592 print_path(s, path, true);
1596 print_pat(s, p, refutable);
1601 ast::pat_enum(path, args_) => {
1602 print_path(s, path, true);
1604 None => word(s.s, ~"(*)"),
1606 if !args.is_empty() {
1608 commasep(s, inconsistent, args,
1609 |s, p| print_pat(s, p, refutable));
1615 ast::pat_rec(fields, etc) => {
1617 fn print_field(s: @ps, f: ast::field_pat, refutable: bool) {
1618 cbox(s, indent_unit);
1619 print_ident(s, f.ident);
1620 word_space(s, ~":");
1621 print_pat(s, f.pat, refutable);
1624 fn get_span(f: ast::field_pat) -> codemap::span { return f.pat.span; }
1625 commasep_cmnt(s, consistent, fields,
1626 |s, f| print_field(s, f, refutable),
1629 if vec::len(fields) != 0u { word_space(s, ~","); }
1634 ast::pat_struct(path, fields, etc) => {
1635 print_path(s, path, true);
1637 fn print_field(s: @ps, f: ast::field_pat, refutable: bool) {
1638 cbox(s, indent_unit);
1639 print_ident(s, f.ident);
1640 word_space(s, ~":");
1641 print_pat(s, f.pat, refutable);
1644 fn get_span(f: ast::field_pat) -> codemap::span { return f.pat.span; }
1645 commasep_cmnt(s, consistent, fields,
1646 |s, f| print_field(s,f,refutable),
1649 if vec::len(fields) != 0u { word_space(s, ~","); }
1654 ast::pat_tup(elts) => {
1656 commasep(s, inconsistent, elts, |s, p| print_pat(s, p, refutable));
1657 if elts.len() == 1 {
1662 ast::pat_box(inner) => {
1664 print_pat(s, inner, refutable);
1666 ast::pat_uniq(inner) => {
1668 print_pat(s, inner, refutable);
1670 ast::pat_region(inner) => {
1672 print_pat(s, inner, refutable);
1674 ast::pat_lit(e) => print_expr(s, e),
1675 ast::pat_range(begin, end) => {
1676 print_expr(s, begin);
1681 ast::pat_vec(elts, tail) => {
1683 commasep(s, inconsistent, elts, |s, p| print_pat(s, p, refutable));
1684 do option::iter(&tail) |tail| {
1685 if vec::len(elts) != 0u { word_space(s, ~","); }
1687 print_pat(s, *tail, refutable);
1692 (s.ann.post)(ann_node);
1695 // Returns whether it printed anything
1696 pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool {
1698 ast::sty_static | ast::sty_by_ref => { return false; }
1699 ast::sty_value => { word(s.s, ~"self"); }
1700 ast::sty_region(m) => {
1701 word(s.s, ~"&"); print_mutability(s, m); word(s.s, ~"self");
1703 ast::sty_box(m) => {
1704 word(s.s, ~"@"); print_mutability(s, m); word(s.s, ~"self");
1706 ast::sty_uniq(m) => {
1707 word(s.s, ~"~"); print_mutability(s, m); word(s.s, ~"self");
1713 pub fn print_fn(s: @ps,
1715 purity: Option<ast::purity>,
1717 typarams: ~[ast::ty_param],
1718 opt_self_ty: Option<ast::self_ty_>,
1719 vis: ast::visibility) {
1721 print_fn_header_info(s, opt_self_ty, purity, ast::Many, None, vis);
1723 print_ident(s, name);
1724 print_type_params(s, typarams);
1725 print_fn_args_and_ret(s, decl, opt_self_ty);
1728 pub fn print_fn_args(s: @ps, decl: ast::fn_decl,
1729 opt_self_ty: Option<ast::self_ty_>) {
1730 // It is unfortunate to duplicate the commasep logic, but we we want the
1731 // self type and the args all in the same box.
1732 box(s, 0u, inconsistent);
1733 let mut first = true;
1734 for opt_self_ty.each |self_ty| {
1735 first = !print_self_ty(s, *self_ty);
1738 for decl.inputs.each |arg| {
1739 if first { first = false; } else { word_space(s, ~","); }
1746 pub fn print_fn_args_and_ret(s: @ps, decl: ast::fn_decl,
1747 opt_self_ty: Option<ast::self_ty_>) {
1749 print_fn_args(s, decl, opt_self_ty);
1752 maybe_print_comment(s, decl.output.span.lo);
1753 match decl.output.node {
1756 space_if_not_bol(s);
1757 word_space(s, ~"->");
1758 print_type(s, decl.output);
1763 pub fn print_fn_block_args(s: @ps, decl: ast::fn_decl) {
1765 print_fn_args(s, decl, None);
1768 match decl.output.node {
1771 space_if_not_bol(s);
1772 word_space(s, ~"->");
1773 print_type(s, decl.output);
1777 maybe_print_comment(s, decl.output.span.lo);
1780 pub fn mode_to_str(m: ast::mode) -> ~str {
1782 ast::expl(ast::by_ref) => ~"&&",
1783 ast::expl(ast::by_copy) => ~"+",
1784 ast::expl(ast::by_val) => ~"++",
1785 ast::infer(_) => ~""
1789 pub fn print_arg_mode(s: @ps, m: ast::mode) {
1790 let ms = mode_to_str(m);
1791 if ms != ~"" { word(s.s, ms); }
1794 pub fn print_bounds(s: @ps, bounds: @~[ast::ty_param_bound]) {
1795 if !bounds.is_empty() {
1797 let mut first = true;
1798 for vec::each(*bounds) |&bound| {
1803 word_space(s, ~"+");
1807 TraitTyParamBound(ty) => print_type(s, ty),
1808 RegionTyParamBound => word(s.s, ~"&static"),
1814 pub fn print_type_params(s: @ps, &¶ms: ~[ast::ty_param]) {
1815 if vec::len(params) > 0u {
1817 fn printParam(s: @ps, param: ast::ty_param) {
1818 print_ident(s, param.ident);
1819 print_bounds(s, param.bounds);
1821 commasep(s, inconsistent, params, printParam);
1826 pub fn print_meta_item(s: @ps, &&item: @ast::meta_item) {
1827 ibox(s, indent_unit);
1829 ast::meta_word(name) => word(s.s, *name),
1830 ast::meta_name_value(name, value) => {
1831 word_space(s, *name);
1832 word_space(s, ~"=");
1833 print_literal(s, @value);
1835 ast::meta_list(name, ref items) => {
1841 /* FIXME (#2543) */ copy *items,
1850 pub fn print_view_path(s: @ps, &&vp: @ast::view_path) {
1852 ast::view_path_simple(ident, path, namespace, _) => {
1853 if namespace == ast::module_ns {
1854 word_space(s, ~"mod");
1856 if path.idents[vec::len(path.idents)-1u] != ident {
1857 print_ident(s, ident);
1859 word_space(s, ~"=");
1861 print_path(s, path, false);
1864 ast::view_path_glob(path, _) => {
1865 print_path(s, path, false);
1869 ast::view_path_list(path, ref idents, _) => {
1870 print_path(s, path, false);
1872 do commasep(s, inconsistent, (*idents)) |s, w| {
1873 print_ident(s, w.node.name);
1880 pub fn print_view_paths(s: @ps, vps: ~[@ast::view_path]) {
1881 commasep(s, inconsistent, vps, print_view_path);
1884 pub fn print_view_item(s: @ps, item: @ast::view_item) {
1885 hardbreak_if_not_bol(s);
1886 maybe_print_comment(s, item.span.lo);
1887 print_outer_attributes(s, item.attrs);
1888 print_visibility(s, item.vis);
1890 ast::view_item_extern_mod(id, mta, _) => {
1891 head(s, ~"extern mod");
1893 if !mta.is_empty() {
1895 commasep(s, consistent, mta, print_meta_item);
1900 ast::view_item_use(vps) => {
1902 print_view_paths(s, vps);
1906 end(s); // end inner head-block
1907 end(s); // end outer head-block
1910 pub fn print_mutability(s: @ps, mutbl: ast::mutability) {
1912 ast::m_mutbl => word_nbsp(s, ~"mut"),
1913 ast::m_const => word_nbsp(s, ~"const"),
1914 ast::m_imm => {/* nothing */ }
1918 pub fn print_mt(s: @ps, mt: ast::mt) {
1919 print_mutability(s, mt.mutbl);
1920 print_type(s, mt.ty);
1923 pub fn print_arg(s: @ps, input: ast::arg) {
1924 ibox(s, indent_unit);
1925 print_arg_mode(s, input.mode);
1927 word_space(s, ~"mut");
1929 match input.ty.node {
1930 ast::ty_infer => print_irrefutable_pat(s, input.pat),
1932 match input.pat.node {
1933 ast::pat_ident(_, path, _) if
1934 path.idents.len() == 1 &&
1935 path.idents[0] == parse::token::special_idents::invalid => {
1939 print_irrefutable_pat(s, input.pat);
1944 print_type(s, input.ty);
1950 pub fn print_ty_fn(s: @ps,
1951 opt_abi: Option<ast::Abi>,
1952 opt_sigil: Option<ast::Sigil>,
1953 opt_region: Option<@ast::region>,
1954 purity: ast::purity,
1955 onceness: ast::Onceness,
1956 decl: ast::fn_decl, id: Option<ast::ident>,
1957 tps: Option<~[ast::ty_param]>,
1958 opt_self_ty: Option<ast::self_ty_>) {
1959 ibox(s, indent_unit);
1961 // Duplicates the logic in `print_fn_header_info()`. This is because that
1962 // function prints the sigil in the wrong place. That should be fixed.
1963 print_self_ty_if_static(s, opt_self_ty);
1964 print_opt_abi(s, opt_abi);
1965 print_opt_sigil(s, opt_sigil);
1966 for opt_region.each |r| { print_region(s, ~"", *r, ~"/"); }
1967 print_purity(s, purity);
1968 print_onceness(s, onceness);
1970 match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
1971 match tps { Some(tps) => print_type_params(s, tps), _ => () }
1975 // It is unfortunate to duplicate the commasep logic, but we we want the
1976 // self type and the args all in the same box.
1977 box(s, 0u, inconsistent);
1978 let mut first = true;
1979 for opt_self_ty.each |self_ty| {
1980 first = !print_self_ty(s, *self_ty);
1982 for decl.inputs.each |arg| {
1983 if first { first = false; } else { word_space(s, ~","); }
1989 maybe_print_comment(s, decl.output.span.lo);
1991 match decl.output.node {
1994 space_if_not_bol(s);
1995 ibox(s, indent_unit);
1996 word_space(s, ~"->");
1997 if decl.cf == ast::noreturn { word_nbsp(s, ~"!"); }
1998 else { print_type(s, decl.output); }
2006 pub fn maybe_print_trailing_comment(s: @ps, span: codemap::span,
2007 next_pos: Option<BytePos>) {
2009 match s.cm { Some(ccm) => cm = ccm, _ => return }
2010 match next_comment(s) {
2012 if (*cmnt).style != comments::trailing { return; }
2013 let span_line = cm.lookup_char_pos(span.hi);
2014 let comment_line = cm.lookup_char_pos((*cmnt).pos);
2015 let mut next = (*cmnt).pos + BytePos(1u);
2016 match next_pos { None => (), Some(p) => next = p }
2017 if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
2018 span_line.line == comment_line.line {
2019 print_comment(s, (*cmnt));
2020 s.cur_cmnt_and_lit.cur_cmnt += 1u;
2027 pub fn print_remaining_comments(s: @ps) {
2028 // If there aren't any remaining comments, then we need to manually
2029 // make sure there is a line break at the end.
2030 if next_comment(s).is_none() { hardbreak(s.s); }
2032 match next_comment(s) {
2034 print_comment(s, (*cmnt));
2035 s.cur_cmnt_and_lit.cur_cmnt += 1u;
2042 pub fn print_literal(s: @ps, &&lit: @ast::lit) {
2043 maybe_print_comment(s, lit.span.lo);
2044 match next_lit(s, lit.span.lo) {
2046 word(s.s, (*ltrl).lit);
2052 ast::lit_str(st) => print_string(s, *st),
2053 ast::lit_int(ch, ast::ty_char) => {
2054 word(s.s, ~"'" + char::escape_default(ch as char) + ~"'");
2056 ast::lit_int(i, t) => {
2059 ~"-" + u64::to_str_radix(-i as u64, 10u)
2060 + ast_util::int_ty_to_str(t));
2063 u64::to_str_radix(i as u64, 10u)
2064 + ast_util::int_ty_to_str(t));
2067 ast::lit_uint(u, t) => {
2069 u64::to_str_radix(u, 10u)
2070 + ast_util::uint_ty_to_str(t));
2072 ast::lit_int_unsuffixed(i) => {
2074 word(s.s, ~"-" + u64::to_str_radix(-i as u64, 10u));
2076 word(s.s, u64::to_str_radix(i as u64, 10u));
2079 ast::lit_float(f, t) => {
2080 word(s.s, *f + ast_util::float_ty_to_str(t));
2082 ast::lit_float_unsuffixed(f) => word(s.s, *f),
2083 ast::lit_nil => word(s.s, ~"()"),
2084 ast::lit_bool(val) => {
2085 if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); }
2090 pub fn lit_to_str(l: @ast::lit) -> ~str {
2091 return to_str(l, print_literal, parse::token::mk_fake_ident_interner());
2094 pub fn next_lit(s: @ps, pos: BytePos) -> Option<comments::lit> {
2097 while s.cur_cmnt_and_lit.cur_lit < vec::len((*lits)) {
2098 let ltrl = (*lits)[s.cur_cmnt_and_lit.cur_lit];
2099 if ltrl.pos > pos { return None; }
2100 s.cur_cmnt_and_lit.cur_lit += 1u;
2101 if ltrl.pos == pos { return Some(ltrl); }
2109 pub fn maybe_print_comment(s: @ps, pos: BytePos) {
2111 match next_comment(s) {
2113 if (*cmnt).pos < pos {
2114 print_comment(s, (*cmnt));
2115 s.cur_cmnt_and_lit.cur_cmnt += 1u;
2123 pub fn print_comment(s: @ps, cmnt: comments::cmnt) {
2125 comments::mixed => {
2126 assert (vec::len(cmnt.lines) == 1u);
2128 word(s.s, cmnt.lines[0]);
2131 comments::isolated => {
2132 pprust::hardbreak_if_not_bol(s);
2133 for cmnt.lines.each |line| {
2134 // Don't print empty lines because they will end up as trailing
2136 if !line.is_empty() { word(s.s, *line); }
2140 comments::trailing => {
2142 if vec::len(cmnt.lines) == 1u {
2143 word(s.s, cmnt.lines[0]);
2147 for cmnt.lines.each |line| {
2148 if !line.is_empty() { word(s.s, *line); }
2154 comments::blank_line => {
2155 // We need to do at least one, possibly two hardbreaks.
2157 match s.s.last_token() {
2158 pp::STRING(s, _) => *s == ~";",
2161 if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); }
2167 pub fn print_string(s: @ps, st: ~str) {
2169 word(s.s, str::escape_default(st));
2173 pub fn to_str<T>(t: T, f: fn@(@ps, T), intr: @ident_interner) -> ~str {
2174 do io::with_str_writer |wr| {
2175 let s = rust_printer(wr, intr);
2181 pub fn next_comment(s: @ps) -> Option<comments::cmnt> {
2183 Some(ref cmnts) => {
2184 if s.cur_cmnt_and_lit.cur_cmnt < vec::len((*cmnts)) {
2185 return Some((*cmnts)[s.cur_cmnt_and_lit.cur_cmnt]);
2186 } else { return None::<comments::cmnt>; }
2188 _ => return None::<comments::cmnt>
2192 pub fn print_self_ty_if_static(s: @ps,
2193 opt_self_ty: Option<ast::self_ty_>) {
2195 Some(ast::sty_static) => { word(s.s, ~"static "); }
2200 pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
2202 Some(ast::impure_fn) => { }
2204 word_nbsp(s, purity_to_str(purity));
2210 pub fn print_opt_abi(s: @ps, opt_abi: Option<ast::Abi>) {
2212 Some(ast::RustAbi) => { word_nbsp(s, ~"extern"); }
2217 pub fn print_opt_sigil(s: @ps, opt_sigil: Option<ast::Sigil>) {
2219 Some(ast::BorrowedSigil) => { word(s.s, ~"&"); }
2220 Some(ast::OwnedSigil) => { word(s.s, ~"~"); }
2221 Some(ast::ManagedSigil) => { word(s.s, ~"@"); }
2226 pub fn print_fn_header_info(s: @ps,
2227 opt_sty: Option<ast::self_ty_>,
2228 opt_purity: Option<ast::purity>,
2229 onceness: ast::Onceness,
2230 opt_sigil: Option<ast::Sigil>,
2231 vis: ast::visibility) {
2232 print_self_ty_if_static(s, opt_sty);
2233 word(s.s, visibility_qualified(vis, ~""));
2234 print_opt_purity(s, opt_purity);
2235 print_onceness(s, onceness);
2237 print_opt_sigil(s, opt_sigil);
2240 pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> ~str {
2243 Some(p) => fmt!("fn%s", p.to_str())
2247 pub pure fn purity_to_str(p: ast::purity) -> ~str {
2249 ast::impure_fn => ~"impure",
2250 ast::unsafe_fn => ~"unsafe",
2251 ast::pure_fn => ~"pure",
2252 ast::extern_fn => ~"extern"
2256 pub pure fn onceness_to_str(o: ast::Onceness) -> ~str {
2258 ast::Once => ~"once",
2259 ast::Many => ~"many"
2263 pub fn print_purity(s: @ps, p: ast::purity) {
2265 ast::impure_fn => (),
2266 _ => word_nbsp(s, purity_to_str(p))
2270 pub fn print_onceness(s: @ps, o: ast::Onceness) {
2272 ast::Once => { word_nbsp(s, ~"once"); }
2284 use util::testing::check_equal;
2286 fn string_check<T:Eq> (given : &T, expected: &T) {
2287 if !(given == expected) {
2288 fail!(fmt!("given %?, expected %?",given,expected));
2293 fn test_fun_to_str() {
2294 let mock_interner = parse::token::mk_fake_ident_interner();
2295 let abba_ident = mock_interner.intern(@~"abba");
2297 let decl: ast::fn_decl = ast::fn_decl {
2299 output: @ast::Ty {id: 0,
2301 span: codemap::dummy_sp()},
2304 check_equal (&fun_to_str(decl, abba_ident, ~[],mock_interner),
2309 fn test_variant_to_str() {
2310 let mock_interner = parse::token::mk_fake_ident_interner();
2311 let ident = mock_interner.intern(@~"principal_skinner");
2313 let var = codemap::respan(codemap::dummy_sp(), ast::variant_ {
2316 // making this up as I go.... ?
2317 kind: ast::tuple_variant_kind(~[]),
2323 let varstr = variant_to_str(var,mock_interner);
2324 check_equal(&varstr,&~"pub principal_skinner");
2332 // indent-tabs-mode: nil
2333 // c-basic-offset: 4
2334 // buffer-file-coding-system: utf-8-unix