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