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