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};
18 use codemap::{CodeMap, BytePos};
21 use parse::classify::{expr_is_simple_block, expr_requires_semi_to_be_stmt};
22 use parse::token::ident_interner;
23 use parse::{comments, lexer, token};
25 use print::pp::{break_offset, word, Printer, space, zerobreak, hardbreak};
26 use print::pp::{breaks, consistent, inconsistent, eof};
36 // The @ps is stored here to prevent recursive type.
37 pub enum ann_node<'self> {
38 node_block(@ps, &'self ast::blk),
39 node_item(@ps, @ast::item),
40 node_expr(@ps, @ast::expr),
41 node_pat(@ps, @ast::pat),
48 pub fn no_ann() -> pp_ann {
49 fn ignore(_node: ann_node) { }
50 return pp_ann {pre: ignore, post: ignore};
53 pub struct CurrentCommentAndLiteral {
61 intr: @token::ident_interner,
62 comments: Option<~[comments::cmnt]>,
63 literals: Option<~[comments::lit]>,
64 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
65 boxes: @mut ~[pp::breaks],
69 pub fn ibox(s: @ps, u: uint) {
70 s.boxes.push(pp::inconsistent);
79 pub fn rust_printer(writer: io::Writer, intr: @ident_interner) -> @ps {
81 s: pp::mk_printer(writer, default_columns),
84 comments: None::<~[comments::cmnt]>,
85 literals: None::<~[comments::lit]>,
86 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
95 pub const indent_unit: uint = 4u;
96 pub const match_indent_unit: uint = 2u;
98 pub const default_columns: uint = 78u;
100 // Requires you to pass an input filename and reader so that
101 // it can scan the input text for comments and literals to
103 pub fn print_crate(cm: @CodeMap, intr: @ident_interner,
104 span_diagnostic: diagnostic::span_handler,
105 crate: @ast::crate, filename: ~str, in: io::Reader,
106 out: io::Writer, ann: pp_ann, is_expanded: bool) {
107 let (cmnts, lits) = comments::gather_comments_and_literals(
113 s: pp::mk_printer(out, default_columns),
116 comments: Some(copy cmnts),
117 // If the code is post expansion, don't use the table of
118 // literals, since it doesn't correspond with the literals
119 // in the AST anymore.
120 literals: if is_expanded { None } else { Some(copy lits) },
121 cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
128 print_crate_(s, crate);
131 pub fn print_crate_(s: @ps, &&crate: @ast::crate) {
132 print_mod(s, crate.node.module, crate.node.attrs);
133 print_remaining_comments(s);
137 pub fn ty_to_str(ty: @ast::Ty, intr: @ident_interner) -> ~str {
138 to_str(ty, print_type, intr)
141 pub fn pat_to_str(pat: @ast::pat, intr: @ident_interner) -> ~str {
142 to_str(pat, print_irrefutable_pat, intr)
145 pub fn expr_to_str(e: @ast::expr, intr: @ident_interner) -> ~str {
146 to_str(e, print_expr, intr)
149 pub fn lifetime_to_str(e: &ast::Lifetime, intr: @ident_interner) -> ~str {
150 to_str(e, print_lifetime, intr)
153 pub fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str {
154 to_str(tt, print_tt, intr)
157 pub fn tts_to_str(tts: &[ast::token_tree], intr: @ident_interner) -> ~str {
158 to_str(tts, print_tts, intr)
161 pub fn stmt_to_str(s: ast::stmt, intr: @ident_interner) -> ~str {
162 to_str(s, print_stmt, intr)
165 pub fn item_to_str(i: @ast::item, intr: @ident_interner) -> ~str {
166 to_str(i, print_item, intr)
169 pub fn generics_to_str(generics: &ast::Generics,
170 intr: @ident_interner) -> ~str {
171 to_str(generics, print_generics, intr)
174 pub fn path_to_str(&&p: @ast::path, intr: @ident_interner) -> ~str {
175 to_str(p, |a,b| print_path(a, b, false), intr)
178 pub fn fun_to_str(decl: &ast::fn_decl, name: ast::ident,
179 generics: &ast::Generics, intr: @ident_interner) -> ~str {
180 do io::with_str_writer |wr| {
181 let s = rust_printer(wr, intr);
182 print_fn(s, decl, None, name, generics, None, ast::inherited);
183 end(s); // Close the head box
184 end(s); // Close the outer box
189 pub fn block_to_str(blk: &ast::blk, intr: @ident_interner) -> ~str {
190 do io::with_str_writer |wr| {
191 let s = rust_printer(wr, intr);
192 // containing cbox, will be closed by print-block at }
193 cbox(s, indent_unit);
194 // head-ibox, will be closed by print-block after {
201 pub fn meta_item_to_str(mi: @ast::meta_item, intr: @ident_interner) -> ~str {
202 to_str(mi, print_meta_item, intr)
205 pub fn attribute_to_str(attr: ast::attribute, intr: @ident_interner) -> ~str {
206 to_str(attr, print_attribute, intr)
209 pub fn variant_to_str(var: ast::variant, intr: @ident_interner) -> ~str {
210 to_str(var, print_variant, intr)
213 pub fn cbox(s: @ps, u: uint) {
214 s.boxes.push(pp::consistent);
218 pub fn box(s: @ps, u: uint, b: pp::breaks) {
223 pub fn nbsp(s: @ps) { word(s.s, ~" "); }
225 pub fn word_nbsp(s: @ps, w: ~str) { word(s.s, w); nbsp(s); }
227 pub fn word_space(s: @ps, w: ~str) { word(s.s, w); space(s.s); }
229 pub fn popen(s: @ps) { word(s.s, ~"("); }
231 pub fn pclose(s: @ps) { word(s.s, ~")"); }
233 pub fn head(s: @ps, w: ~str) {
234 // outer-box is consistent
235 cbox(s, indent_unit);
236 // head-box is inconsistent
237 ibox(s, str::len(w) + 1);
238 // keyword that starts the head
244 pub fn bopen(s: @ps) {
246 end(s); // close the head-box
249 pub fn bclose_(s: @ps, span: codemap::span, indented: uint) {
250 bclose_maybe_open(s, span, indented, true);
252 pub fn bclose_maybe_open (s: @ps, span: codemap::span, indented: uint,
254 maybe_print_comment(s, span.hi);
255 break_offset_if_not_bol(s, 1u, -(indented as int));
258 end(s); // close the outer-box
261 pub fn bclose(s: @ps, span: codemap::span) { bclose_(s, span, indent_unit); }
263 pub fn is_begin(s: @ps) -> bool {
264 match s.s.last_token() { pp::BEGIN(_) => true, _ => false }
267 pub fn is_end(s: @ps) -> bool {
268 match s.s.last_token() { pp::END => true, _ => false }
271 pub fn is_bol(s: @ps) -> bool {
272 return s.s.last_token().is_eof() || s.s.last_token().is_hardbreak_tok();
275 pub fn in_cbox(s: @ps) -> bool {
276 let len = s.boxes.len();
277 if len == 0u { return false; }
278 return s.boxes[len - 1u] == pp::consistent;
281 pub fn hardbreak_if_not_bol(s: @ps) { if !is_bol(s) { hardbreak(s.s); } }
282 pub fn space_if_not_bol(s: @ps) { if !is_bol(s) { space(s.s); } }
283 pub fn break_offset_if_not_bol(s: @ps, n: uint, off: int) {
285 break_offset(s.s, n, off);
287 if off != 0 && s.s.last_token().is_hardbreak_tok() {
288 // We do something pretty sketchy here: tuck the nonzero
289 // offset-adjustment we were going to deposit along with the
290 // break into the previous hardbreak.
291 s.s.replace_last_token(pp::hardbreak_tok_offset(off));
296 // Synthesizes a comment that was not textually present in the original source
298 pub fn synth_comment(s: @ps, text: ~str) {
306 pub fn commasep<IN>(s: @ps, b: breaks, elts: ~[IN], op: &fn(@ps, IN)) {
308 let mut first = true;
309 for elts.each |elt| {
310 if first { first = false; } else { word_space(s, ~","); }
317 pub fn commasep_cmnt<IN>(s: @ps, b: breaks, elts: ~[IN], op: &fn(@ps, IN),
318 get_span: &fn(IN) -> codemap::span) {
320 let len = vec::len::<IN>(elts);
322 for elts.each |elt| {
323 maybe_print_comment(s, get_span(*elt).hi);
328 maybe_print_trailing_comment(s, get_span(*elt),
329 Some(get_span(elts[i]).hi));
336 pub fn commasep_exprs(s: @ps, b: breaks, exprs: ~[@ast::expr]) {
337 fn expr_span(&&expr: @ast::expr) -> codemap::span { return expr.span; }
338 commasep_cmnt(s, b, exprs, print_expr, expr_span);
341 pub fn print_mod(s: @ps, _mod: ast::_mod, attrs: ~[ast::attribute]) {
342 print_inner_attributes(s, attrs);
343 for _mod.view_items.each |vitem| {
344 print_view_item(s, *vitem);
346 for _mod.items.each |item| { print_item(s, *item); }
349 pub fn print_foreign_mod(s: @ps, nmod: ast::foreign_mod,
350 attrs: ~[ast::attribute]) {
351 print_inner_attributes(s, attrs);
352 for nmod.view_items.each |vitem| {
353 print_view_item(s, *vitem);
355 for nmod.items.each |item| { print_foreign_item(s, *item); }
358 pub fn print_opt_lifetime(s: @ps, lifetime: Option<@ast::Lifetime>) {
359 for lifetime.each |l| {
360 print_lifetime(s, *l);
365 pub fn print_type(s: @ps, &&ty: @ast::Ty) {
366 print_type_ex(s, ty, false);
369 pub fn print_type_ex(s: @ps, &&ty: @ast::Ty, print_colons: bool) {
370 maybe_print_comment(s, ty.span.lo);
372 match /*bad*/ copy ty.node {
373 ast::ty_nil => word(s.s, ~"()"),
374 ast::ty_bot => word(s.s, ~"!"),
375 ast::ty_box(mt) => { word(s.s, ~"@"); print_mt(s, mt); }
376 ast::ty_uniq(mt) => { word(s.s, ~"~"); print_mt(s, mt); }
380 ast::m_mutbl => word_space(s, ~"mut"),
381 ast::m_const => word_space(s, ~"const"),
384 print_type(s, mt.ty);
387 ast::ty_ptr(mt) => { word(s.s, ~"*"); print_mt(s, mt); }
388 ast::ty_rptr(lifetime, mt) => {
390 print_opt_lifetime(s, lifetime);
393 ast::ty_tup(elts) => {
395 commasep(s, inconsistent, elts, print_type);
401 ast::ty_bare_fn(f) => {
402 print_ty_fn(s, Some(f.abi), None, None,
403 f.purity, ast::Many, &f.decl, None,
406 ast::ty_closure(f) => {
407 print_ty_fn(s, None, Some(f.sigil), f.region,
408 f.purity, f.onceness, &f.decl, None,
411 ast::ty_path(path, _) => print_path(s, path, print_colons),
412 ast::ty_fixed_length_vec(mt, v) => {
415 ast::m_mutbl => word_space(s, ~"mut"),
416 ast::m_const => word_space(s, ~"const"),
419 print_type(s, mt.ty);
421 word(s.s, fmt!("%u", v));
425 fail!(~"print_type doesn't know how to print a ty_mac");
428 fail!(~"print_type shouldn't see a ty_infer");
435 pub fn print_foreign_item(s: @ps, item: @ast::foreign_item) {
436 hardbreak_if_not_bol(s);
437 maybe_print_comment(s, item.span.lo);
438 print_outer_attributes(s, item.attrs);
439 match /*bad*/ copy item.node {
440 ast::foreign_item_fn(ref decl, purity, ref generics) => {
441 print_fn(s, decl, Some(purity), item.ident, generics, None,
443 end(s); // end head-ibox
445 end(s); // end the outer fn box
447 ast::foreign_item_const(t) => {
449 print_ident(s, item.ident);
453 end(s); // end the head-ibox
454 end(s); // end the outer cbox
459 pub fn print_item(s: @ps, &&item: @ast::item) {
460 hardbreak_if_not_bol(s);
461 maybe_print_comment(s, item.span.lo);
462 print_outer_attributes(s, item.attrs);
463 let ann_node = node_item(s, item);
464 (s.ann.pre)(ann_node);
465 match /*bad*/ copy item.node {
466 ast::item_const(ty, expr) => {
467 head(s, visibility_qualified(item.vis, ~"const"));
468 print_ident(s, item.ident);
472 end(s); // end the head-ibox
477 end(s); // end the outer cbox
480 ast::item_fn(ref decl, purity, ref typarams, ref body) => {
491 print_block_with_attrs(s, body, item.attrs);
493 ast::item_mod(_mod) => {
494 head(s, visibility_qualified(item.vis, ~"mod"));
495 print_ident(s, item.ident);
498 print_mod(s, _mod, item.attrs);
499 bclose(s, item.span);
501 ast::item_foreign_mod(nmod) => {
502 head(s, visibility_qualified(item.vis, ~"extern"));
503 print_string(s, *s.intr.get(nmod.abi));
507 word_nbsp(s, ~"mod");
508 print_ident(s, item.ident);
514 print_foreign_mod(s, nmod, item.attrs);
515 bclose(s, item.span);
517 ast::item_ty(ty, ref params) => {
518 ibox(s, indent_unit);
520 word_nbsp(s, visibility_qualified(item.vis, ~"type"));
521 print_ident(s, item.ident);
522 print_generics(s, params);
523 end(s); // end the inner ibox
529 end(s); // end the outer ibox
531 ast::item_enum(ref enum_definition, ref params) => {
541 ast::item_struct(struct_def, ref generics) => {
542 head(s, visibility_qualified(item.vis, ~"struct"));
543 print_struct(s, struct_def, generics, item.ident, item.span);
546 ast::item_impl(ref generics, opt_trait, ty, ref methods) => {
547 head(s, visibility_qualified(item.vis, ~"impl"));
548 if generics.is_parameterized() {
549 print_generics(s, generics);
555 print_path(s, t.path, false);
557 word_space(s, ~"for");
565 if methods.len() == 0 {
569 for methods.each |meth| {
570 print_method(s, *meth);
572 bclose(s, item.span);
575 ast::item_trait(ref generics, ref traits, ref methods) => {
576 head(s, visibility_qualified(item.vis, ~"trait"));
577 print_ident(s, item.ident);
578 print_generics(s, generics);
579 if traits.len() != 0u {
581 for traits.eachi |i, trait_| {
586 print_path(s, trait_.path, false);
591 for methods.each |meth| {
592 print_trait_method(s, meth);
594 bclose(s, item.span);
596 ast::item_mac(codemap::spanned { node: ast::mac_invoc_tt(pth, ref tts),
598 print_visibility(s, item.vis);
599 print_path(s, pth, false);
601 print_ident(s, item.ident);
602 cbox(s, indent_unit);
609 (s.ann.post)(ann_node);
612 pub fn print_enum_def(s: @ps, enum_definition: ast::enum_def,
613 generics: &ast::Generics, ident: ast::ident,
614 span: codemap::span, visibility: ast::visibility) {
615 head(s, visibility_qualified(visibility, ~"enum"));
616 print_ident(s, ident);
617 print_generics(s, generics);
619 print_variants(s, enum_definition.variants, span);
622 pub fn print_variants(s: @ps,
623 variants: ~[ast::variant],
624 span: codemap::span) {
626 for variants.each |v| {
628 maybe_print_comment(s, v.span.lo);
629 print_outer_attributes(s, v.node.attrs);
630 ibox(s, indent_unit);
631 print_variant(s, *v);
634 maybe_print_trailing_comment(s, v.span, None);
639 pub fn visibility_to_str(vis: ast::visibility) -> ~str {
641 ast::private => ~"priv",
642 ast::public => ~"pub",
643 ast::inherited => ~""
647 pub fn visibility_qualified(vis: ast::visibility, s: ~str) -> ~str {
649 ast::private | ast::public => visibility_to_str(vis) + " " + s,
650 ast::inherited => copy s
654 pub fn print_visibility(s: @ps, vis: ast::visibility) {
656 ast::private | ast::public =>
657 word_nbsp(s, visibility_to_str(vis)),
662 pub fn print_struct(s: @ps,
663 struct_def: @ast::struct_def,
664 generics: &ast::Generics,
666 span: codemap::span) {
667 print_ident(s, ident);
668 print_generics(s, generics);
669 if ast_util::struct_def_is_tuple_like(struct_def) {
670 if !struct_def.fields.is_empty() {
672 do commasep(s, inconsistent, struct_def.fields) |s, field| {
673 match field.node.kind {
674 ast::named_field(*) => fail!(~"unexpected named field"),
675 ast::unnamed_field => {
676 maybe_print_comment(s, field.span.lo);
677 print_type(s, field.node.ty);
685 end(s); // close the outer-box
689 hardbreak_if_not_bol(s);
690 for struct_def.dtor.each |dtor| {
691 hardbreak_if_not_bol(s);
692 maybe_print_comment(s, dtor.span.lo);
693 print_outer_attributes(s, dtor.node.attrs);
695 print_block(s, &dtor.node.body);
698 for struct_def.fields.each |field| {
699 match field.node.kind {
700 ast::unnamed_field => fail!(~"unexpected unnamed field"),
701 ast::named_field(ident, mutability, visibility) => {
702 hardbreak_if_not_bol(s);
703 maybe_print_comment(s, field.span.lo);
704 print_visibility(s, visibility);
705 if mutability == ast::struct_mutable {
706 word_nbsp(s, ~"mut");
708 print_ident(s, ident);
710 print_type(s, field.node.ty);
720 /// This doesn't deserve to be called "pretty" printing, but it should be
721 /// meaning-preserving. A quick hack that might help would be to look at the
722 /// spans embedded in the TTs to decide where to put spaces and newlines.
723 /// But it'd be better to parse these according to the grammar of the
724 /// appropriate macro, transcribe back into the grammar we just parsed from,
725 /// and then pretty-print the resulting AST nodes (so, e.g., we print
726 /// expression arguments as expressions). It can be done! I think.
727 pub fn print_tt(s: @ps, tt: ast::token_tree) {
729 ast::tt_delim(ref tts) => print_tts(s, *tts),
730 ast::tt_tok(_, ref tk) => {
731 word(s.s, parse::token::to_str(s.intr, tk));
733 ast::tt_seq(_, ref tts, ref sep, zerok) => {
735 for (*tts).each() |tt_elt| { print_tt(s, *tt_elt); }
738 Some(ref tk) => word(s.s, parse::token::to_str(s.intr, tk)),
741 word(s.s, if zerok { ~"*" } else { ~"+" });
743 ast::tt_nonterminal(_, name) => {
745 print_ident(s, name);
750 pub fn print_tts(s: @ps, &&tts: &[ast::token_tree]) {
752 for tts.eachi |i, tt| {
761 pub fn print_variant(s: @ps, v: ast::variant) {
762 print_visibility(s, v.node.vis);
763 match /*bad*/ copy v.node.kind {
764 ast::tuple_variant_kind(args) => {
765 print_ident(s, v.node.name);
766 if !args.is_empty() {
768 fn print_variant_arg(s: @ps, arg: ast::variant_arg) {
769 print_type(s, arg.ty);
771 commasep(s, consistent, args, print_variant_arg);
775 ast::struct_variant_kind(struct_def) => {
777 let generics = ast_util::empty_generics();
778 print_struct(s, struct_def, &generics, v.node.name, v.span);
780 ast::enum_variant_kind(ref enum_definition) => {
781 print_variants(s, (*enum_definition).variants, v.span);
784 match v.node.disr_expr {
794 pub fn print_ty_method(s: @ps, m: &ast::ty_method) {
795 hardbreak_if_not_bol(s);
796 maybe_print_comment(s, m.span.lo);
797 print_outer_attributes(s, m.attrs);
798 print_ty_fn(s, None, None, None, m.purity, ast::Many,
799 &m.decl, Some(m.ident), Some(&m.generics),
800 Some(/*bad*/ copy m.self_ty.node));
804 pub fn print_trait_method(s: @ps, m: &ast::trait_method) {
806 required(ref ty_m) => print_ty_method(s, ty_m),
807 provided(m) => print_method(s, m)
811 pub fn print_method(s: @ps, meth: @ast::method) {
812 hardbreak_if_not_bol(s);
813 maybe_print_comment(s, meth.span.lo);
814 print_outer_attributes(s, meth.attrs);
815 print_fn(s, &meth.decl, Some(meth.purity),
816 meth.ident, &meth.generics, Some(meth.self_ty.node),
819 print_block_with_attrs(s, &meth.body, meth.attrs);
822 pub fn print_outer_attributes(s: @ps, attrs: ~[ast::attribute]) {
824 for attrs.each |attr| {
825 match attr.node.style {
826 ast::attr_outer => { print_attribute(s, *attr); count += 1; }
827 _ => {/* fallthrough */ }
830 if count > 0 { hardbreak_if_not_bol(s); }
833 pub fn print_inner_attributes(s: @ps, attrs: ~[ast::attribute]) {
835 for attrs.each |attr| {
836 match attr.node.style {
838 print_attribute(s, *attr);
839 if !attr.node.is_sugared_doc {
844 _ => {/* fallthrough */ }
847 if count > 0 { hardbreak_if_not_bol(s); }
850 pub fn print_attribute(s: @ps, attr: ast::attribute) {
851 hardbreak_if_not_bol(s);
852 maybe_print_comment(s, attr.span.lo);
853 if attr.node.is_sugared_doc {
854 let meta = attr::attr_meta(attr);
855 let comment = attr::get_meta_item_value_str(meta).get();
859 print_meta_item(s, attr.node.value);
865 pub fn print_stmt(s: @ps, st: ast::stmt) {
866 maybe_print_comment(s, st.span.lo);
868 ast::stmt_decl(decl, _) => {
871 ast::stmt_expr(expr, _) => {
875 ast::stmt_semi(expr, _) => {
880 ast::stmt_mac(ref mac, semi) => {
882 print_mac(s, (*mac));
883 if semi { word(s.s, ~";"); }
886 if parse::classify::stmt_ends_with_semi(st) { word(s.s, ~";"); }
887 maybe_print_trailing_comment(s, st.span, None);
890 pub fn print_block(s: @ps, blk: &ast::blk) {
891 print_possibly_embedded_block(s, blk, block_normal, indent_unit);
894 pub fn print_block_unclosed(s: @ps, blk: &ast::blk) {
895 print_possibly_embedded_block_(s, blk, block_normal, indent_unit, ~[],
899 pub fn print_block_unclosed_indent(s: @ps, blk: &ast::blk, indented: uint) {
900 print_possibly_embedded_block_(s, blk, block_normal, indented, ~[],
904 pub fn print_block_with_attrs(s: @ps,
906 attrs: ~[ast::attribute]) {
907 print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
911 pub enum embed_type { block_block_fn, block_normal, }
913 pub fn print_possibly_embedded_block(s: @ps,
915 embedded: embed_type,
917 print_possibly_embedded_block_(
918 s, blk, embedded, indented, ~[], true);
921 pub fn print_possibly_embedded_block_(s: @ps,
923 embedded: embed_type,
925 attrs: ~[ast::attribute],
927 match blk.node.rules {
928 ast::unsafe_blk => word_space(s, ~"unsafe"),
929 ast::default_blk => ()
931 maybe_print_comment(s, blk.span.lo);
932 let ann_node = node_block(s, blk);
933 (s.ann.pre)(ann_node);
935 block_block_fn => end(s),
936 block_normal => bopen(s)
939 print_inner_attributes(s, attrs);
941 for blk.node.view_items.each |vi| { print_view_item(s, *vi); }
942 for blk.node.stmts.each |st| {
945 match blk.node.expr {
949 maybe_print_trailing_comment(s, expr.span, Some(blk.span.hi));
953 bclose_maybe_open(s, blk.span, indented, close_box);
954 (s.ann.post)(ann_node);
957 pub fn print_if(s: @ps, test: @ast::expr, blk: &ast::blk,
958 elseopt: Option<@ast::expr>, chk: bool) {
960 if chk { word_nbsp(s, ~"check"); }
964 fn do_else(s: @ps, els: Option<@ast::expr>) {
969 ast::expr_if(i, ref t, e) => {
970 cbox(s, indent_unit - 1u);
972 word(s.s, ~" else if ");
979 ast::expr_block(ref b) => {
980 cbox(s, indent_unit - 1u);
982 word(s.s, ~" else ");
985 // BLEAH, constraints would be great here
987 fail!(~"print_if saw if with weird alternative");
991 _ => {/* fall through */ }
997 pub fn print_mac(s: @ps, m: ast::mac) {
999 ast::mac_invoc_tt(pth, ref tts) => {
1000 print_path(s, pth, false);
1009 pub fn print_vstore(s: @ps, t: ast::vstore) {
1011 ast::vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
1012 ast::vstore_fixed(None) => word(s.s, ~"_"),
1013 ast::vstore_uniq => word(s.s, ~"~"),
1014 ast::vstore_box => word(s.s, ~"@"),
1015 ast::vstore_slice(r) => {
1017 print_opt_lifetime(s, r);
1022 pub fn print_expr_vstore(s: @ps, t: ast::expr_vstore) {
1024 ast::expr_vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
1025 ast::expr_vstore_fixed(None) => word(s.s, ~"_"),
1026 ast::expr_vstore_uniq => word(s.s, ~"~"),
1027 ast::expr_vstore_box => word(s.s, ~"@"),
1028 ast::expr_vstore_mut_box => {
1032 ast::expr_vstore_slice => word(s.s, ~"&"),
1033 ast::expr_vstore_mut_slice => {
1040 pub fn print_call_pre(s: @ps,
1041 sugar: ast::CallSugar,
1042 base_args: &mut ~[@ast::expr])
1043 -> Option<@ast::expr> {
1047 Some(base_args.pop())
1051 Some(base_args.pop())
1053 ast::NoSugar => None
1057 pub fn print_call_post(s: @ps,
1058 sugar: ast::CallSugar,
1059 blk: &Option<@ast::expr>,
1060 base_args: &mut ~[@ast::expr]) {
1061 if sugar == ast::NoSugar || !base_args.is_empty() {
1063 commasep_exprs(s, inconsistent, *base_args);
1066 if sugar != ast::NoSugar {
1068 match blk.get().node {
1069 // need to handle closures specifically
1070 ast::expr_do_body(e) | ast::expr_loop_body(e) => {
1071 end(s); // we close our head box; closure
1072 // will create it's own.
1074 end(s); // close outer box, as closures don't
1077 // not sure if this can happen.
1078 print_expr(s, blk.get());
1084 pub fn print_expr(s: @ps, &&expr: @ast::expr) {
1085 fn print_field(s: @ps, field: ast::field) {
1086 ibox(s, indent_unit);
1087 if field.node.mutbl == ast::m_mutbl { word_nbsp(s, ~"mut"); }
1088 print_ident(s, field.node.ident);
1089 word_space(s, ~":");
1090 print_expr(s, field.node.expr);
1093 fn get_span(field: ast::field) -> codemap::span { return field.span; }
1095 maybe_print_comment(s, expr.span.lo);
1096 ibox(s, indent_unit);
1097 let ann_node = node_expr(s, expr);
1098 (s.ann.pre)(ann_node);
1099 match /*bad*/ copy expr.node {
1100 ast::expr_vstore(e, v) => match v {
1101 ast::expr_vstore_fixed(_) => {
1104 print_expr_vstore(s, v);
1107 print_expr_vstore(s, v);
1111 ast::expr_vec(exprs, mutbl) => {
1112 ibox(s, indent_unit);
1114 if mutbl == ast::m_mutbl {
1116 if vec::len(exprs) > 0u { nbsp(s); }
1118 commasep_exprs(s, inconsistent, exprs);
1123 ast::expr_repeat(element, count, mutbl) => {
1124 ibox(s, indent_unit);
1126 if mutbl == ast::m_mutbl {
1130 print_expr(s, element);
1133 print_expr(s, count);
1138 ast::expr_struct(path, ref fields, wth) => {
1139 print_path(s, path, true);
1141 commasep_cmnt(s, consistent, (*fields), print_field, get_span);
1144 ibox(s, indent_unit);
1148 print_expr(s, expr);
1151 _ => (word(s.s, ~","))
1155 ast::expr_tup(exprs) => {
1157 commasep_exprs(s, inconsistent, exprs);
1158 if exprs.len() == 1 {
1163 ast::expr_call(func, args, sugar) => {
1164 let mut base_args = copy args;
1165 let blk = print_call_pre(s, sugar, &mut base_args);
1166 print_expr(s, func);
1167 print_call_post(s, sugar, &blk, &mut base_args);
1169 ast::expr_method_call(func, ident, tys, args, sugar) => {
1170 let mut base_args = copy args;
1171 let blk = print_call_pre(s, sugar, &mut base_args);
1172 print_expr(s, func);
1174 print_ident(s, ident);
1175 if vec::len(tys) > 0u {
1177 commasep(s, inconsistent, tys, print_type);
1180 print_call_post(s, sugar, &blk, &mut base_args);
1182 ast::expr_binary(op, lhs, rhs) => {
1185 word_space(s, ast_util::binop_to_str(op));
1188 ast::expr_unary(op, expr) => {
1189 word(s.s, ast_util::unop_to_str(op));
1190 print_expr(s, expr);
1192 ast::expr_addr_of(m, expr) => {
1194 print_mutability(s, m);
1195 // Avoid `& &e` => `&&e`.
1196 match (m, &expr.node) {
1197 (ast::m_imm, &ast::expr_addr_of(*)) => space(s.s),
1200 print_expr(s, expr);
1202 ast::expr_lit(lit) => print_literal(s, lit),
1203 ast::expr_cast(expr, ty) => {
1204 print_expr(s, expr);
1206 word_space(s, ~"as");
1207 print_type_ex(s, ty, true);
1209 ast::expr_if(test, ref blk, elseopt) => {
1210 print_if(s, test, blk, elseopt, false);
1212 ast::expr_while(test, ref blk) => {
1214 print_expr(s, test);
1216 print_block(s, blk);
1218 ast::expr_loop(ref blk, opt_ident) => {
1221 for opt_ident.each |ident| {
1222 print_ident(s, *ident);
1223 word_space(s, ~":");
1225 print_block(s, blk);
1227 ast::expr_match(expr, ref arms) => {
1228 cbox(s, match_indent_unit);
1230 word_nbsp(s, ~"match");
1231 print_expr(s, expr);
1234 let len = (*arms).len();
1235 for (*arms).eachi |i, arm| {
1237 cbox(s, match_indent_unit);
1239 let mut first = true;
1240 for arm.pats.each |p| {
1243 } else { space(s.s); word_space(s, ~"|"); }
1244 print_refutable_pat(s, *p);
1249 word_space(s, ~"if");
1255 word_space(s, ~"=>");
1257 // Extract the expression from the extra block the parser adds
1258 // in the case of foo => expr
1259 if arm.body.node.view_items.is_empty() &&
1260 arm.body.node.stmts.is_empty() &&
1261 arm.body.node.rules == ast::default_blk &&
1262 arm.body.node.expr.is_some()
1264 match arm.body.node.expr {
1267 ast::expr_block(ref blk) => {
1268 // the block will close the pattern's ibox
1269 print_block_unclosed_indent(
1270 s, blk, match_indent_unit);
1273 end(s); // close the ibox for the pattern
1274 print_expr(s, expr);
1277 if !expr_is_simple_block(expr)
1281 end(s); // close enclosing cbox
1286 // the block will close the pattern's ibox
1287 print_block_unclosed_indent(s, &arm.body, match_indent_unit);
1290 bclose_(s, expr.span, match_indent_unit);
1292 ast::expr_fn_block(ref decl, ref body) => {
1293 // in do/for blocks we don't want to show an empty
1294 // argument list, but at this point we don't know which
1297 // if !decl.inputs.is_empty() {
1298 print_fn_block_args(s, decl);
1301 fail_unless!(body.node.stmts.is_empty());
1302 fail_unless!(body.node.expr.is_some());
1303 // we extract the block, so as not to create another set of boxes
1304 match body.node.expr.get().node {
1305 ast::expr_block(ref blk) => {
1306 print_block_unclosed(s, blk);
1309 // this is a bare expression
1310 print_expr(s, body.node.expr.get());
1311 end(s); // need to close a box
1314 // a box will be closed by print_expr, but we didn't want an overall
1315 // wrapper so we closed the corresponding opening. so create an
1316 // empty box to satisfy the close.
1319 ast::expr_loop_body(body) => {
1320 print_expr(s, body);
1322 ast::expr_do_body(body) => {
1323 print_expr(s, body);
1325 ast::expr_block(ref blk) => {
1326 // containing cbox, will be closed by print-block at }
1327 cbox(s, indent_unit);
1328 // head-box, will be closed by print-block after {
1330 print_block(s, blk);
1332 ast::expr_copy(e) => { word_space(s, ~"copy"); print_expr(s, e); }
1333 ast::expr_assign(lhs, rhs) => {
1336 word_space(s, ~"=");
1339 ast::expr_swap(lhs, rhs) => {
1342 word_space(s, ~"<->");
1345 ast::expr_assign_op(op, lhs, rhs) => {
1348 word(s.s, ast_util::binop_to_str(op));
1349 word_space(s, ~"=");
1352 ast::expr_field(expr, id, tys) => {
1353 print_expr(s, expr);
1356 if vec::len(tys) > 0u {
1358 commasep(s, inconsistent, tys, print_type);
1362 ast::expr_index(expr, index) => {
1363 print_expr(s, expr);
1365 print_expr(s, index);
1368 ast::expr_path(path) => print_path(s, path, true),
1369 ast::expr_break(opt_ident) => {
1370 word(s.s, ~"break");
1372 for opt_ident.each |ident| { print_ident(s, *ident); space(s.s) }
1374 ast::expr_again(opt_ident) => {
1377 for opt_ident.each |ident| { print_ident(s, *ident); space(s.s) }
1379 ast::expr_ret(result) => {
1380 word(s.s, ~"return");
1382 Some(expr) => { word(s.s, ~" "); print_expr(s, expr); }
1386 ast::expr_log(lvl, lexp, expr) => {
1388 ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); }
1389 ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); }
1391 word_nbsp(s, ~"log");
1393 print_expr(s, lexp);
1395 space_if_not_bol(s);
1396 print_expr(s, expr);
1401 ast::expr_inline_asm(a, c) => {
1402 word(s.s, ~"__asm__");
1404 print_string(s, *a);
1405 word_space(s, ~",");
1406 print_string(s, *c);
1409 ast::expr_mac(ref m) => print_mac(s, (*m)),
1410 ast::expr_paren(e) => {
1416 (s.ann.post)(ann_node);
1420 pub fn print_local_decl(s: @ps, loc: @ast::local) {
1421 print_irrefutable_pat(s, loc.node.pat);
1422 match loc.node.ty.node {
1423 ast::ty_infer => (),
1424 _ => { word_space(s, ~":"); print_type(s, loc.node.ty); }
1428 pub fn print_decl(s: @ps, decl: @ast::decl) {
1429 maybe_print_comment(s, decl.span.lo);
1430 match /*bad*/ copy decl.node {
1431 ast::decl_local(locs) => {
1432 space_if_not_bol(s);
1433 ibox(s, indent_unit);
1434 word_nbsp(s, ~"let");
1436 // if any are mut, all are mut
1437 if vec::any(locs, |l| l.node.is_mutbl) {
1438 fail_unless!(vec::all(locs, |l| l.node.is_mutbl));
1439 word_nbsp(s, ~"mut");
1442 fn print_local(s: @ps, &&loc: @ast::local) {
1443 ibox(s, indent_unit);
1444 print_local_decl(s, loc);
1446 match loc.node.init {
1449 word_space(s, ~"=");
1450 print_expr(s, init);
1455 commasep(s, consistent, locs, print_local);
1458 ast::decl_item(item) => print_item(s, item)
1462 pub fn print_ident(s: @ps, ident: ast::ident) {
1463 word(s.s, *s.intr.get(ident));
1466 pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
1467 print_local_decl(s, loc);
1469 word_space(s, ~"in");
1470 print_expr(s, coll);
1473 pub fn print_path(s: @ps, &&path: @ast::path, colons_before_params: bool) {
1474 maybe_print_comment(s, path.span.lo);
1475 if path.global { word(s.s, ~"::"); }
1476 let mut first = true;
1477 for path.idents.each |id| {
1478 if first { first = false; } else { word(s.s, ~"::"); }
1479 print_ident(s, *id);
1481 if path.rp.is_some() || !path.types.is_empty() {
1482 if colons_before_params { word(s.s, ~"::"); }
1484 if path.rp.is_some() || !path.types.is_empty() {
1487 for path.rp.each |r| {
1488 print_lifetime(s, *r);
1489 if !path.types.is_empty() {
1490 word_space(s, ~",");
1494 commasep(s, inconsistent, path.types, print_type);
1501 pub fn print_irrefutable_pat(s: @ps, &&pat: @ast::pat) {
1502 print_pat(s, pat, false)
1505 pub fn print_refutable_pat(s: @ps, &&pat: @ast::pat) {
1506 print_pat(s, pat, true)
1509 pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) {
1510 maybe_print_comment(s, pat.span.lo);
1511 let ann_node = node_pat(s, pat);
1512 (s.ann.pre)(ann_node);
1513 /* Pat isn't normalized, but the beauty of it
1514 is that it doesn't matter */
1515 match /*bad*/ copy pat.node {
1516 ast::pat_wild => word(s.s, ~"_"),
1517 ast::pat_ident(binding_mode, path, sub) => {
1519 match binding_mode {
1520 ast::bind_by_ref(mutbl) => {
1521 word_nbsp(s, ~"ref");
1522 print_mutability(s, mutbl);
1524 ast::bind_by_copy => {
1525 word_nbsp(s, ~"copy");
1527 ast::bind_infer => {}
1530 print_path(s, path, true);
1534 print_pat(s, p, refutable);
1539 ast::pat_enum(path, args_) => {
1540 print_path(s, path, true);
1542 None => word(s.s, ~"(*)"),
1544 if !args.is_empty() {
1546 commasep(s, inconsistent, args,
1547 |s, p| print_pat(s, p, refutable));
1553 ast::pat_struct(path, fields, etc) => {
1554 print_path(s, path, true);
1556 fn print_field(s: @ps, f: ast::field_pat, refutable: bool) {
1557 cbox(s, indent_unit);
1558 print_ident(s, f.ident);
1559 word_space(s, ~":");
1560 print_pat(s, f.pat, refutable);
1563 fn get_span(f: ast::field_pat) -> codemap::span { return f.pat.span; }
1564 commasep_cmnt(s, consistent, fields,
1565 |s, f| print_field(s,f,refutable),
1568 if vec::len(fields) != 0u { word_space(s, ~","); }
1573 ast::pat_tup(elts) => {
1575 commasep(s, inconsistent, elts, |s, p| print_pat(s, p, refutable));
1576 if elts.len() == 1 {
1581 ast::pat_box(inner) => {
1583 print_pat(s, inner, refutable);
1585 ast::pat_uniq(inner) => {
1587 print_pat(s, inner, refutable);
1589 ast::pat_region(inner) => {
1591 print_pat(s, inner, refutable);
1593 ast::pat_lit(e) => print_expr(s, e),
1594 ast::pat_range(begin, end) => {
1595 print_expr(s, begin);
1600 ast::pat_vec(before, slice, after) => {
1602 do commasep(s, inconsistent, before) |s, p| {
1603 print_pat(s, p, refutable);
1605 for slice.each |&p| {
1606 if !before.is_empty() { word_space(s, ~","); }
1608 print_pat(s, p, refutable);
1609 if !after.is_empty() { word_space(s, ~","); }
1611 do commasep(s, inconsistent, after) |s, p| {
1612 print_pat(s, p, refutable);
1617 (s.ann.post)(ann_node);
1620 // Returns whether it printed anything
1621 pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool {
1623 ast::sty_static | ast::sty_by_ref => { return false; }
1624 ast::sty_value => { word(s.s, ~"self"); }
1625 ast::sty_region(m) => {
1626 word(s.s, ~"&"); print_mutability(s, m); word(s.s, ~"self");
1628 ast::sty_box(m) => {
1629 word(s.s, ~"@"); print_mutability(s, m); word(s.s, ~"self");
1631 ast::sty_uniq(m) => {
1632 word(s.s, ~"~"); print_mutability(s, m); word(s.s, ~"self");
1638 pub fn print_fn(s: @ps,
1639 decl: &ast::fn_decl,
1640 purity: Option<ast::purity>,
1642 generics: &ast::Generics,
1643 opt_self_ty: Option<ast::self_ty_>,
1644 vis: ast::visibility) {
1646 print_fn_header_info(s, opt_self_ty, purity, ast::Many, None, vis);
1648 print_ident(s, name);
1649 print_generics(s, generics);
1650 print_fn_args_and_ret(s, decl, opt_self_ty);
1653 pub fn print_fn_args(s: @ps, decl: &ast::fn_decl,
1654 opt_self_ty: Option<ast::self_ty_>) {
1655 // It is unfortunate to duplicate the commasep logic, but we we want the
1656 // self type and the args all in the same box.
1657 box(s, 0u, inconsistent);
1658 let mut first = true;
1659 for opt_self_ty.each |self_ty| {
1660 first = !print_self_ty(s, *self_ty);
1663 for decl.inputs.each |arg| {
1664 if first { first = false; } else { word_space(s, ~","); }
1671 pub fn print_fn_args_and_ret(s: @ps, decl: &ast::fn_decl,
1672 opt_self_ty: Option<ast::self_ty_>) {
1674 print_fn_args(s, decl, opt_self_ty);
1677 maybe_print_comment(s, decl.output.span.lo);
1678 match decl.output.node {
1681 space_if_not_bol(s);
1682 word_space(s, ~"->");
1683 print_type(s, decl.output);
1688 pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
1690 print_fn_args(s, decl, None);
1693 match decl.output.node {
1696 space_if_not_bol(s);
1697 word_space(s, ~"->");
1698 print_type(s, decl.output);
1702 maybe_print_comment(s, decl.output.span.lo);
1705 pub fn mode_to_str(m: ast::mode) -> ~str {
1707 ast::expl(ast::by_ref) => ~"&&",
1708 ast::expl(ast::by_copy) => ~"+",
1709 ast::expl(ast::by_val) => ~"++",
1710 ast::infer(_) => ~""
1714 pub fn print_arg_mode(s: @ps, m: ast::mode) {
1715 let ms = mode_to_str(m);
1716 if ms != ~"" { word(s.s, ms); }
1719 pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) {
1720 if !bounds.is_empty() {
1722 let mut first = true;
1723 for bounds.each |bound| {
1728 word_space(s, ~"+");
1732 TraitTyParamBound(ty) => print_type(s, ty),
1733 RegionTyParamBound => word(s.s, ~"&static"),
1739 pub fn print_lifetime(s: @ps, &&lifetime: &ast::Lifetime) {
1741 print_ident(s, lifetime.ident);
1744 pub fn print_generics(s: @ps, &&generics: &ast::Generics) {
1745 let total = generics.lifetimes.len() + generics.ty_params.len();
1748 fn print_item(s: @ps, generics: &ast::Generics, idx: uint) {
1749 if idx < generics.lifetimes.len() {
1750 let lifetime = generics.lifetimes.get(idx);
1751 print_lifetime(s, lifetime);
1753 let idx = idx - generics.lifetimes.len();
1754 let param = generics.ty_params.get(idx);
1755 print_ident(s, param.ident);
1756 print_bounds(s, param.bounds);
1761 for uint::range(0, total) |i| {
1765 commasep(s, inconsistent, ints,
1766 |s, i| print_item(s, generics, i));
1771 pub fn print_meta_item(s: @ps, &&item: @ast::meta_item) {
1772 ibox(s, indent_unit);
1774 ast::meta_word(name) => word(s.s, *name),
1775 ast::meta_name_value(name, value) => {
1776 word_space(s, *name);
1777 word_space(s, ~"=");
1778 print_literal(s, @value);
1780 ast::meta_list(name, ref items) => {
1786 /* FIXME (#2543) */ copy *items,
1795 pub fn print_view_path(s: @ps, &&vp: @ast::view_path) {
1797 ast::view_path_simple(ident, path, namespace, _) => {
1798 if namespace == ast::module_ns {
1799 word_space(s, ~"mod");
1801 if path.idents[vec::len(path.idents)-1u] != ident {
1802 print_ident(s, ident);
1804 word_space(s, ~"=");
1806 print_path(s, path, false);
1809 ast::view_path_glob(path, _) => {
1810 print_path(s, path, false);
1814 ast::view_path_list(path, ref idents, _) => {
1815 print_path(s, path, false);
1817 do commasep(s, inconsistent, (*idents)) |s, w| {
1818 print_ident(s, w.node.name);
1825 pub fn print_view_paths(s: @ps, vps: ~[@ast::view_path]) {
1826 commasep(s, inconsistent, vps, print_view_path);
1829 pub fn print_view_item(s: @ps, item: @ast::view_item) {
1830 hardbreak_if_not_bol(s);
1831 maybe_print_comment(s, item.span.lo);
1832 print_outer_attributes(s, item.attrs);
1833 print_visibility(s, item.vis);
1834 match /*bad*/ copy item.node {
1835 ast::view_item_extern_mod(id, mta, _) => {
1836 head(s, ~"extern mod");
1838 if !mta.is_empty() {
1840 commasep(s, consistent, mta, print_meta_item);
1845 ast::view_item_use(vps) => {
1847 print_view_paths(s, vps);
1851 end(s); // end inner head-block
1852 end(s); // end outer head-block
1855 pub fn print_mutability(s: @ps, mutbl: ast::mutability) {
1857 ast::m_mutbl => word_nbsp(s, ~"mut"),
1858 ast::m_const => word_nbsp(s, ~"const"),
1859 ast::m_imm => {/* nothing */ }
1863 pub fn print_mt(s: @ps, mt: ast::mt) {
1864 print_mutability(s, mt.mutbl);
1865 print_type(s, mt.ty);
1868 pub fn print_arg(s: @ps, input: ast::arg) {
1869 ibox(s, indent_unit);
1870 print_arg_mode(s, input.mode);
1872 word_space(s, ~"mut");
1874 match input.ty.node {
1875 ast::ty_infer => print_irrefutable_pat(s, input.pat),
1877 match input.pat.node {
1878 ast::pat_ident(_, path, _) if
1879 path.idents.len() == 1 &&
1880 path.idents[0] == parse::token::special_idents::invalid => {
1884 print_irrefutable_pat(s, input.pat);
1889 print_type(s, input.ty);
1895 pub fn print_ty_fn(s: @ps,
1896 opt_abi: Option<ast::Abi>,
1897 opt_sigil: Option<ast::Sigil>,
1898 opt_region: Option<@ast::Lifetime>,
1899 purity: ast::purity,
1900 onceness: ast::Onceness,
1901 decl: &ast::fn_decl, id: Option<ast::ident>,
1902 generics: Option<&ast::Generics>,
1903 opt_self_ty: Option<ast::self_ty_>) {
1904 ibox(s, indent_unit);
1906 // Duplicates the logic in `print_fn_header_info()`. This is because that
1907 // function prints the sigil in the wrong place. That should be fixed.
1908 print_self_ty_if_static(s, opt_self_ty);
1909 print_opt_abi(s, opt_abi);
1910 print_opt_sigil(s, opt_sigil);
1911 print_opt_lifetime(s, opt_region);
1912 print_purity(s, purity);
1913 print_onceness(s, onceness);
1915 match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
1916 match /*bad*/ copy generics { Some(g) => print_generics(s, g), _ => () }
1920 // It is unfortunate to duplicate the commasep logic, but we we want the
1921 // self type and the args all in the same box.
1922 box(s, 0u, inconsistent);
1923 let mut first = true;
1924 for opt_self_ty.each |self_ty| {
1925 first = !print_self_ty(s, *self_ty);
1927 for decl.inputs.each |arg| {
1928 if first { first = false; } else { word_space(s, ~","); }
1934 maybe_print_comment(s, decl.output.span.lo);
1936 match decl.output.node {
1939 space_if_not_bol(s);
1940 ibox(s, indent_unit);
1941 word_space(s, ~"->");
1942 if decl.cf == ast::noreturn { word_nbsp(s, ~"!"); }
1943 else { print_type(s, decl.output); }
1951 pub fn maybe_print_trailing_comment(s: @ps, span: codemap::span,
1952 next_pos: Option<BytePos>) {
1954 match s.cm { Some(ccm) => cm = ccm, _ => return }
1955 match next_comment(s) {
1957 if (*cmnt).style != comments::trailing { return; }
1958 let span_line = cm.lookup_char_pos(span.hi);
1959 let comment_line = cm.lookup_char_pos((*cmnt).pos);
1960 let mut next = (*cmnt).pos + BytePos(1u);
1961 match next_pos { None => (), Some(p) => next = p }
1962 if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
1963 span_line.line == comment_line.line {
1964 print_comment(s, (*cmnt));
1965 s.cur_cmnt_and_lit.cur_cmnt += 1u;
1972 pub fn print_remaining_comments(s: @ps) {
1973 // If there aren't any remaining comments, then we need to manually
1974 // make sure there is a line break at the end.
1975 if next_comment(s).is_none() { hardbreak(s.s); }
1977 match next_comment(s) {
1979 print_comment(s, (*cmnt));
1980 s.cur_cmnt_and_lit.cur_cmnt += 1u;
1987 pub fn print_literal(s: @ps, &&lit: @ast::lit) {
1988 maybe_print_comment(s, lit.span.lo);
1989 match next_lit(s, lit.span.lo) {
1991 word(s.s, (*ltrl).lit);
1997 ast::lit_str(st) => print_string(s, *st),
1998 ast::lit_int(ch, ast::ty_char) => {
1999 word(s.s, ~"'" + char::escape_default(ch as char) + ~"'");
2001 ast::lit_int(i, t) => {
2004 ~"-" + u64::to_str_radix(-i as u64, 10u)
2005 + ast_util::int_ty_to_str(t));
2008 u64::to_str_radix(i as u64, 10u)
2009 + ast_util::int_ty_to_str(t));
2012 ast::lit_uint(u, t) => {
2014 u64::to_str_radix(u, 10u)
2015 + ast_util::uint_ty_to_str(t));
2017 ast::lit_int_unsuffixed(i) => {
2019 word(s.s, ~"-" + u64::to_str_radix(-i as u64, 10u));
2021 word(s.s, u64::to_str_radix(i as u64, 10u));
2024 ast::lit_float(f, t) => {
2025 word(s.s, *f + ast_util::float_ty_to_str(t));
2027 ast::lit_float_unsuffixed(f) => word(s.s, *f),
2028 ast::lit_nil => word(s.s, ~"()"),
2029 ast::lit_bool(val) => {
2030 if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); }
2035 pub fn lit_to_str(l: @ast::lit) -> ~str {
2036 return to_str(l, print_literal, parse::token::mk_fake_ident_interner());
2039 pub fn next_lit(s: @ps, pos: BytePos) -> Option<comments::lit> {
2042 while s.cur_cmnt_and_lit.cur_lit < vec::len((*lits)) {
2043 let ltrl = /*bad*/ copy (*lits)[s.cur_cmnt_and_lit.cur_lit];
2044 if ltrl.pos > pos { return None; }
2045 s.cur_cmnt_and_lit.cur_lit += 1u;
2046 if ltrl.pos == pos { return Some(ltrl); }
2054 pub fn maybe_print_comment(s: @ps, pos: BytePos) {
2056 match next_comment(s) {
2058 if (*cmnt).pos < pos {
2059 print_comment(s, (*cmnt));
2060 s.cur_cmnt_and_lit.cur_cmnt += 1u;
2068 pub fn print_comment(s: @ps, cmnt: comments::cmnt) {
2070 comments::mixed => {
2071 fail_unless!((vec::len(cmnt.lines) == 1u));
2073 word(s.s, cmnt.lines[0]);
2076 comments::isolated => {
2077 pprust::hardbreak_if_not_bol(s);
2078 for cmnt.lines.each |line| {
2079 // Don't print empty lines because they will end up as trailing
2081 if !line.is_empty() { word(s.s, *line); }
2085 comments::trailing => {
2087 if vec::len(cmnt.lines) == 1u {
2088 word(s.s, cmnt.lines[0]);
2092 for cmnt.lines.each |line| {
2093 if !line.is_empty() { word(s.s, *line); }
2099 comments::blank_line => {
2100 // We need to do at least one, possibly two hardbreaks.
2102 match s.s.last_token() {
2103 pp::STRING(s, _) => *s == ~";",
2106 if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); }
2112 pub fn print_string(s: @ps, st: ~str) {
2114 word(s.s, str::escape_default(st));
2118 pub fn to_str<T>(t: T, f: @fn(@ps, T), intr: @ident_interner) -> ~str {
2119 do io::with_str_writer |wr| {
2120 let s = rust_printer(wr, intr);
2126 pub fn next_comment(s: @ps) -> Option<comments::cmnt> {
2128 Some(ref cmnts) => {
2129 if s.cur_cmnt_and_lit.cur_cmnt < vec::len((*cmnts)) {
2130 return Some(copy cmnts[s.cur_cmnt_and_lit.cur_cmnt]);
2131 } else { return None::<comments::cmnt>; }
2133 _ => return None::<comments::cmnt>
2137 pub fn print_self_ty_if_static(s: @ps,
2138 opt_self_ty: Option<ast::self_ty_>) {
2140 Some(ast::sty_static) => { word(s.s, ~"static "); }
2145 pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
2147 Some(ast::impure_fn) => { }
2149 word_nbsp(s, purity_to_str(purity));
2155 pub fn print_opt_abi(s: @ps, opt_abi: Option<ast::Abi>) {
2157 Some(ast::RustAbi) => { word_nbsp(s, ~"extern"); }
2162 pub fn print_opt_sigil(s: @ps, opt_sigil: Option<ast::Sigil>) {
2164 Some(ast::BorrowedSigil) => { word(s.s, ~"&"); }
2165 Some(ast::OwnedSigil) => { word(s.s, ~"~"); }
2166 Some(ast::ManagedSigil) => { word(s.s, ~"@"); }
2171 pub fn print_fn_header_info(s: @ps,
2172 opt_sty: Option<ast::self_ty_>,
2173 opt_purity: Option<ast::purity>,
2174 onceness: ast::Onceness,
2175 opt_sigil: Option<ast::Sigil>,
2176 vis: ast::visibility) {
2177 print_self_ty_if_static(s, opt_sty);
2178 word(s.s, visibility_qualified(vis, ~""));
2179 print_opt_purity(s, opt_purity);
2180 print_onceness(s, onceness);
2182 print_opt_sigil(s, opt_sigil);
2185 pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> ~str {
2188 Some(p) => fmt!("fn%s", p.to_str())
2192 pub pure fn purity_to_str(p: ast::purity) -> ~str {
2194 ast::impure_fn => ~"impure",
2195 ast::unsafe_fn => ~"unsafe",
2196 ast::pure_fn => ~"pure",
2197 ast::extern_fn => ~"extern"
2201 pub pure fn onceness_to_str(o: ast::Onceness) -> ~str {
2203 ast::Once => ~"once",
2204 ast::Many => ~"many"
2208 pub fn print_purity(s: @ps, p: ast::purity) {
2210 ast::impure_fn => (),
2211 _ => word_nbsp(s, purity_to_str(p))
2215 pub fn print_onceness(s: @ps, o: ast::Onceness) {
2217 ast::Once => { word_nbsp(s, ~"once"); }
2230 use core::option::None;
2232 use util::testing::check_equal;
2234 fn string_check<T:Eq> (given : &T, expected: &T) {
2235 if !(given == expected) {
2236 fail!(fmt!("given %?, expected %?",given,expected));
2241 fn test_fun_to_str() {
2242 let mock_interner = parse::token::mk_fake_ident_interner();
2243 let abba_ident = mock_interner.intern(@~"abba");
2245 let decl = ast::fn_decl {
2247 output: @ast::Ty {id: 0,
2249 span: codemap::dummy_sp()},
2252 let generics = ast_util::empty_generics();
2253 check_equal (&fun_to_str(&decl, abba_ident, &generics, mock_interner),
2258 fn test_variant_to_str() {
2259 let mock_interner = parse::token::mk_fake_ident_interner();
2260 let ident = mock_interner.intern(@~"principal_skinner");
2262 let var = codemap::respan(codemap::dummy_sp(), ast::variant_ {
2265 // making this up as I go.... ?
2266 kind: ast::tuple_variant_kind(~[]),
2272 let varstr = variant_to_str(var,mock_interner);
2273 check_equal(&varstr,&~"pub principal_skinner");
2281 // indent-tabs-mode: nil
2282 // c-basic-offset: 4
2283 // buffer-file-coding-system: utf-8-unix