]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/print/pprust.rs
auto merge of #15693 : steveklabnik/rust/guide_fix_cargo, r=cmr
[rust.git] / src / libsyntax / print / pprust.rs
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.
4 //
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.
10
11 use abi;
12 use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound};
13 use ast::{TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
14 use ast;
15 use ast_util;
16 use owned_slice::OwnedSlice;
17 use attr::{AttrMetaMethods, AttributeMethods};
18 use codemap::{CodeMap, BytePos};
19 use codemap;
20 use diagnostic;
21 use parse::classify::expr_is_simple_block;
22 use parse::token;
23 use parse::lexer::comments;
24 use parse;
25 use print::pp::{break_offset, word, space, zerobreak, hardbreak};
26 use print::pp::{Breaks, Consistent, Inconsistent, eof};
27 use print::pp;
28
29 use std::gc::Gc;
30 use std::io::{IoResult, MemWriter};
31 use std::io;
32 use std::mem;
33
34 pub enum AnnNode<'a> {
35     NodeBlock(&'a ast::Block),
36     NodeItem(&'a ast::Item),
37     NodeExpr(&'a ast::Expr),
38     NodePat(&'a ast::Pat),
39 }
40
41 pub trait PpAnn {
42     fn pre(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) }
43     fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) }
44 }
45
46 pub struct NoAnn;
47
48 impl PpAnn for NoAnn {}
49
50 pub struct CurrentCommentAndLiteral {
51     cur_cmnt: uint,
52     cur_lit: uint,
53 }
54
55 pub struct State<'a> {
56     pub s: pp::Printer,
57     cm: Option<&'a CodeMap>,
58     comments: Option<Vec<comments::Comment> >,
59     literals: Option<Vec<comments::Literal> >,
60     cur_cmnt_and_lit: CurrentCommentAndLiteral,
61     boxes: Vec<pp::Breaks>,
62     ann: &'a PpAnn
63 }
64
65 pub fn rust_printer(writer: Box<io::Writer>) -> State<'static> {
66     static NO_ANN: NoAnn = NoAnn;
67     rust_printer_annotated(writer, &NO_ANN)
68 }
69
70 pub fn rust_printer_annotated<'a>(writer: Box<io::Writer>,
71                                   ann: &'a PpAnn) -> State<'a> {
72     State {
73         s: pp::mk_printer(writer, default_columns),
74         cm: None,
75         comments: None,
76         literals: None,
77         cur_cmnt_and_lit: CurrentCommentAndLiteral {
78             cur_cmnt: 0,
79             cur_lit: 0
80         },
81         boxes: Vec::new(),
82         ann: ann
83     }
84 }
85
86 pub static indent_unit: uint = 4u;
87
88 pub static default_columns: uint = 78u;
89
90 /// Requires you to pass an input filename and reader so that
91 /// it can scan the input text for comments and literals to
92 /// copy forward.
93 pub fn print_crate<'a>(cm: &'a CodeMap,
94                        span_diagnostic: &diagnostic::SpanHandler,
95                        krate: &ast::Crate,
96                        filename: String,
97                        input: &mut io::Reader,
98                        out: Box<io::Writer>,
99                        ann: &'a PpAnn,
100                        is_expanded: bool) -> IoResult<()> {
101     let (cmnts, lits) = comments::gather_comments_and_literals(
102         span_diagnostic,
103         filename,
104         input
105     );
106     let mut s = State {
107         s: pp::mk_printer(out, default_columns),
108         cm: Some(cm),
109         comments: Some(cmnts),
110         // If the code is post expansion, don't use the table of
111         // literals, since it doesn't correspond with the literals
112         // in the AST anymore.
113         literals: if is_expanded {
114             None
115         } else {
116             Some(lits)
117         },
118         cur_cmnt_and_lit: CurrentCommentAndLiteral {
119             cur_cmnt: 0,
120             cur_lit: 0
121         },
122         boxes: Vec::new(),
123         ann: ann
124     };
125     try!(s.print_mod(&krate.module, krate.attrs.as_slice()));
126     try!(s.print_remaining_comments());
127     eof(&mut s.s)
128 }
129
130 pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
131     let mut s = rust_printer(box MemWriter::new());
132     f(&mut s).unwrap();
133     eof(&mut s.s).unwrap();
134     unsafe {
135         // FIXME(pcwalton): A nasty function to extract the string from an `io::Writer`
136         // that we "know" to be a `MemWriter` that works around the lack of checked
137         // downcasts.
138         let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out);
139         let result =
140             String::from_utf8(Vec::from_slice(wr.get_ref())).unwrap();
141         mem::forget(wr);
142         result.to_string()
143     }
144 }
145
146 pub fn ty_to_string(ty: &ast::Ty) -> String {
147     to_string(|s| s.print_type(ty))
148 }
149
150 pub fn pat_to_string(pat: &ast::Pat) -> String {
151     to_string(|s| s.print_pat(pat))
152 }
153
154 pub fn expr_to_string(e: &ast::Expr) -> String {
155     to_string(|s| s.print_expr(e))
156 }
157
158 pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
159     to_string(|s| s.print_lifetime(e))
160 }
161
162 pub fn tt_to_string(tt: &ast::TokenTree) -> String {
163     to_string(|s| s.print_tt(tt))
164 }
165
166 pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
167     to_string(|s| s.print_tts(tts))
168 }
169
170 pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
171     to_string(|s| s.print_stmt(stmt))
172 }
173
174 pub fn item_to_string(i: &ast::Item) -> String {
175     to_string(|s| s.print_item(i))
176 }
177
178 pub fn generics_to_string(generics: &ast::Generics) -> String {
179     to_string(|s| s.print_generics(generics))
180 }
181
182 pub fn ty_method_to_string(p: &ast::TypeMethod) -> String {
183     to_string(|s| s.print_ty_method(p))
184 }
185
186 pub fn method_to_string(p: &ast::Method) -> String {
187     to_string(|s| s.print_method(p))
188 }
189
190 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
191     to_string(|s| s.print_fn_block_args(p))
192 }
193
194 pub fn path_to_string(p: &ast::Path) -> String {
195     to_string(|s| s.print_path(p, false))
196 }
197
198 pub fn ident_to_string(id: &ast::Ident) -> String {
199     to_string(|s| s.print_ident(*id))
200 }
201
202 pub fn fun_to_string(decl: &ast::FnDecl, fn_style: ast::FnStyle, name: ast::Ident,
203                   opt_explicit_self: Option<ast::ExplicitSelf_>,
204                   generics: &ast::Generics) -> String {
205     to_string(|s| {
206         try!(s.print_fn(decl, Some(fn_style), abi::Rust,
207                         name, generics, opt_explicit_self, ast::Inherited));
208         try!(s.end()); // Close the head box
209         s.end() // Close the outer box
210     })
211 }
212
213 pub fn block_to_string(blk: &ast::Block) -> String {
214     to_string(|s| {
215         // containing cbox, will be closed by print-block at }
216         try!(s.cbox(indent_unit));
217         // head-ibox, will be closed by print-block after {
218         try!(s.ibox(0u));
219         s.print_block(blk)
220     })
221 }
222
223 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
224     to_string(|s| s.print_meta_item(mi))
225 }
226
227 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
228     to_string(|s| s.print_attribute(attr))
229 }
230
231 pub fn lit_to_string(l: &ast::Lit) -> String {
232     to_string(|s| s.print_literal(l))
233 }
234
235 pub fn explicit_self_to_string(explicit_self: ast::ExplicitSelf_) -> String {
236     to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
237 }
238
239 pub fn variant_to_string(var: &ast::Variant) -> String {
240     to_string(|s| s.print_variant(var))
241 }
242
243 pub fn arg_to_string(arg: &ast::Arg) -> String {
244     to_string(|s| s.print_arg(arg))
245 }
246
247 pub fn mac_to_string(arg: &ast::Mac) -> String {
248     to_string(|s| s.print_mac(arg))
249 }
250
251 pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
252     match vis {
253         ast::Public => format!("pub {}", s),
254         ast::Inherited => s.to_string()
255     }
256 }
257
258 fn needs_parentheses(expr: &ast::Expr) -> bool {
259     match expr.node {
260         ast::ExprAssign(..) | ast::ExprBinary(..) |
261         ast::ExprFnBlock(..) | ast::ExprProc(..) |
262         ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
263         _ => false,
264     }
265 }
266
267 impl<'a> State<'a> {
268     pub fn ibox(&mut self, u: uint) -> IoResult<()> {
269         self.boxes.push(pp::Inconsistent);
270         pp::ibox(&mut self.s, u)
271     }
272
273     pub fn end(&mut self) -> IoResult<()> {
274         self.boxes.pop().unwrap();
275         pp::end(&mut self.s)
276     }
277
278     pub fn cbox(&mut self, u: uint) -> IoResult<()> {
279         self.boxes.push(pp::Consistent);
280         pp::cbox(&mut self.s, u)
281     }
282
283     // "raw box"
284     pub fn rbox(&mut self, u: uint, b: pp::Breaks) -> IoResult<()> {
285         self.boxes.push(b);
286         pp::rbox(&mut self.s, u, b)
287     }
288
289     pub fn nbsp(&mut self) -> IoResult<()> { word(&mut self.s, " ") }
290
291     pub fn word_nbsp(&mut self, w: &str) -> IoResult<()> {
292         try!(word(&mut self.s, w));
293         self.nbsp()
294     }
295
296     pub fn word_space(&mut self, w: &str) -> IoResult<()> {
297         try!(word(&mut self.s, w));
298         space(&mut self.s)
299     }
300
301     pub fn popen(&mut self) -> IoResult<()> { word(&mut self.s, "(") }
302
303     pub fn pclose(&mut self) -> IoResult<()> { word(&mut self.s, ")") }
304
305     pub fn head(&mut self, w: &str) -> IoResult<()> {
306         // outer-box is consistent
307         try!(self.cbox(indent_unit));
308         // head-box is inconsistent
309         try!(self.ibox(w.len() + 1));
310         // keyword that starts the head
311         if !w.is_empty() {
312             try!(self.word_nbsp(w));
313         }
314         Ok(())
315     }
316
317     pub fn bopen(&mut self) -> IoResult<()> {
318         try!(word(&mut self.s, "{"));
319         self.end() // close the head-box
320     }
321
322     pub fn bclose_(&mut self, span: codemap::Span,
323                    indented: uint) -> IoResult<()> {
324         self.bclose_maybe_open(span, indented, true)
325     }
326     pub fn bclose_maybe_open (&mut self, span: codemap::Span,
327                               indented: uint, close_box: bool) -> IoResult<()> {
328         try!(self.maybe_print_comment(span.hi));
329         try!(self.break_offset_if_not_bol(1u, -(indented as int)));
330         try!(word(&mut self.s, "}"));
331         if close_box {
332             try!(self.end()); // close the outer-box
333         }
334         Ok(())
335     }
336     pub fn bclose(&mut self, span: codemap::Span) -> IoResult<()> {
337         self.bclose_(span, indent_unit)
338     }
339
340     pub fn is_begin(&mut self) -> bool {
341         match self.s.last_token() { pp::Begin(_) => true, _ => false }
342     }
343
344     pub fn is_end(&mut self) -> bool {
345         match self.s.last_token() { pp::End => true, _ => false }
346     }
347
348     // is this the beginning of a line?
349     pub fn is_bol(&mut self) -> bool {
350         self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
351     }
352
353     pub fn in_cbox(&self) -> bool {
354         match self.boxes.last() {
355             Some(&last_box) => last_box == pp::Consistent,
356             None => false
357         }
358     }
359
360     pub fn hardbreak_if_not_bol(&mut self) -> IoResult<()> {
361         if !self.is_bol() {
362             try!(hardbreak(&mut self.s))
363         }
364         Ok(())
365     }
366     pub fn space_if_not_bol(&mut self) -> IoResult<()> {
367         if !self.is_bol() { try!(space(&mut self.s)); }
368         Ok(())
369     }
370     pub fn break_offset_if_not_bol(&mut self, n: uint,
371                                    off: int) -> IoResult<()> {
372         if !self.is_bol() {
373             break_offset(&mut self.s, n, off)
374         } else {
375             if off != 0 && self.s.last_token().is_hardbreak_tok() {
376                 // We do something pretty sketchy here: tuck the nonzero
377                 // offset-adjustment we were going to deposit along with the
378                 // break into the previous hardbreak.
379                 self.s.replace_last_token(pp::hardbreak_tok_offset(off));
380             }
381             Ok(())
382         }
383     }
384
385     // Synthesizes a comment that was not textually present in the original source
386     // file.
387     pub fn synth_comment(&mut self, text: String) -> IoResult<()> {
388         try!(word(&mut self.s, "/*"));
389         try!(space(&mut self.s));
390         try!(word(&mut self.s, text.as_slice()));
391         try!(space(&mut self.s));
392         word(&mut self.s, "*/")
393     }
394
395     pub fn commasep<T>(&mut self, b: Breaks, elts: &[T],
396                        op: |&mut State, &T| -> IoResult<()>)
397         -> IoResult<()> {
398         try!(self.rbox(0u, b));
399         let mut first = true;
400         for elt in elts.iter() {
401             if first { first = false; } else { try!(self.word_space(",")); }
402             try!(op(self, elt));
403         }
404         self.end()
405     }
406
407
408     pub fn commasep_cmnt<T>(
409                          &mut self,
410                          b: Breaks,
411                          elts: &[T],
412                          op: |&mut State, &T| -> IoResult<()>,
413                          get_span: |&T| -> codemap::Span) -> IoResult<()> {
414         try!(self.rbox(0u, b));
415         let len = elts.len();
416         let mut i = 0u;
417         for elt in elts.iter() {
418             try!(self.maybe_print_comment(get_span(elt).hi));
419             try!(op(self, elt));
420             i += 1u;
421             if i < len {
422                 try!(word(&mut self.s, ","));
423                 try!(self.maybe_print_trailing_comment(get_span(elt),
424                                                     Some(get_span(&elts[i]).hi)));
425                 try!(self.space_if_not_bol());
426             }
427         }
428         self.end()
429     }
430
431     pub fn commasep_exprs(&mut self, b: Breaks,
432                           exprs: &[Gc<ast::Expr>]) -> IoResult<()> {
433         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&**e), |e| e.span)
434     }
435
436     pub fn print_mod(&mut self, _mod: &ast::Mod,
437                      attrs: &[ast::Attribute]) -> IoResult<()> {
438         try!(self.print_inner_attributes(attrs));
439         for vitem in _mod.view_items.iter() {
440             try!(self.print_view_item(vitem));
441         }
442         for item in _mod.items.iter() {
443             try!(self.print_item(&**item));
444         }
445         Ok(())
446     }
447
448     pub fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod,
449                              attrs: &[ast::Attribute]) -> IoResult<()> {
450         try!(self.print_inner_attributes(attrs));
451         for vitem in nmod.view_items.iter() {
452             try!(self.print_view_item(vitem));
453         }
454         for item in nmod.items.iter() {
455             try!(self.print_foreign_item(&**item));
456         }
457         Ok(())
458     }
459
460     pub fn print_opt_lifetime(&mut self,
461                               lifetime: &Option<ast::Lifetime>) -> IoResult<()> {
462         for l in lifetime.iter() {
463             try!(self.print_lifetime(l));
464             try!(self.nbsp());
465         }
466         Ok(())
467     }
468
469     pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> {
470         try!(self.maybe_print_comment(ty.span.lo));
471         try!(self.ibox(0u));
472         match ty.node {
473             ast::TyNil => try!(word(&mut self.s, "()")),
474             ast::TyBot => try!(word(&mut self.s, "!")),
475             ast::TyBox(ref ty) => {
476                 try!(word(&mut self.s, "@"));
477                 try!(self.print_type(&**ty));
478             }
479             ast::TyUniq(ref ty) => {
480                 try!(word(&mut self.s, "~"));
481                 try!(self.print_type(&**ty));
482             }
483             ast::TyVec(ref ty) => {
484                 try!(word(&mut self.s, "["));
485                 try!(self.print_type(&**ty));
486                 try!(word(&mut self.s, "]"));
487             }
488             ast::TyPtr(ref mt) => {
489                 try!(word(&mut self.s, "*"));
490                 match mt.mutbl {
491                     ast::MutMutable => try!(self.word_nbsp("mut")),
492                     ast::MutImmutable => try!(self.word_nbsp("const")),
493                 }
494                 try!(self.print_type(&*mt.ty));
495             }
496             ast::TyRptr(ref lifetime, ref mt) => {
497                 try!(word(&mut self.s, "&"));
498                 try!(self.print_opt_lifetime(lifetime));
499                 try!(self.print_mt(mt));
500             }
501             ast::TyTup(ref elts) => {
502                 try!(self.popen());
503                 try!(self.commasep(Inconsistent, elts.as_slice(),
504                                    |s, ty| s.print_type_ref(ty)));
505                 if elts.len() == 1 {
506                     try!(word(&mut self.s, ","));
507                 }
508                 try!(self.pclose());
509             }
510             ast::TyParen(ref typ) => {
511                 try!(self.popen());
512                 try!(self.print_type(&**typ));
513                 try!(self.pclose());
514             }
515             ast::TyBareFn(f) => {
516                 let generics = ast::Generics {
517                     lifetimes: f.lifetimes.clone(),
518                     ty_params: OwnedSlice::empty()
519                 };
520                 try!(self.print_ty_fn(Some(f.abi),
521                                       None,
522                                       &None,
523                                       f.fn_style,
524                                       ast::Many,
525                                       &*f.decl,
526                                       None,
527                                       &None,
528                                       Some(&generics),
529                                       None,
530                                       false));
531             }
532             ast::TyClosure(f, ref region) => {
533                 let generics = ast::Generics {
534                     lifetimes: f.lifetimes.clone(),
535                     ty_params: OwnedSlice::empty()
536                 };
537                 try!(self.print_ty_fn(None,
538                                       Some('&'),
539                                       region,
540                                       f.fn_style,
541                                       f.onceness,
542                                       &*f.decl,
543                                       None,
544                                       &f.bounds,
545                                       Some(&generics),
546                                       None,
547                                       false));
548             }
549             ast::TyProc(ref f) => {
550                 let generics = ast::Generics {
551                     lifetimes: f.lifetimes.clone(),
552                     ty_params: OwnedSlice::empty()
553                 };
554                 try!(self.print_ty_fn(None,
555                                       Some('~'),
556                                       &None,
557                                       f.fn_style,
558                                       f.onceness,
559                                       &*f.decl,
560                                       None,
561                                       &f.bounds,
562                                       Some(&generics),
563                                       None,
564                                       false));
565             }
566             ast::TyUnboxedFn(f) => {
567                 try!(self.print_ty_fn(None,
568                                       None,
569                                       &None,
570                                       ast::NormalFn,
571                                       ast::Many,
572                                       &*f.decl,
573                                       None,
574                                       &None,
575                                       None,
576                                       None,
577                                       true));
578             }
579             ast::TyPath(ref path, ref bounds, _) => {
580                 try!(self.print_bounded_path(path, bounds));
581             }
582             ast::TyFixedLengthVec(ref ty, ref v) => {
583                 try!(word(&mut self.s, "["));
584                 try!(self.print_type(&**ty));
585                 try!(word(&mut self.s, ", .."));
586                 try!(self.print_expr(&**v));
587                 try!(word(&mut self.s, "]"));
588             }
589             ast::TyTypeof(ref e) => {
590                 try!(word(&mut self.s, "typeof("));
591                 try!(self.print_expr(&**e));
592                 try!(word(&mut self.s, ")"));
593             }
594             ast::TyInfer => {
595                 try!(word(&mut self.s, "_"));
596             }
597         }
598         self.end()
599     }
600
601     pub fn print_type_ref(&mut self, ty: &P<ast::Ty>) -> IoResult<()> {
602         self.print_type(&**ty)
603     }
604
605     pub fn print_foreign_item(&mut self,
606                               item: &ast::ForeignItem) -> IoResult<()> {
607         try!(self.hardbreak_if_not_bol());
608         try!(self.maybe_print_comment(item.span.lo));
609         try!(self.print_outer_attributes(item.attrs.as_slice()));
610         match item.node {
611             ast::ForeignItemFn(ref decl, ref generics) => {
612                 try!(self.print_fn(&**decl, None, abi::Rust, item.ident, generics,
613                                    None, item.vis));
614                 try!(self.end()); // end head-ibox
615                 try!(word(&mut self.s, ";"));
616                 self.end() // end the outer fn box
617             }
618             ast::ForeignItemStatic(ref t, m) => {
619                 try!(self.head(visibility_qualified(item.vis,
620                                                     "static").as_slice()));
621                 if m {
622                     try!(self.word_space("mut"));
623                 }
624                 try!(self.print_ident(item.ident));
625                 try!(self.word_space(":"));
626                 try!(self.print_type(&**t));
627                 try!(word(&mut self.s, ";"));
628                 try!(self.end()); // end the head-ibox
629                 self.end() // end the outer cbox
630             }
631         }
632     }
633
634     /// Pretty-print an item
635     pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
636         try!(self.hardbreak_if_not_bol());
637         try!(self.maybe_print_comment(item.span.lo));
638         try!(self.print_outer_attributes(item.attrs.as_slice()));
639         try!(self.ann.pre(self, NodeItem(item)));
640         match item.node {
641             ast::ItemStatic(ref ty, m, ref expr) => {
642                 try!(self.head(visibility_qualified(item.vis,
643                                                     "static").as_slice()));
644                 if m == ast::MutMutable {
645                     try!(self.word_space("mut"));
646                 }
647                 try!(self.print_ident(item.ident));
648                 try!(self.word_space(":"));
649                 try!(self.print_type(&**ty));
650                 try!(space(&mut self.s));
651                 try!(self.end()); // end the head-ibox
652
653                 try!(self.word_space("="));
654                 try!(self.print_expr(&**expr));
655                 try!(word(&mut self.s, ";"));
656                 try!(self.end()); // end the outer cbox
657             }
658             ast::ItemFn(ref decl, fn_style, abi, ref typarams, ref body) => {
659                 try!(self.print_fn(
660                     &**decl,
661                     Some(fn_style),
662                     abi,
663                     item.ident,
664                     typarams,
665                     None,
666                     item.vis
667                 ));
668                 try!(word(&mut self.s, " "));
669                 try!(self.print_block_with_attrs(&**body, item.attrs.as_slice()));
670             }
671             ast::ItemMod(ref _mod) => {
672                 try!(self.head(visibility_qualified(item.vis,
673                                                     "mod").as_slice()));
674                 try!(self.print_ident(item.ident));
675                 try!(self.nbsp());
676                 try!(self.bopen());
677                 try!(self.print_mod(_mod, item.attrs.as_slice()));
678                 try!(self.bclose(item.span));
679             }
680             ast::ItemForeignMod(ref nmod) => {
681                 try!(self.head("extern"));
682                 try!(self.word_nbsp(nmod.abi.to_string().as_slice()));
683                 try!(self.bopen());
684                 try!(self.print_foreign_mod(nmod, item.attrs.as_slice()));
685                 try!(self.bclose(item.span));
686             }
687             ast::ItemTy(ref ty, ref params) => {
688                 try!(self.ibox(indent_unit));
689                 try!(self.ibox(0u));
690                 try!(self.word_nbsp(visibility_qualified(item.vis,
691                                                          "type").as_slice()));
692                 try!(self.print_ident(item.ident));
693                 try!(self.print_generics(params));
694                 try!(self.end()); // end the inner ibox
695
696                 try!(space(&mut self.s));
697                 try!(self.word_space("="));
698                 try!(self.print_type(&**ty));
699                 try!(word(&mut self.s, ";"));
700                 try!(self.end()); // end the outer ibox
701             }
702             ast::ItemEnum(ref enum_definition, ref params) => {
703                 try!(self.print_enum_def(
704                     enum_definition,
705                     params,
706                     item.ident,
707                     item.span,
708                     item.vis
709                 ));
710             }
711             ast::ItemStruct(ref struct_def, ref generics) => {
712                 if struct_def.is_virtual {
713                     try!(self.word_space("virtual"));
714                 }
715                 try!(self.head(visibility_qualified(item.vis,
716                                                     "struct").as_slice()));
717                 try!(self.print_struct(&**struct_def, generics, item.ident,
718                                        item.span));
719             }
720
721             ast::ItemImpl(ref generics, ref opt_trait, ref ty, ref methods) => {
722                 try!(self.head(visibility_qualified(item.vis,
723                                                     "impl").as_slice()));
724                 if generics.is_parameterized() {
725                     try!(self.print_generics(generics));
726                     try!(space(&mut self.s));
727                 }
728
729                 match opt_trait {
730                     &Some(ref t) => {
731                         try!(self.print_trait_ref(t));
732                         try!(space(&mut self.s));
733                         try!(self.word_space("for"));
734                     }
735                     &None => {}
736                 }
737
738                 try!(self.print_type(&**ty));
739
740                 try!(space(&mut self.s));
741                 try!(self.bopen());
742                 try!(self.print_inner_attributes(item.attrs.as_slice()));
743                 for meth in methods.iter() {
744                     try!(self.print_method(&**meth));
745                 }
746                 try!(self.bclose(item.span));
747             }
748             ast::ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
749                 try!(self.head(visibility_qualified(item.vis,
750                                                     "trait").as_slice()));
751                 try!(self.print_ident(item.ident));
752                 try!(self.print_generics(generics));
753                 match unbound {
754                     &Some(TraitTyParamBound(ref tref)) => {
755                         try!(space(&mut self.s));
756                         try!(self.word_space("for"));
757                         try!(self.print_trait_ref(tref));
758                         try!(word(&mut self.s, "?"));
759                     }
760                     _ => {}
761                 }
762                 if traits.len() != 0u {
763                     try!(word(&mut self.s, ":"));
764                     for (i, trait_) in traits.iter().enumerate() {
765                         try!(self.nbsp());
766                         if i != 0 {
767                             try!(self.word_space("+"));
768                         }
769                         try!(self.print_path(&trait_.path, false));
770                     }
771                 }
772                 try!(word(&mut self.s, " "));
773                 try!(self.bopen());
774                 for meth in methods.iter() {
775                     try!(self.print_trait_method(meth));
776                 }
777                 try!(self.bclose(item.span));
778             }
779             // I think it's reasonable to hide the context here:
780             ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
781                                             ..}) => {
782                 try!(self.print_visibility(item.vis));
783                 try!(self.print_path(pth, false));
784                 try!(word(&mut self.s, "! "));
785                 try!(self.print_ident(item.ident));
786                 try!(self.cbox(indent_unit));
787                 try!(self.popen());
788                 try!(self.print_tts(tts.as_slice()));
789                 try!(self.pclose());
790                 try!(self.end());
791             }
792         }
793         self.ann.post(self, NodeItem(item))
794     }
795
796     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> {
797         self.print_path(&t.path, false)
798     }
799
800     pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
801                           generics: &ast::Generics, ident: ast::Ident,
802                           span: codemap::Span,
803                           visibility: ast::Visibility) -> IoResult<()> {
804         try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
805         try!(self.print_ident(ident));
806         try!(self.print_generics(generics));
807         try!(space(&mut self.s));
808         self.print_variants(enum_definition.variants.as_slice(), span)
809     }
810
811     pub fn print_variants(&mut self,
812                           variants: &[P<ast::Variant>],
813                           span: codemap::Span) -> IoResult<()> {
814         try!(self.bopen());
815         for v in variants.iter() {
816             try!(self.space_if_not_bol());
817             try!(self.maybe_print_comment(v.span.lo));
818             try!(self.print_outer_attributes(v.node.attrs.as_slice()));
819             try!(self.ibox(indent_unit));
820             try!(self.print_variant(&**v));
821             try!(word(&mut self.s, ","));
822             try!(self.end());
823             try!(self.maybe_print_trailing_comment(v.span, None));
824         }
825         self.bclose(span)
826     }
827
828     pub fn print_visibility(&mut self, vis: ast::Visibility) -> IoResult<()> {
829         match vis {
830             ast::Public => self.word_nbsp("pub"),
831             ast::Inherited => Ok(())
832         }
833     }
834
835     pub fn print_struct(&mut self,
836                         struct_def: &ast::StructDef,
837                         generics: &ast::Generics,
838                         ident: ast::Ident,
839                         span: codemap::Span) -> IoResult<()> {
840         try!(self.print_ident(ident));
841         try!(self.print_generics(generics));
842         match struct_def.super_struct {
843             Some(ref t) => {
844                 try!(self.word_space(":"));
845                 try!(self.print_type(&**t));
846             },
847             None => {},
848         }
849         if ast_util::struct_def_is_tuple_like(struct_def) {
850             if !struct_def.fields.is_empty() {
851                 try!(self.popen());
852                 try!(self.commasep(
853                     Inconsistent, struct_def.fields.as_slice(),
854                     |s, field| {
855                         match field.node.kind {
856                             ast::NamedField(..) => fail!("unexpected named field"),
857                             ast::UnnamedField(vis) => {
858                                 try!(s.print_visibility(vis));
859                                 try!(s.maybe_print_comment(field.span.lo));
860                                 s.print_type(&*field.node.ty)
861                             }
862                         }
863                     }
864                 ));
865                 try!(self.pclose());
866             }
867             try!(word(&mut self.s, ";"));
868             try!(self.end());
869             self.end() // close the outer-box
870         } else {
871             try!(self.nbsp());
872             try!(self.bopen());
873             try!(self.hardbreak_if_not_bol());
874
875             for field in struct_def.fields.iter() {
876                 match field.node.kind {
877                     ast::UnnamedField(..) => fail!("unexpected unnamed field"),
878                     ast::NamedField(ident, visibility) => {
879                         try!(self.hardbreak_if_not_bol());
880                         try!(self.maybe_print_comment(field.span.lo));
881                         try!(self.print_outer_attributes(field.node.attrs.as_slice()));
882                         try!(self.print_visibility(visibility));
883                         try!(self.print_ident(ident));
884                         try!(self.word_nbsp(":"));
885                         try!(self.print_type(&*field.node.ty));
886                         try!(word(&mut self.s, ","));
887                     }
888                 }
889             }
890
891             self.bclose(span)
892         }
893     }
894
895     /// This doesn't deserve to be called "pretty" printing, but it should be
896     /// meaning-preserving. A quick hack that might help would be to look at the
897     /// spans embedded in the TTs to decide where to put spaces and newlines.
898     /// But it'd be better to parse these according to the grammar of the
899     /// appropriate macro, transcribe back into the grammar we just parsed from,
900     /// and then pretty-print the resulting AST nodes (so, e.g., we print
901     /// expression arguments as expressions). It can be done! I think.
902     pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
903         match *tt {
904             ast::TTDelim(ref tts) => self.print_tts(tts.as_slice()),
905             ast::TTTok(_, ref tk) => {
906                 try!(word(&mut self.s, parse::token::to_string(tk).as_slice()));
907                 match *tk {
908                     parse::token::DOC_COMMENT(..) => {
909                         hardbreak(&mut self.s)
910                     }
911                     _ => Ok(())
912                 }
913             }
914             ast::TTSeq(_, ref tts, ref sep, zerok) => {
915                 try!(word(&mut self.s, "$("));
916                 for tt_elt in (*tts).iter() {
917                     try!(self.print_tt(tt_elt));
918                 }
919                 try!(word(&mut self.s, ")"));
920                 match *sep {
921                     Some(ref tk) => {
922                         try!(word(&mut self.s,
923                                   parse::token::to_string(tk).as_slice()));
924                     }
925                     None => ()
926                 }
927                 word(&mut self.s, if zerok { "*" } else { "+" })
928             }
929             ast::TTNonterminal(_, name) => {
930                 try!(word(&mut self.s, "$"));
931                 self.print_ident(name)
932             }
933         }
934     }
935
936     pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> IoResult<()> {
937         try!(self.ibox(0));
938         for (i, tt) in tts.iter().enumerate() {
939             if i != 0 {
940                 try!(space(&mut self.s));
941             }
942             try!(self.print_tt(tt));
943         }
944         self.end()
945     }
946
947     pub fn print_variant(&mut self, v: &ast::Variant) -> IoResult<()> {
948         try!(self.print_visibility(v.node.vis));
949         match v.node.kind {
950             ast::TupleVariantKind(ref args) => {
951                 try!(self.print_ident(v.node.name));
952                 if !args.is_empty() {
953                     try!(self.popen());
954                     try!(self.commasep(Consistent,
955                                        args.as_slice(),
956                                        |s, arg| s.print_type(&*arg.ty)));
957                     try!(self.pclose());
958                 }
959             }
960             ast::StructVariantKind(ref struct_def) => {
961                 try!(self.head(""));
962                 let generics = ast_util::empty_generics();
963                 try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
964             }
965         }
966         match v.node.disr_expr {
967             Some(ref d) => {
968                 try!(space(&mut self.s));
969                 try!(self.word_space("="));
970                 self.print_expr(&**d)
971             }
972             _ => Ok(())
973         }
974     }
975
976     pub fn print_ty_method(&mut self, m: &ast::TypeMethod) -> IoResult<()> {
977         try!(self.hardbreak_if_not_bol());
978         try!(self.maybe_print_comment(m.span.lo));
979         try!(self.print_outer_attributes(m.attrs.as_slice()));
980         try!(self.print_ty_fn(None,
981                               None,
982                               &None,
983                               m.fn_style,
984                               ast::Many,
985                               &*m.decl,
986                               Some(m.ident),
987                               &None,
988                               Some(&m.generics),
989                               Some(m.explicit_self.node),
990                               false));
991         word(&mut self.s, ";")
992     }
993
994     pub fn print_trait_method(&mut self,
995                               m: &ast::TraitMethod) -> IoResult<()> {
996         match *m {
997             Required(ref ty_m) => self.print_ty_method(ty_m),
998             Provided(ref m) => self.print_method(&**m)
999         }
1000     }
1001
1002     pub fn print_method(&mut self, meth: &ast::Method) -> IoResult<()> {
1003         try!(self.hardbreak_if_not_bol());
1004         try!(self.maybe_print_comment(meth.span.lo));
1005         try!(self.print_outer_attributes(meth.attrs.as_slice()));
1006         match meth.node {
1007             ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
1008                 try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
1009                                    ident, generics, Some(explicit_self.node),
1010                                    vis));
1011                 try!(word(&mut self.s, " "));
1012                 self.print_block_with_attrs(&*body, meth.attrs.as_slice())
1013             },
1014             ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
1015                                             ..}) => {
1016                 // code copied from ItemMac:
1017                 try!(self.print_path(pth, false));
1018                 try!(word(&mut self.s, "! "));
1019                 try!(self.cbox(indent_unit));
1020                 try!(self.popen());
1021                 try!(self.print_tts(tts.as_slice()));
1022                 try!(self.pclose());
1023                 self.end()
1024             }
1025         }
1026     }
1027
1028     pub fn print_outer_attributes(&mut self,
1029                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1030         let mut count = 0u;
1031         for attr in attrs.iter() {
1032             match attr.node.style {
1033                 ast::AttrOuter => {
1034                     try!(self.print_attribute(attr));
1035                     count += 1;
1036                 }
1037                 _ => {/* fallthrough */ }
1038             }
1039         }
1040         if count > 0 {
1041             try!(self.hardbreak_if_not_bol());
1042         }
1043         Ok(())
1044     }
1045
1046     pub fn print_inner_attributes(&mut self,
1047                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1048         let mut count = 0u;
1049         for attr in attrs.iter() {
1050             match attr.node.style {
1051                 ast::AttrInner => {
1052                     try!(self.print_attribute(attr));
1053                     count += 1;
1054                 }
1055                 _ => {/* fallthrough */ }
1056             }
1057         }
1058         if count > 0 {
1059             try!(self.hardbreak_if_not_bol());
1060         }
1061         Ok(())
1062     }
1063
1064     pub fn print_attribute(&mut self, attr: &ast::Attribute) -> IoResult<()> {
1065         try!(self.hardbreak_if_not_bol());
1066         try!(self.maybe_print_comment(attr.span.lo));
1067         if attr.node.is_sugared_doc {
1068             word(&mut self.s, attr.value_str().unwrap().get())
1069         } else {
1070             match attr.node.style {
1071                 ast::AttrInner => try!(word(&mut self.s, "#![")),
1072                 ast::AttrOuter => try!(word(&mut self.s, "#[")),
1073             }
1074             try!(self.print_meta_item(&*attr.meta()));
1075             word(&mut self.s, "]")
1076         }
1077     }
1078
1079
1080     pub fn print_stmt(&mut self, st: &ast::Stmt) -> IoResult<()> {
1081         try!(self.maybe_print_comment(st.span.lo));
1082         match st.node {
1083             ast::StmtDecl(ref decl, _) => {
1084                 try!(self.print_decl(&**decl));
1085             }
1086             ast::StmtExpr(ref expr, _) => {
1087                 try!(self.space_if_not_bol());
1088                 try!(self.print_expr(&**expr));
1089             }
1090             ast::StmtSemi(ref expr, _) => {
1091                 try!(self.space_if_not_bol());
1092                 try!(self.print_expr(&**expr));
1093                 try!(word(&mut self.s, ";"));
1094             }
1095             ast::StmtMac(ref mac, semi) => {
1096                 try!(self.space_if_not_bol());
1097                 try!(self.print_mac(mac));
1098                 if semi {
1099                     try!(word(&mut self.s, ";"));
1100                 }
1101             }
1102         }
1103         if parse::classify::stmt_ends_with_semi(st) {
1104             try!(word(&mut self.s, ";"));
1105         }
1106         self.maybe_print_trailing_comment(st.span, None)
1107     }
1108
1109     pub fn print_block(&mut self, blk: &ast::Block) -> IoResult<()> {
1110         self.print_block_with_attrs(blk, &[])
1111     }
1112
1113     pub fn print_block_unclosed(&mut self, blk: &ast::Block) -> IoResult<()> {
1114         self.print_block_unclosed_indent(blk, indent_unit)
1115     }
1116
1117     pub fn print_block_unclosed_indent(&mut self, blk: &ast::Block,
1118                                        indented: uint) -> IoResult<()> {
1119         self.print_block_maybe_unclosed(blk, indented, &[], false)
1120     }
1121
1122     pub fn print_block_with_attrs(&mut self,
1123                                   blk: &ast::Block,
1124                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1125         self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
1126     }
1127
1128     pub fn print_block_maybe_unclosed(&mut self,
1129                                       blk: &ast::Block,
1130                                       indented: uint,
1131                                       attrs: &[ast::Attribute],
1132                                       close_box: bool) -> IoResult<()> {
1133         match blk.rules {
1134             ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
1135             ast::DefaultBlock => ()
1136         }
1137         try!(self.maybe_print_comment(blk.span.lo));
1138         try!(self.ann.pre(self, NodeBlock(blk)));
1139         try!(self.bopen());
1140
1141         try!(self.print_inner_attributes(attrs));
1142
1143         for vi in blk.view_items.iter() {
1144             try!(self.print_view_item(vi));
1145         }
1146         for st in blk.stmts.iter() {
1147             try!(self.print_stmt(&**st));
1148         }
1149         match blk.expr {
1150             Some(ref expr) => {
1151                 try!(self.space_if_not_bol());
1152                 try!(self.print_expr(&**expr));
1153                 try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
1154             }
1155             _ => ()
1156         }
1157         try!(self.bclose_maybe_open(blk.span, indented, close_box));
1158         self.ann.post(self, NodeBlock(blk))
1159     }
1160
1161     fn print_else(&mut self, els: Option<Gc<ast::Expr>>) -> IoResult<()> {
1162         match els {
1163             Some(_else) => {
1164                 match _else.node {
1165                     // "another else-if"
1166                     ast::ExprIf(ref i, ref t, e) => {
1167                         try!(self.cbox(indent_unit - 1u));
1168                         try!(self.ibox(0u));
1169                         try!(word(&mut self.s, " else if "));
1170                         try!(self.print_expr(&**i));
1171                         try!(space(&mut self.s));
1172                         try!(self.print_block(&**t));
1173                         self.print_else(e)
1174                     }
1175                     // "final else"
1176                     ast::ExprBlock(ref b) => {
1177                         try!(self.cbox(indent_unit - 1u));
1178                         try!(self.ibox(0u));
1179                         try!(word(&mut self.s, " else "));
1180                         self.print_block(&**b)
1181                     }
1182                     // BLEAH, constraints would be great here
1183                     _ => {
1184                         fail!("print_if saw if with weird alternative");
1185                     }
1186                 }
1187             }
1188             _ => Ok(())
1189         }
1190     }
1191
1192     pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
1193                     elseopt: Option<Gc<ast::Expr>>, chk: bool) -> IoResult<()> {
1194         try!(self.head("if"));
1195         if chk { try!(self.word_nbsp("check")); }
1196         try!(self.print_expr(test));
1197         try!(space(&mut self.s));
1198         try!(self.print_block(blk));
1199         self.print_else(elseopt)
1200     }
1201
1202     pub fn print_mac(&mut self, m: &ast::Mac) -> IoResult<()> {
1203         match m.node {
1204             // I think it's reasonable to hide the ctxt here:
1205             ast::MacInvocTT(ref pth, ref tts, _) => {
1206                 try!(self.print_path(pth, false));
1207                 try!(word(&mut self.s, "!"));
1208                 try!(self.popen());
1209                 try!(self.print_tts(tts.as_slice()));
1210                 self.pclose()
1211             }
1212         }
1213     }
1214
1215     pub fn print_expr_vstore(&mut self, t: ast::ExprVstore) -> IoResult<()> {
1216         match t {
1217             ast::ExprVstoreUniq => word(&mut self.s, "box "),
1218             ast::ExprVstoreSlice => word(&mut self.s, "&"),
1219             ast::ExprVstoreMutSlice => {
1220                 try!(word(&mut self.s, "&"));
1221                 word(&mut self.s, "mut")
1222             }
1223         }
1224     }
1225
1226     fn print_call_post(&mut self, args: &[Gc<ast::Expr>]) -> IoResult<()> {
1227         try!(self.popen());
1228         try!(self.commasep_exprs(Inconsistent, args));
1229         self.pclose()
1230     }
1231
1232     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
1233         let needs_par = needs_parentheses(expr);
1234         if needs_par {
1235             try!(self.popen());
1236         }
1237         try!(self.print_expr(expr));
1238         if needs_par {
1239             try!(self.pclose());
1240         }
1241         Ok(())
1242     }
1243
1244     pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
1245         try!(self.maybe_print_comment(expr.span.lo));
1246         try!(self.ibox(indent_unit));
1247         try!(self.ann.pre(self, NodeExpr(expr)));
1248         match expr.node {
1249             ast::ExprVstore(ref e, v) => {
1250                 try!(self.print_expr_vstore(v));
1251                 try!(self.print_expr(&**e));
1252             },
1253             ast::ExprBox(ref p, ref e) => {
1254                 try!(word(&mut self.s, "box"));
1255                 try!(word(&mut self.s, "("));
1256                 try!(self.print_expr(&**p));
1257                 try!(self.word_space(")"));
1258                 try!(self.print_expr(&**e));
1259             }
1260             ast::ExprVec(ref exprs) => {
1261                 try!(self.ibox(indent_unit));
1262                 try!(word(&mut self.s, "["));
1263                 try!(self.commasep_exprs(Inconsistent, exprs.as_slice()));
1264                 try!(word(&mut self.s, "]"));
1265                 try!(self.end());
1266             }
1267
1268             ast::ExprRepeat(ref element, ref count) => {
1269                 try!(self.ibox(indent_unit));
1270                 try!(word(&mut self.s, "["));
1271                 try!(self.print_expr(&**element));
1272                 try!(word(&mut self.s, ","));
1273                 try!(word(&mut self.s, ".."));
1274                 try!(self.print_expr(&**count));
1275                 try!(word(&mut self.s, "]"));
1276                 try!(self.end());
1277             }
1278
1279             ast::ExprStruct(ref path, ref fields, wth) => {
1280                 try!(self.print_path(path, true));
1281                 try!(word(&mut self.s, "{"));
1282                 try!(self.commasep_cmnt(
1283                     Consistent,
1284                     fields.as_slice(),
1285                     |s, field| {
1286                         try!(s.ibox(indent_unit));
1287                         try!(s.print_ident(field.ident.node));
1288                         try!(s.word_space(":"));
1289                         try!(s.print_expr(&*field.expr));
1290                         s.end()
1291                     },
1292                     |f| f.span));
1293                 match wth {
1294                     Some(ref expr) => {
1295                         try!(self.ibox(indent_unit));
1296                         if !fields.is_empty() {
1297                             try!(word(&mut self.s, ","));
1298                             try!(space(&mut self.s));
1299                         }
1300                         try!(word(&mut self.s, ".."));
1301                         try!(self.print_expr(&**expr));
1302                         try!(self.end());
1303                     }
1304                     _ => try!(word(&mut self.s, ","))
1305                 }
1306                 try!(word(&mut self.s, "}"));
1307             }
1308             ast::ExprTup(ref exprs) => {
1309                 try!(self.popen());
1310                 try!(self.commasep_exprs(Inconsistent, exprs.as_slice()));
1311                 if exprs.len() == 1 {
1312                     try!(word(&mut self.s, ","));
1313                 }
1314                 try!(self.pclose());
1315             }
1316             ast::ExprCall(ref func, ref args) => {
1317                 try!(self.print_expr_maybe_paren(&**func));
1318                 try!(self.print_call_post(args.as_slice()));
1319             }
1320             ast::ExprMethodCall(ident, ref tys, ref args) => {
1321                 let base_args = args.slice_from(1);
1322                 try!(self.print_expr(&**args.get(0)));
1323                 try!(word(&mut self.s, "."));
1324                 try!(self.print_ident(ident.node));
1325                 if tys.len() > 0u {
1326                     try!(word(&mut self.s, "::<"));
1327                     try!(self.commasep(Inconsistent, tys.as_slice(),
1328                                        |s, ty| s.print_type_ref(ty)));
1329                     try!(word(&mut self.s, ">"));
1330                 }
1331                 try!(self.print_call_post(base_args));
1332             }
1333             ast::ExprBinary(op, ref lhs, ref rhs) => {
1334                 try!(self.print_expr(&**lhs));
1335                 try!(space(&mut self.s));
1336                 try!(self.word_space(ast_util::binop_to_string(op)));
1337                 try!(self.print_expr(&**rhs));
1338             }
1339             ast::ExprUnary(op, ref expr) => {
1340                 try!(word(&mut self.s, ast_util::unop_to_string(op)));
1341                 try!(self.print_expr_maybe_paren(&**expr));
1342             }
1343             ast::ExprAddrOf(m, ref expr) => {
1344                 try!(word(&mut self.s, "&"));
1345                 try!(self.print_mutability(m));
1346                 try!(self.print_expr_maybe_paren(&**expr));
1347             }
1348             ast::ExprLit(ref lit) => try!(self.print_literal(&**lit)),
1349             ast::ExprCast(ref expr, ref ty) => {
1350                 try!(self.print_expr(&**expr));
1351                 try!(space(&mut self.s));
1352                 try!(self.word_space("as"));
1353                 try!(self.print_type(&**ty));
1354             }
1355             ast::ExprIf(ref test, ref blk, elseopt) => {
1356                 try!(self.print_if(&**test, &**blk, elseopt, false));
1357             }
1358             ast::ExprWhile(ref test, ref blk) => {
1359                 try!(self.head("while"));
1360                 try!(self.print_expr(&**test));
1361                 try!(space(&mut self.s));
1362                 try!(self.print_block(&**blk));
1363             }
1364             ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
1365                 for ident in opt_ident.iter() {
1366                     try!(self.print_ident(*ident));
1367                     try!(self.word_space(":"));
1368                 }
1369                 try!(self.head("for"));
1370                 try!(self.print_pat(&**pat));
1371                 try!(space(&mut self.s));
1372                 try!(self.word_space("in"));
1373                 try!(self.print_expr(&**iter));
1374                 try!(space(&mut self.s));
1375                 try!(self.print_block(&**blk));
1376             }
1377             ast::ExprLoop(ref blk, opt_ident) => {
1378                 for ident in opt_ident.iter() {
1379                     try!(self.print_ident(*ident));
1380                     try!(self.word_space(":"));
1381                 }
1382                 try!(self.head("loop"));
1383                 try!(space(&mut self.s));
1384                 try!(self.print_block(&**blk));
1385             }
1386             ast::ExprMatch(ref expr, ref arms) => {
1387                 try!(self.cbox(indent_unit));
1388                 try!(self.ibox(4));
1389                 try!(self.word_nbsp("match"));
1390                 try!(self.print_expr(&**expr));
1391                 try!(space(&mut self.s));
1392                 try!(self.bopen());
1393                 let len = arms.len();
1394                 for (i, arm) in arms.iter().enumerate() {
1395                     // I have no idea why this check is necessary, but here it
1396                     // is :(
1397                     if arm.attrs.is_empty() {
1398                         try!(space(&mut self.s));
1399                     }
1400                     try!(self.cbox(indent_unit));
1401                     try!(self.ibox(0u));
1402                     try!(self.print_outer_attributes(arm.attrs.as_slice()));
1403                     let mut first = true;
1404                     for p in arm.pats.iter() {
1405                         if first {
1406                             first = false;
1407                         } else {
1408                             try!(space(&mut self.s));
1409                             try!(self.word_space("|"));
1410                         }
1411                         try!(self.print_pat(&**p));
1412                     }
1413                     try!(space(&mut self.s));
1414                     match arm.guard {
1415                         Some(ref e) => {
1416                             try!(self.word_space("if"));
1417                             try!(self.print_expr(&**e));
1418                             try!(space(&mut self.s));
1419                         }
1420                         None => ()
1421                     }
1422                     try!(self.word_space("=>"));
1423
1424                     match arm.body.node {
1425                         ast::ExprBlock(ref blk) => {
1426                             // the block will close the pattern's ibox
1427                             try!(self.print_block_unclosed_indent(&**blk,
1428                                                                   indent_unit));
1429                         }
1430                         _ => {
1431                             try!(self.end()); // close the ibox for the pattern
1432                             try!(self.print_expr(&*arm.body));
1433                         }
1434                     }
1435                     if !expr_is_simple_block(expr.clone())
1436                         && i < len - 1 {
1437                         try!(word(&mut self.s, ","));
1438                     }
1439                     try!(self.end()); // close enclosing cbox
1440                 }
1441                 try!(self.bclose_(expr.span, indent_unit));
1442             }
1443             ast::ExprFnBlock(ref decl, ref body) => {
1444                 // in do/for blocks we don't want to show an empty
1445                 // argument list, but at this point we don't know which
1446                 // we are inside.
1447                 //
1448                 // if !decl.inputs.is_empty() {
1449                 try!(self.print_fn_block_args(&**decl));
1450                 try!(space(&mut self.s));
1451                 // }
1452
1453                 if !body.stmts.is_empty() || !body.expr.is_some() {
1454                     try!(self.print_block_unclosed(&**body));
1455                 } else {
1456                     // we extract the block, so as not to create another set of boxes
1457                     match body.expr.unwrap().node {
1458                         ast::ExprBlock(ref blk) => {
1459                             try!(self.print_block_unclosed(&**blk));
1460                         }
1461                         _ => {
1462                             // this is a bare expression
1463                             try!(self.print_expr(&*body.expr.unwrap()));
1464                             try!(self.end()); // need to close a box
1465                         }
1466                     }
1467                 }
1468                 // a box will be closed by print_expr, but we didn't want an overall
1469                 // wrapper so we closed the corresponding opening. so create an
1470                 // empty box to satisfy the close.
1471                 try!(self.ibox(0));
1472             }
1473             ast::ExprProc(ref decl, ref body) => {
1474                 // in do/for blocks we don't want to show an empty
1475                 // argument list, but at this point we don't know which
1476                 // we are inside.
1477                 //
1478                 // if !decl.inputs.is_empty() {
1479                 try!(self.print_proc_args(&**decl));
1480                 try!(space(&mut self.s));
1481                 // }
1482                 assert!(body.stmts.is_empty());
1483                 assert!(body.expr.is_some());
1484                 // we extract the block, so as not to create another set of boxes
1485                 match body.expr.unwrap().node {
1486                     ast::ExprBlock(ref blk) => {
1487                         try!(self.print_block_unclosed(&**blk));
1488                     }
1489                     _ => {
1490                         // this is a bare expression
1491                         try!(self.print_expr(&*body.expr.unwrap()));
1492                         try!(self.end()); // need to close a box
1493                     }
1494                 }
1495                 // a box will be closed by print_expr, but we didn't want an overall
1496                 // wrapper so we closed the corresponding opening. so create an
1497                 // empty box to satisfy the close.
1498                 try!(self.ibox(0));
1499             }
1500             ast::ExprBlock(ref blk) => {
1501                 // containing cbox, will be closed by print-block at }
1502                 try!(self.cbox(indent_unit));
1503                 // head-box, will be closed by print-block after {
1504                 try!(self.ibox(0u));
1505                 try!(self.print_block(&**blk));
1506             }
1507             ast::ExprAssign(ref lhs, ref rhs) => {
1508                 try!(self.print_expr(&**lhs));
1509                 try!(space(&mut self.s));
1510                 try!(self.word_space("="));
1511                 try!(self.print_expr(&**rhs));
1512             }
1513             ast::ExprAssignOp(op, ref lhs, ref rhs) => {
1514                 try!(self.print_expr(&**lhs));
1515                 try!(space(&mut self.s));
1516                 try!(word(&mut self.s, ast_util::binop_to_string(op)));
1517                 try!(self.word_space("="));
1518                 try!(self.print_expr(&**rhs));
1519             }
1520             ast::ExprField(ref expr, id, ref tys) => {
1521                 try!(self.print_expr(&**expr));
1522                 try!(word(&mut self.s, "."));
1523                 try!(self.print_ident(id.node));
1524                 if tys.len() > 0u {
1525                     try!(word(&mut self.s, "::<"));
1526                     try!(self.commasep(
1527                         Inconsistent, tys.as_slice(),
1528                         |s, ty| s.print_type_ref(ty)));
1529                     try!(word(&mut self.s, ">"));
1530                 }
1531             }
1532             ast::ExprIndex(ref expr, ref index) => {
1533                 try!(self.print_expr(&**expr));
1534                 try!(word(&mut self.s, "["));
1535                 try!(self.print_expr(&**index));
1536                 try!(word(&mut self.s, "]"));
1537             }
1538             ast::ExprPath(ref path) => try!(self.print_path(path, true)),
1539             ast::ExprBreak(opt_ident) => {
1540                 try!(word(&mut self.s, "break"));
1541                 try!(space(&mut self.s));
1542                 for ident in opt_ident.iter() {
1543                     try!(self.print_ident(*ident));
1544                     try!(space(&mut self.s));
1545                 }
1546             }
1547             ast::ExprAgain(opt_ident) => {
1548                 try!(word(&mut self.s, "continue"));
1549                 try!(space(&mut self.s));
1550                 for ident in opt_ident.iter() {
1551                     try!(self.print_ident(*ident));
1552                     try!(space(&mut self.s))
1553                 }
1554             }
1555             ast::ExprRet(ref result) => {
1556                 try!(word(&mut self.s, "return"));
1557                 match *result {
1558                     Some(ref expr) => {
1559                         try!(word(&mut self.s, " "));
1560                         try!(self.print_expr(&**expr));
1561                     }
1562                     _ => ()
1563                 }
1564             }
1565             ast::ExprInlineAsm(ref a) => {
1566                 if a.volatile {
1567                     try!(word(&mut self.s, "__volatile__ asm!"));
1568                 } else {
1569                     try!(word(&mut self.s, "asm!"));
1570                 }
1571                 try!(self.popen());
1572                 try!(self.print_string(a.asm.get(), a.asm_str_style));
1573                 try!(self.word_space(":"));
1574
1575                 try!(self.commasep(Inconsistent, a.outputs.as_slice(),
1576                                    |s, &(ref co, ref o)| {
1577                     try!(s.print_string(co.get(), ast::CookedStr));
1578                     try!(s.popen());
1579                     try!(s.print_expr(&**o));
1580                     try!(s.pclose());
1581                     Ok(())
1582                 }));
1583                 try!(space(&mut self.s));
1584                 try!(self.word_space(":"));
1585
1586                 try!(self.commasep(Inconsistent, a.inputs.as_slice(),
1587                                    |s, &(ref co, ref o)| {
1588                     try!(s.print_string(co.get(), ast::CookedStr));
1589                     try!(s.popen());
1590                     try!(s.print_expr(&**o));
1591                     try!(s.pclose());
1592                     Ok(())
1593                 }));
1594                 try!(space(&mut self.s));
1595                 try!(self.word_space(":"));
1596
1597                 try!(self.print_string(a.clobbers.get(), ast::CookedStr));
1598                 try!(self.pclose());
1599             }
1600             ast::ExprMac(ref m) => try!(self.print_mac(m)),
1601             ast::ExprParen(ref e) => {
1602                 try!(self.popen());
1603                 try!(self.print_expr(&**e));
1604                 try!(self.pclose());
1605             }
1606         }
1607         try!(self.ann.post(self, NodeExpr(expr)));
1608         self.end()
1609     }
1610
1611     pub fn print_local_decl(&mut self, loc: &ast::Local) -> IoResult<()> {
1612         try!(self.print_pat(&*loc.pat));
1613         match loc.ty.node {
1614             ast::TyInfer => Ok(()),
1615             _ => {
1616                 try!(self.word_space(":"));
1617                 self.print_type(&*loc.ty)
1618             }
1619         }
1620     }
1621
1622     pub fn print_decl(&mut self, decl: &ast::Decl) -> IoResult<()> {
1623         try!(self.maybe_print_comment(decl.span.lo));
1624         match decl.node {
1625             ast::DeclLocal(ref loc) => {
1626                 try!(self.space_if_not_bol());
1627                 try!(self.ibox(indent_unit));
1628                 try!(self.word_nbsp("let"));
1629
1630                 try!(self.ibox(indent_unit));
1631                 try!(self.print_local_decl(&**loc));
1632                 try!(self.end());
1633                 match loc.init {
1634                     Some(ref init) => {
1635                         try!(self.nbsp());
1636                         try!(self.word_space("="));
1637                         try!(self.print_expr(&**init));
1638                     }
1639                     _ => {}
1640                 }
1641                 self.end()
1642             }
1643             ast::DeclItem(ref item) => self.print_item(&**item)
1644         }
1645     }
1646
1647     pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
1648         word(&mut self.s, token::get_ident(ident).get())
1649     }
1650
1651     pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
1652         word(&mut self.s, token::get_name(name).get())
1653     }
1654
1655     pub fn print_for_decl(&mut self, loc: &ast::Local,
1656                           coll: &ast::Expr) -> IoResult<()> {
1657         try!(self.print_local_decl(loc));
1658         try!(space(&mut self.s));
1659         try!(self.word_space("in"));
1660         self.print_expr(coll)
1661     }
1662
1663     fn print_path_(&mut self,
1664                    path: &ast::Path,
1665                    colons_before_params: bool,
1666                    opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>)
1667         -> IoResult<()> {
1668         try!(self.maybe_print_comment(path.span.lo));
1669         if path.global {
1670             try!(word(&mut self.s, "::"));
1671         }
1672
1673         let mut first = true;
1674         for segment in path.segments.iter() {
1675             if first {
1676                 first = false
1677             } else {
1678                 try!(word(&mut self.s, "::"))
1679             }
1680
1681             try!(self.print_ident(segment.identifier));
1682
1683             if !segment.lifetimes.is_empty() || !segment.types.is_empty() {
1684                 if colons_before_params {
1685                     try!(word(&mut self.s, "::"))
1686                 }
1687                 try!(word(&mut self.s, "<"));
1688
1689                 let mut comma = false;
1690                 for lifetime in segment.lifetimes.iter() {
1691                     if comma {
1692                         try!(self.word_space(","))
1693                     }
1694                     try!(self.print_lifetime(lifetime));
1695                     comma = true;
1696                 }
1697
1698                 if !segment.types.is_empty() {
1699                     if comma {
1700                         try!(self.word_space(","))
1701                     }
1702                     try!(self.commasep(
1703                         Inconsistent,
1704                         segment.types.as_slice(),
1705                         |s, ty| s.print_type_ref(ty)));
1706                 }
1707
1708                 try!(word(&mut self.s, ">"))
1709             }
1710         }
1711
1712         match *opt_bounds {
1713             None => Ok(()),
1714             Some(ref bounds) => self.print_bounds(&None, bounds, true, true),
1715         }
1716     }
1717
1718     fn print_path(&mut self, path: &ast::Path,
1719                   colons_before_params: bool) -> IoResult<()> {
1720         self.print_path_(path, colons_before_params, &None)
1721     }
1722
1723     fn print_bounded_path(&mut self, path: &ast::Path,
1724                           bounds: &Option<OwnedSlice<ast::TyParamBound>>)
1725         -> IoResult<()> {
1726         self.print_path_(path, false, bounds)
1727     }
1728
1729     pub fn print_pat(&mut self, pat: &ast::Pat) -> IoResult<()> {
1730         try!(self.maybe_print_comment(pat.span.lo));
1731         try!(self.ann.pre(self, NodePat(pat)));
1732         /* Pat isn't normalized, but the beauty of it
1733          is that it doesn't matter */
1734         match pat.node {
1735             ast::PatWild => try!(word(&mut self.s, "_")),
1736             ast::PatWildMulti => try!(word(&mut self.s, "..")),
1737             ast::PatIdent(binding_mode, ref path1, sub) => {
1738                 match binding_mode {
1739                     ast::BindByRef(mutbl) => {
1740                         try!(self.word_nbsp("ref"));
1741                         try!(self.print_mutability(mutbl));
1742                     }
1743                     ast::BindByValue(ast::MutImmutable) => {}
1744                     ast::BindByValue(ast::MutMutable) => {
1745                         try!(self.word_nbsp("mut"));
1746                     }
1747                 }
1748                 try!(self.print_ident(path1.node));
1749                 match sub {
1750                     Some(ref p) => {
1751                         try!(word(&mut self.s, "@"));
1752                         try!(self.print_pat(&**p));
1753                     }
1754                     None => ()
1755                 }
1756             }
1757             ast::PatEnum(ref path, ref args_) => {
1758                 try!(self.print_path(path, true));
1759                 match *args_ {
1760                     None => try!(word(&mut self.s, "(..)")),
1761                     Some(ref args) => {
1762                         if !args.is_empty() {
1763                             try!(self.popen());
1764                             try!(self.commasep(Inconsistent, args.as_slice(),
1765                                               |s, p| s.print_pat(&**p)));
1766                             try!(self.pclose());
1767                         }
1768                     }
1769                 }
1770             }
1771             ast::PatStruct(ref path, ref fields, etc) => {
1772                 try!(self.print_path(path, true));
1773                 try!(self.nbsp());
1774                 try!(self.word_space("{"));
1775                 try!(self.commasep_cmnt(
1776                     Consistent, fields.as_slice(),
1777                     |s, f| {
1778                         try!(s.cbox(indent_unit));
1779                         try!(s.print_ident(f.ident));
1780                         try!(s.word_nbsp(":"));
1781                         try!(s.print_pat(&*f.pat));
1782                         s.end()
1783                     },
1784                     |f| f.pat.span));
1785                 if etc {
1786                     if fields.len() != 0u { try!(self.word_space(",")); }
1787                     try!(word(&mut self.s, ".."));
1788                 }
1789                 try!(space(&mut self.s));
1790                 try!(word(&mut self.s, "}"));
1791             }
1792             ast::PatTup(ref elts) => {
1793                 try!(self.popen());
1794                 try!(self.commasep(Inconsistent,
1795                                    elts.as_slice(),
1796                                    |s, p| s.print_pat(&**p)));
1797                 if elts.len() == 1 {
1798                     try!(word(&mut self.s, ","));
1799                 }
1800                 try!(self.pclose());
1801             }
1802             ast::PatBox(ref inner) => {
1803                 try!(word(&mut self.s, "box "));
1804                 try!(self.print_pat(&**inner));
1805             }
1806             ast::PatRegion(ref inner) => {
1807                 try!(word(&mut self.s, "&"));
1808                 try!(self.print_pat(&**inner));
1809             }
1810             ast::PatLit(ref e) => try!(self.print_expr(&**e)),
1811             ast::PatRange(ref begin, ref end) => {
1812                 try!(self.print_expr(&**begin));
1813                 try!(space(&mut self.s));
1814                 try!(word(&mut self.s, ".."));
1815                 try!(self.print_expr(&**end));
1816             }
1817             ast::PatVec(ref before, slice, ref after) => {
1818                 try!(word(&mut self.s, "["));
1819                 try!(self.commasep(Inconsistent,
1820                                    before.as_slice(),
1821                                    |s, p| s.print_pat(&**p)));
1822                 for p in slice.iter() {
1823                     if !before.is_empty() { try!(self.word_space(",")); }
1824                     match **p {
1825                         ast::Pat { node: ast::PatWildMulti, .. } => {
1826                             // this case is handled by print_pat
1827                         }
1828                         _ => try!(word(&mut self.s, "..")),
1829                     }
1830                     try!(self.print_pat(&**p));
1831                     if !after.is_empty() { try!(self.word_space(",")); }
1832                 }
1833                 try!(self.commasep(Inconsistent,
1834                                    after.as_slice(),
1835                                    |s, p| s.print_pat(&**p)));
1836                 try!(word(&mut self.s, "]"));
1837             }
1838             ast::PatMac(ref m) => try!(self.print_mac(m)),
1839         }
1840         self.ann.post(self, NodePat(pat))
1841     }
1842
1843     // Returns whether it printed anything
1844     fn print_explicit_self(&mut self,
1845                            explicit_self: ast::ExplicitSelf_,
1846                            mutbl: ast::Mutability) -> IoResult<bool> {
1847         try!(self.print_mutability(mutbl));
1848         match explicit_self {
1849             ast::SelfStatic => { return Ok(false); }
1850             ast::SelfValue(_) => {
1851                 try!(word(&mut self.s, "self"));
1852             }
1853             ast::SelfUniq(_) => {
1854                 try!(word(&mut self.s, "~self"));
1855             }
1856             ast::SelfRegion(ref lt, m, _) => {
1857                 try!(word(&mut self.s, "&"));
1858                 try!(self.print_opt_lifetime(lt));
1859                 try!(self.print_mutability(m));
1860                 try!(word(&mut self.s, "self"));
1861             }
1862         }
1863         return Ok(true);
1864     }
1865
1866     pub fn print_fn(&mut self,
1867                     decl: &ast::FnDecl,
1868                     fn_style: Option<ast::FnStyle>,
1869                     abi: abi::Abi,
1870                     name: ast::Ident,
1871                     generics: &ast::Generics,
1872                     opt_explicit_self: Option<ast::ExplicitSelf_>,
1873                     vis: ast::Visibility) -> IoResult<()> {
1874         try!(self.head(""));
1875         try!(self.print_fn_header_info(opt_explicit_self, fn_style, abi, vis));
1876         try!(self.nbsp());
1877         try!(self.print_ident(name));
1878         try!(self.print_generics(generics));
1879         self.print_fn_args_and_ret(decl, opt_explicit_self)
1880     }
1881
1882     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
1883                          opt_explicit_self: Option<ast::ExplicitSelf_>)
1884         -> IoResult<()> {
1885         // It is unfortunate to duplicate the commasep logic, but we want the
1886         // self type and the args all in the same box.
1887         try!(self.rbox(0u, Inconsistent));
1888         let mut first = true;
1889         for &explicit_self in opt_explicit_self.iter() {
1890             let m = match explicit_self {
1891                 ast::SelfStatic => ast::MutImmutable,
1892                 _ => match decl.inputs.get(0).pat.node {
1893                     ast::PatIdent(ast::BindByValue(m), _, _) => m,
1894                     _ => ast::MutImmutable
1895                 }
1896             };
1897             first = !try!(self.print_explicit_self(explicit_self, m));
1898         }
1899
1900         // HACK(eddyb) ignore the separately printed self argument.
1901         let args = if first {
1902             decl.inputs.as_slice()
1903         } else {
1904             decl.inputs.slice_from(1)
1905         };
1906
1907         for arg in args.iter() {
1908             if first { first = false; } else { try!(self.word_space(",")); }
1909             try!(self.print_arg(arg));
1910         }
1911
1912         self.end()
1913     }
1914
1915     pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl,
1916                                  opt_explicit_self: Option<ast::ExplicitSelf_>)
1917         -> IoResult<()> {
1918         try!(self.popen());
1919         try!(self.print_fn_args(decl, opt_explicit_self));
1920         if decl.variadic {
1921             try!(word(&mut self.s, ", ..."));
1922         }
1923         try!(self.pclose());
1924
1925         try!(self.maybe_print_comment(decl.output.span.lo));
1926         match decl.output.node {
1927             ast::TyNil => Ok(()),
1928             _ => {
1929                 try!(self.space_if_not_bol());
1930                 try!(self.word_space("->"));
1931                 self.print_type(&*decl.output)
1932             }
1933         }
1934     }
1935
1936     pub fn print_fn_block_args(&mut self,
1937                                decl: &ast::FnDecl) -> IoResult<()> {
1938         try!(word(&mut self.s, "|"));
1939         try!(self.print_fn_args(decl, None));
1940         try!(word(&mut self.s, "|"));
1941
1942         match decl.output.node {
1943             ast::TyInfer => {}
1944             _ => {
1945                 try!(self.space_if_not_bol());
1946                 try!(self.word_space("->"));
1947                 try!(self.print_type(&*decl.output));
1948             }
1949         }
1950
1951         self.maybe_print_comment(decl.output.span.lo)
1952     }
1953
1954     pub fn print_proc_args(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
1955         try!(word(&mut self.s, "proc"));
1956         try!(word(&mut self.s, "("));
1957         try!(self.print_fn_args(decl, None));
1958         try!(word(&mut self.s, ")"));
1959
1960         match decl.output.node {
1961             ast::TyInfer => {}
1962             _ => {
1963                 try!(self.space_if_not_bol());
1964                 try!(self.word_space("->"));
1965                 try!(self.print_type(&*decl.output));
1966             }
1967         }
1968
1969         self.maybe_print_comment(decl.output.span.lo)
1970     }
1971
1972     pub fn print_bounds(&mut self,
1973                         region: &Option<ast::Lifetime>,
1974                         bounds: &OwnedSlice<ast::TyParamBound>,
1975                         print_colon_anyway: bool,
1976                         print_plus_before_bounds: bool)
1977                         -> IoResult<()> {
1978         let separator = if print_plus_before_bounds {
1979             "+"
1980         } else {
1981             ":"
1982         };
1983         if !bounds.is_empty() || region.is_some() {
1984             try!(word(&mut self.s, separator));
1985             let mut first = true;
1986             match *region {
1987                 Some(ref lt) => {
1988                     let token = token::get_name(lt.name);
1989                     if token.get() != "'static" {
1990                         try!(self.nbsp());
1991                         first = false;
1992                         try!(self.print_lifetime(lt));
1993                     }
1994                 }
1995                 None => {}
1996             }
1997             for bound in bounds.iter() {
1998                 try!(self.nbsp());
1999                 if first {
2000                     first = false;
2001                 } else {
2002                     try!(self.word_space("+"));
2003                 }
2004
2005                 try!(match *bound {
2006                     TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
2007                     StaticRegionTyParamBound => word(&mut self.s, "'static"),
2008                     UnboxedFnTyParamBound(ref unboxed_function_type) => {
2009                         self.print_ty_fn(None,
2010                                          None,
2011                                          &None,
2012                                          ast::NormalFn,
2013                                          ast::Many,
2014                                          &*unboxed_function_type.decl,
2015                                          None,
2016                                          &None,
2017                                          None,
2018                                          None,
2019                                          true)
2020                     }
2021                     OtherRegionTyParamBound(_) => Ok(())
2022                 })
2023             }
2024             Ok(())
2025         } else if print_colon_anyway {
2026             word(&mut self.s, separator)
2027         } else {
2028             Ok(())
2029         }
2030     }
2031
2032     pub fn print_lifetime(&mut self,
2033                           lifetime: &ast::Lifetime) -> IoResult<()> {
2034         self.print_name(lifetime.name)
2035     }
2036
2037     pub fn print_generics(&mut self,
2038                           generics: &ast::Generics) -> IoResult<()> {
2039         let total = generics.lifetimes.len() + generics.ty_params.len();
2040         if total > 0 {
2041             try!(word(&mut self.s, "<"));
2042
2043             let mut ints = Vec::new();
2044             for i in range(0u, total) {
2045                 ints.push(i);
2046             }
2047
2048             try!(self.commasep(
2049                 Inconsistent, ints.as_slice(),
2050                 |s, &idx| {
2051                     if idx < generics.lifetimes.len() {
2052                         let lifetime = generics.lifetimes.get(idx);
2053                         s.print_lifetime(lifetime)
2054                     } else {
2055                         let idx = idx - generics.lifetimes.len();
2056                         let param = generics.ty_params.get(idx);
2057                         match param.unbound {
2058                             Some(TraitTyParamBound(ref tref)) => {
2059                                 try!(s.print_trait_ref(tref));
2060                                 try!(s.word_space("?"));
2061                             }
2062                             _ => {}
2063                         }
2064                         try!(s.print_ident(param.ident));
2065                         try!(s.print_bounds(&None,
2066                                             &param.bounds,
2067                                             false,
2068                                             false));
2069                         match param.default {
2070                             Some(ref default) => {
2071                                 try!(space(&mut s.s));
2072                                 try!(s.word_space("="));
2073                                 s.print_type(&**default)
2074                             }
2075                             _ => Ok(())
2076                         }
2077                     }
2078                 }));
2079             word(&mut self.s, ">")
2080         } else {
2081             Ok(())
2082         }
2083     }
2084
2085     pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
2086         try!(self.ibox(indent_unit));
2087         match item.node {
2088             ast::MetaWord(ref name) => {
2089                 try!(word(&mut self.s, name.get()));
2090             }
2091             ast::MetaNameValue(ref name, ref value) => {
2092                 try!(self.word_space(name.get()));
2093                 try!(self.word_space("="));
2094                 try!(self.print_literal(value));
2095             }
2096             ast::MetaList(ref name, ref items) => {
2097                 try!(word(&mut self.s, name.get()));
2098                 try!(self.popen());
2099                 try!(self.commasep(Consistent,
2100                                    items.as_slice(),
2101                                    |s, i| s.print_meta_item(&**i)));
2102                 try!(self.pclose());
2103             }
2104         }
2105         self.end()
2106     }
2107
2108     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> IoResult<()> {
2109         match vp.node {
2110             ast::ViewPathSimple(ident, ref path, _) => {
2111                 // FIXME(#6993) can't compare identifiers directly here
2112                 if path.segments.last().unwrap().identifier.name != ident.name {
2113                     try!(self.print_ident(ident));
2114                     try!(space(&mut self.s));
2115                     try!(self.word_space("="));
2116                 }
2117                 self.print_path(path, false)
2118             }
2119
2120             ast::ViewPathGlob(ref path, _) => {
2121                 try!(self.print_path(path, false));
2122                 word(&mut self.s, "::*")
2123             }
2124
2125             ast::ViewPathList(ref path, ref idents, _) => {
2126                 if path.segments.is_empty() {
2127                     try!(word(&mut self.s, "{"));
2128                 } else {
2129                     try!(self.print_path(path, false));
2130                     try!(word(&mut self.s, "::{"));
2131                 }
2132                 try!(self.commasep(Inconsistent, idents.as_slice(), |s, w| {
2133                     s.print_ident(w.node.name)
2134                 }));
2135                 word(&mut self.s, "}")
2136             }
2137         }
2138     }
2139
2140     pub fn print_view_item(&mut self, item: &ast::ViewItem) -> IoResult<()> {
2141         try!(self.hardbreak_if_not_bol());
2142         try!(self.maybe_print_comment(item.span.lo));
2143         try!(self.print_outer_attributes(item.attrs.as_slice()));
2144         try!(self.print_visibility(item.vis));
2145         match item.node {
2146             ast::ViewItemExternCrate(id, ref optional_path, _) => {
2147                 try!(self.head("extern crate"));
2148                 try!(self.print_ident(id));
2149                 for &(ref p, style) in optional_path.iter() {
2150                     try!(space(&mut self.s));
2151                     try!(word(&mut self.s, "="));
2152                     try!(space(&mut self.s));
2153                     try!(self.print_string(p.get(), style));
2154                 }
2155             }
2156
2157             ast::ViewItemUse(ref vp) => {
2158                 try!(self.head("use"));
2159                 try!(self.print_view_path(&**vp));
2160             }
2161         }
2162         try!(word(&mut self.s, ";"));
2163         try!(self.end()); // end inner head-block
2164         self.end() // end outer head-block
2165     }
2166
2167     pub fn print_mutability(&mut self,
2168                             mutbl: ast::Mutability) -> IoResult<()> {
2169         match mutbl {
2170             ast::MutMutable => self.word_nbsp("mut"),
2171             ast::MutImmutable => Ok(()),
2172         }
2173     }
2174
2175     pub fn print_mt(&mut self, mt: &ast::MutTy) -> IoResult<()> {
2176         try!(self.print_mutability(mt.mutbl));
2177         self.print_type(&*mt.ty)
2178     }
2179
2180     pub fn print_arg(&mut self, input: &ast::Arg) -> IoResult<()> {
2181         try!(self.ibox(indent_unit));
2182         match input.ty.node {
2183             ast::TyInfer => try!(self.print_pat(&*input.pat)),
2184             _ => {
2185                 match input.pat.node {
2186                     ast::PatIdent(_, ref path1, _) if
2187                         path1.node.name ==
2188                             parse::token::special_idents::invalid.name => {
2189                         // Do nothing.
2190                     }
2191                     _ => {
2192                         try!(self.print_pat(&*input.pat));
2193                         try!(word(&mut self.s, ":"));
2194                         try!(space(&mut self.s));
2195                     }
2196                 }
2197                 try!(self.print_type(&*input.ty));
2198             }
2199         }
2200         self.end()
2201     }
2202
2203     pub fn print_ty_fn(&mut self,
2204                        opt_abi: Option<abi::Abi>,
2205                        opt_sigil: Option<char>,
2206                        opt_region: &Option<ast::Lifetime>,
2207                        fn_style: ast::FnStyle,
2208                        onceness: ast::Onceness,
2209                        decl: &ast::FnDecl,
2210                        id: Option<ast::Ident>,
2211                        opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
2212                        generics: Option<&ast::Generics>,
2213                        opt_explicit_self: Option<ast::ExplicitSelf_>,
2214                        is_unboxed: bool)
2215                        -> IoResult<()> {
2216         try!(self.ibox(indent_unit));
2217
2218         // Duplicates the logic in `print_fn_header_info()`.  This is because that
2219         // function prints the sigil in the wrong place.  That should be fixed.
2220         if opt_sigil == Some('~') && onceness == ast::Once {
2221             try!(word(&mut self.s, "proc"));
2222         } else if opt_sigil == Some('&') {
2223             try!(self.print_fn_style(fn_style));
2224             try!(self.print_extern_opt_abi(opt_abi));
2225             try!(self.print_onceness(onceness));
2226         } else {
2227             assert!(opt_sigil.is_none());
2228             try!(self.print_fn_style(fn_style));
2229             try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
2230             try!(self.print_onceness(onceness));
2231             if !is_unboxed {
2232                 try!(word(&mut self.s, "fn"));
2233             }
2234         }
2235
2236         match id {
2237             Some(id) => {
2238                 try!(word(&mut self.s, " "));
2239                 try!(self.print_ident(id));
2240             }
2241             _ => ()
2242         }
2243
2244         match generics { Some(g) => try!(self.print_generics(g)), _ => () }
2245         try!(zerobreak(&mut self.s));
2246
2247         if is_unboxed || opt_sigil == Some('&') {
2248             try!(word(&mut self.s, "|"));
2249         } else {
2250             try!(self.popen());
2251         }
2252
2253         if is_unboxed {
2254             try!(word(&mut self.s, "&mut"));
2255             try!(self.word_space(":"));
2256         }
2257
2258         try!(self.print_fn_args(decl, opt_explicit_self));
2259
2260         if is_unboxed || opt_sigil == Some('&') {
2261             try!(word(&mut self.s, "|"));
2262         } else {
2263             if decl.variadic {
2264                 try!(word(&mut self.s, ", ..."));
2265             }
2266             try!(self.pclose());
2267         }
2268
2269         opt_bounds.as_ref().map(|bounds| {
2270             self.print_bounds(opt_region, bounds, true, false)
2271         });
2272
2273         try!(self.maybe_print_comment(decl.output.span.lo));
2274
2275         match decl.output.node {
2276             ast::TyNil => {}
2277             _ => {
2278                 try!(self.space_if_not_bol());
2279                 try!(self.ibox(indent_unit));
2280                 try!(self.word_space("->"));
2281                 if decl.cf == ast::NoReturn {
2282                     try!(self.word_nbsp("!"));
2283                 } else {
2284                     try!(self.print_type(&*decl.output));
2285                 }
2286                 try!(self.end());
2287             }
2288         }
2289
2290         self.end()
2291     }
2292
2293     pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
2294                                         next_pos: Option<BytePos>)
2295         -> IoResult<()> {
2296         let cm = match self.cm {
2297             Some(cm) => cm,
2298             _ => return Ok(())
2299         };
2300         match self.next_comment() {
2301             Some(ref cmnt) => {
2302                 if (*cmnt).style != comments::Trailing { return Ok(()) }
2303                 let span_line = cm.lookup_char_pos(span.hi);
2304                 let comment_line = cm.lookup_char_pos((*cmnt).pos);
2305                 let mut next = (*cmnt).pos + BytePos(1);
2306                 match next_pos { None => (), Some(p) => next = p }
2307                 if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
2308                     span_line.line == comment_line.line {
2309                         try!(self.print_comment(cmnt));
2310                         self.cur_cmnt_and_lit.cur_cmnt += 1u;
2311                     }
2312             }
2313             _ => ()
2314         }
2315         Ok(())
2316     }
2317
2318     pub fn print_remaining_comments(&mut self) -> IoResult<()> {
2319         // If there aren't any remaining comments, then we need to manually
2320         // make sure there is a line break at the end.
2321         if self.next_comment().is_none() {
2322             try!(hardbreak(&mut self.s));
2323         }
2324         loop {
2325             match self.next_comment() {
2326                 Some(ref cmnt) => {
2327                     try!(self.print_comment(cmnt));
2328                     self.cur_cmnt_and_lit.cur_cmnt += 1u;
2329                 }
2330                 _ => break
2331             }
2332         }
2333         Ok(())
2334     }
2335
2336     pub fn print_literal(&mut self, lit: &ast::Lit) -> IoResult<()> {
2337         try!(self.maybe_print_comment(lit.span.lo));
2338         match self.next_lit(lit.span.lo) {
2339             Some(ref ltrl) => {
2340                 return word(&mut self.s, (*ltrl).lit.as_slice());
2341             }
2342             _ => ()
2343         }
2344         match lit.node {
2345             ast::LitStr(ref st, style) => self.print_string(st.get(), style),
2346             ast::LitByte(byte) => {
2347                 let mut res = String::from_str("b'");
2348                 (byte as char).escape_default(|c| res.push_char(c));
2349                 res.push_char('\'');
2350                 word(&mut self.s, res.as_slice())
2351             }
2352             ast::LitChar(ch) => {
2353                 let mut res = String::from_str("'");
2354                 ch.escape_default(|c| res.push_char(c));
2355                 res.push_char('\'');
2356                 word(&mut self.s, res.as_slice())
2357             }
2358             ast::LitInt(i, t) => {
2359                 word(&mut self.s,
2360                      ast_util::int_ty_to_string(t, Some(i)).as_slice())
2361             }
2362             ast::LitUint(u, t) => {
2363                 word(&mut self.s,
2364                      ast_util::uint_ty_to_string(t, Some(u)).as_slice())
2365             }
2366             ast::LitIntUnsuffixed(i) => {
2367                 word(&mut self.s, format!("{}", i).as_slice())
2368             }
2369             ast::LitFloat(ref f, t) => {
2370                 word(&mut self.s,
2371                      format!(
2372                          "{}{}",
2373                          f.get(),
2374                          ast_util::float_ty_to_string(t).as_slice()).as_slice())
2375             }
2376             ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, f.get()),
2377             ast::LitNil => word(&mut self.s, "()"),
2378             ast::LitBool(val) => {
2379                 if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
2380             }
2381             ast::LitBinary(ref v) => {
2382                 let escaped: String = v.iter().map(|&b| b as char).collect();
2383                 word(&mut self.s, format!("b\"{}\"", escaped.escape_default()).as_slice())
2384             }
2385         }
2386     }
2387
2388     pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
2389         match self.literals {
2390             Some(ref lits) => {
2391                 while self.cur_cmnt_and_lit.cur_lit < lits.len() {
2392                     let ltrl = (*(*lits).get(self.cur_cmnt_and_lit.cur_lit)).clone();
2393                     if ltrl.pos > pos { return None; }
2394                     self.cur_cmnt_and_lit.cur_lit += 1u;
2395                     if ltrl.pos == pos { return Some(ltrl); }
2396                 }
2397                 None
2398             }
2399             _ => None
2400         }
2401     }
2402
2403     pub fn maybe_print_comment(&mut self, pos: BytePos) -> IoResult<()> {
2404         loop {
2405             match self.next_comment() {
2406                 Some(ref cmnt) => {
2407                     if (*cmnt).pos < pos {
2408                         try!(self.print_comment(cmnt));
2409                         self.cur_cmnt_and_lit.cur_cmnt += 1u;
2410                     } else { break; }
2411                 }
2412                 _ => break
2413             }
2414         }
2415         Ok(())
2416     }
2417
2418     pub fn print_comment(&mut self,
2419                          cmnt: &comments::Comment) -> IoResult<()> {
2420         match cmnt.style {
2421             comments::Mixed => {
2422                 assert_eq!(cmnt.lines.len(), 1u);
2423                 try!(zerobreak(&mut self.s));
2424                 try!(word(&mut self.s, cmnt.lines.get(0).as_slice()));
2425                 zerobreak(&mut self.s)
2426             }
2427             comments::Isolated => {
2428                 try!(self.hardbreak_if_not_bol());
2429                 for line in cmnt.lines.iter() {
2430                     // Don't print empty lines because they will end up as trailing
2431                     // whitespace
2432                     if !line.is_empty() {
2433                         try!(word(&mut self.s, line.as_slice()));
2434                     }
2435                     try!(hardbreak(&mut self.s));
2436                 }
2437                 Ok(())
2438             }
2439             comments::Trailing => {
2440                 try!(word(&mut self.s, " "));
2441                 if cmnt.lines.len() == 1u {
2442                     try!(word(&mut self.s, cmnt.lines.get(0).as_slice()));
2443                     hardbreak(&mut self.s)
2444                 } else {
2445                     try!(self.ibox(0u));
2446                     for line in cmnt.lines.iter() {
2447                         if !line.is_empty() {
2448                             try!(word(&mut self.s, line.as_slice()));
2449                         }
2450                         try!(hardbreak(&mut self.s));
2451                     }
2452                     self.end()
2453                 }
2454             }
2455             comments::BlankLine => {
2456                 // We need to do at least one, possibly two hardbreaks.
2457                 let is_semi = match self.s.last_token() {
2458                     pp::String(s, _) => ";" == s.as_slice(),
2459                     _ => false
2460                 };
2461                 if is_semi || self.is_begin() || self.is_end() {
2462                     try!(hardbreak(&mut self.s));
2463                 }
2464                 hardbreak(&mut self.s)
2465             }
2466         }
2467     }
2468
2469     pub fn print_string(&mut self, st: &str,
2470                         style: ast::StrStyle) -> IoResult<()> {
2471         let st = match style {
2472             ast::CookedStr => {
2473                 (format!("\"{}\"", st.escape_default()))
2474             }
2475             ast::RawStr(n) => {
2476                 (format!("r{delim}\"{string}\"{delim}",
2477                          delim="#".repeat(n),
2478                          string=st))
2479             }
2480         };
2481         word(&mut self.s, st.as_slice())
2482     }
2483
2484     pub fn next_comment(&mut self) -> Option<comments::Comment> {
2485         match self.comments {
2486             Some(ref cmnts) => {
2487                 if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
2488                     Some((*cmnts.get(self.cur_cmnt_and_lit.cur_cmnt)).clone())
2489                 } else {
2490                     None
2491                 }
2492             }
2493             _ => None
2494         }
2495     }
2496
2497     pub fn print_opt_fn_style(&mut self,
2498                             opt_fn_style: Option<ast::FnStyle>) -> IoResult<()> {
2499         match opt_fn_style {
2500             Some(fn_style) => self.print_fn_style(fn_style),
2501             None => Ok(())
2502         }
2503     }
2504
2505     pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
2506                                                   opt_abi: Option<abi::Abi>)
2507         -> IoResult<()> {
2508         match opt_abi {
2509             Some(abi::Rust) => Ok(()),
2510             Some(abi) => {
2511                 try!(self.word_nbsp("extern"));
2512                 self.word_nbsp(abi.to_string().as_slice())
2513             }
2514             None => Ok(())
2515         }
2516     }
2517
2518     pub fn print_extern_opt_abi(&mut self,
2519                                 opt_abi: Option<abi::Abi>) -> IoResult<()> {
2520         match opt_abi {
2521             Some(abi) => {
2522                 try!(self.word_nbsp("extern"));
2523                 self.word_nbsp(abi.to_string().as_slice())
2524             }
2525             None => Ok(())
2526         }
2527     }
2528
2529     pub fn print_fn_header_info(&mut self,
2530                                 _opt_explicit_self: Option<ast::ExplicitSelf_>,
2531                                 opt_fn_style: Option<ast::FnStyle>,
2532                                 abi: abi::Abi,
2533                                 vis: ast::Visibility) -> IoResult<()> {
2534         try!(word(&mut self.s, visibility_qualified(vis, "").as_slice()));
2535         try!(self.print_opt_fn_style(opt_fn_style));
2536
2537         if abi != abi::Rust {
2538             try!(self.word_nbsp("extern"));
2539             try!(self.word_nbsp(abi.to_string().as_slice()));
2540         }
2541
2542         word(&mut self.s, "fn")
2543     }
2544
2545     pub fn print_fn_style(&mut self, s: ast::FnStyle) -> IoResult<()> {
2546         match s {
2547             ast::NormalFn => Ok(()),
2548             ast::UnsafeFn => self.word_nbsp("unsafe"),
2549         }
2550     }
2551
2552     pub fn print_onceness(&mut self, o: ast::Onceness) -> IoResult<()> {
2553         match o {
2554             ast::Once => self.word_nbsp("once"),
2555             ast::Many => Ok(())
2556         }
2557     }
2558 }
2559
2560 #[cfg(test)]
2561 mod test {
2562     use super::*;
2563
2564     use ast;
2565     use ast_util;
2566     use codemap;
2567     use parse::token;
2568
2569     #[test]
2570     fn test_fun_to_string() {
2571         let abba_ident = token::str_to_ident("abba");
2572
2573         let decl = ast::FnDecl {
2574             inputs: Vec::new(),
2575             output: ast::P(ast::Ty {id: 0,
2576                                     node: ast::TyNil,
2577                                     span: codemap::DUMMY_SP}),
2578             cf: ast::Return,
2579             variadic: false
2580         };
2581         let generics = ast_util::empty_generics();
2582         assert_eq!(&fun_to_string(&decl, ast::NormalFn, abba_ident,
2583                                None, &generics),
2584                    &"fn abba()".to_string());
2585     }
2586
2587     #[test]
2588     fn test_variant_to_string() {
2589         let ident = token::str_to_ident("principal_skinner");
2590
2591         let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ {
2592             name: ident,
2593             attrs: Vec::new(),
2594             // making this up as I go.... ?
2595             kind: ast::TupleVariantKind(Vec::new()),
2596             id: 0,
2597             disr_expr: None,
2598             vis: ast::Public,
2599         });
2600
2601         let varstr = variant_to_string(&var);
2602         assert_eq!(&varstr,&"pub principal_skinner".to_string());
2603     }
2604 }