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