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