]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/print/pprust.rs
Auto merge of #22517 - brson:relnotes, 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 bounds: Vec<_> = bounds.iter().map(|b| b.clone()).collect();
987                 let mut real_bounds = Vec::with_capacity(bounds.len());
988                 for b in bounds {
989                     if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = b {
990                         try!(space(&mut self.s));
991                         try!(self.word_space("for ?"));
992                         try!(self.print_trait_ref(&ptr.trait_ref));
993                     } else {
994                         real_bounds.push(b);
995                     }
996                 }
997                 try!(self.print_bounds(":", &real_bounds[]));
998                 try!(self.print_where_clause(generics));
999                 try!(word(&mut self.s, " "));
1000                 try!(self.bopen());
1001                 for meth in methods {
1002                     try!(self.print_trait_method(meth));
1003                 }
1004                 try!(self.bclose(item.span));
1005             }
1006             // I think it's reasonable to hide the context here:
1007             ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
1008                                             ..}) => {
1009                 try!(self.print_visibility(item.vis));
1010                 try!(self.print_path(pth, false));
1011                 try!(word(&mut self.s, "! "));
1012                 try!(self.print_ident(item.ident));
1013                 try!(self.cbox(indent_unit));
1014                 try!(self.popen());
1015                 try!(self.print_tts(&tts[]));
1016                 try!(self.pclose());
1017                 try!(word(&mut self.s, ";"));
1018                 try!(self.end());
1019             }
1020         }
1021         self.ann.post(self, NodeItem(item))
1022     }
1023
1024     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> {
1025         self.print_path(&t.path, false)
1026     }
1027
1028     fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> IoResult<()> {
1029         if !lifetimes.is_empty() {
1030             try!(word(&mut self.s, "for<"));
1031             let mut comma = false;
1032             for lifetime_def in lifetimes {
1033                 if comma {
1034                     try!(self.word_space(","))
1035                 }
1036                 try!(self.print_lifetime_def(lifetime_def));
1037                 comma = true;
1038             }
1039             try!(word(&mut self.s, ">"));
1040         }
1041         Ok(())
1042     }
1043
1044     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> {
1045         try!(self.print_formal_lifetime_list(&t.bound_lifetimes));
1046         self.print_trait_ref(&t.trait_ref)
1047     }
1048
1049     pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
1050                           generics: &ast::Generics, ident: ast::Ident,
1051                           span: codemap::Span,
1052                           visibility: ast::Visibility) -> IoResult<()> {
1053         try!(self.head(&visibility_qualified(visibility, "enum")[]));
1054         try!(self.print_ident(ident));
1055         try!(self.print_generics(generics));
1056         try!(self.print_where_clause(generics));
1057         try!(space(&mut self.s));
1058         self.print_variants(&enum_definition.variants[], span)
1059     }
1060
1061     pub fn print_variants(&mut self,
1062                           variants: &[P<ast::Variant>],
1063                           span: codemap::Span) -> IoResult<()> {
1064         try!(self.bopen());
1065         for v in variants {
1066             try!(self.space_if_not_bol());
1067             try!(self.maybe_print_comment(v.span.lo));
1068             try!(self.print_outer_attributes(&v.node.attrs[]));
1069             try!(self.ibox(indent_unit));
1070             try!(self.print_variant(&**v));
1071             try!(word(&mut self.s, ","));
1072             try!(self.end());
1073             try!(self.maybe_print_trailing_comment(v.span, None));
1074         }
1075         self.bclose(span)
1076     }
1077
1078     pub fn print_visibility(&mut self, vis: ast::Visibility) -> IoResult<()> {
1079         match vis {
1080             ast::Public => self.word_nbsp("pub"),
1081             ast::Inherited => Ok(())
1082         }
1083     }
1084
1085     pub fn print_struct(&mut self,
1086                         struct_def: &ast::StructDef,
1087                         generics: &ast::Generics,
1088                         ident: ast::Ident,
1089                         span: codemap::Span) -> IoResult<()> {
1090         try!(self.print_ident(ident));
1091         try!(self.print_generics(generics));
1092         if ast_util::struct_def_is_tuple_like(struct_def) {
1093             if !struct_def.fields.is_empty() {
1094                 try!(self.popen());
1095                 try!(self.commasep(
1096                     Inconsistent, &struct_def.fields[],
1097                     |s, field| {
1098                         match field.node.kind {
1099                             ast::NamedField(..) => panic!("unexpected named field"),
1100                             ast::UnnamedField(vis) => {
1101                                 try!(s.print_visibility(vis));
1102                                 try!(s.maybe_print_comment(field.span.lo));
1103                                 s.print_type(&*field.node.ty)
1104                             }
1105                         }
1106                     }
1107                 ));
1108                 try!(self.pclose());
1109             }
1110             try!(self.print_where_clause(generics));
1111             try!(word(&mut self.s, ";"));
1112             try!(self.end());
1113             self.end() // close the outer-box
1114         } else {
1115             try!(self.print_where_clause(generics));
1116             try!(self.nbsp());
1117             try!(self.bopen());
1118             try!(self.hardbreak_if_not_bol());
1119
1120             for field in &struct_def.fields {
1121                 match field.node.kind {
1122                     ast::UnnamedField(..) => panic!("unexpected unnamed field"),
1123                     ast::NamedField(ident, visibility) => {
1124                         try!(self.hardbreak_if_not_bol());
1125                         try!(self.maybe_print_comment(field.span.lo));
1126                         try!(self.print_outer_attributes(&field.node.attrs[]));
1127                         try!(self.print_visibility(visibility));
1128                         try!(self.print_ident(ident));
1129                         try!(self.word_nbsp(":"));
1130                         try!(self.print_type(&*field.node.ty));
1131                         try!(word(&mut self.s, ","));
1132                     }
1133                 }
1134             }
1135
1136             self.bclose(span)
1137         }
1138     }
1139
1140     /// This doesn't deserve to be called "pretty" printing, but it should be
1141     /// meaning-preserving. A quick hack that might help would be to look at the
1142     /// spans embedded in the TTs to decide where to put spaces and newlines.
1143     /// But it'd be better to parse these according to the grammar of the
1144     /// appropriate macro, transcribe back into the grammar we just parsed from,
1145     /// and then pretty-print the resulting AST nodes (so, e.g., we print
1146     /// expression arguments as expressions). It can be done! I think.
1147     pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
1148         match *tt {
1149             ast::TtToken(_, ref tk) => {
1150                 try!(word(&mut self.s, &token_to_string(tk)[]));
1151                 match *tk {
1152                     parse::token::DocComment(..) => {
1153                         hardbreak(&mut self.s)
1154                     }
1155                     _ => Ok(())
1156                 }
1157             }
1158             ast::TtDelimited(_, ref delimed) => {
1159                 try!(word(&mut self.s, &token_to_string(&delimed.open_token())[]));
1160                 try!(space(&mut self.s));
1161                 try!(self.print_tts(&delimed.tts[]));
1162                 try!(space(&mut self.s));
1163                 word(&mut self.s, &token_to_string(&delimed.close_token())[])
1164             },
1165             ast::TtSequence(_, ref seq) => {
1166                 try!(word(&mut self.s, "$("));
1167                 for tt_elt in &seq.tts {
1168                     try!(self.print_tt(tt_elt));
1169                 }
1170                 try!(word(&mut self.s, ")"));
1171                 match seq.separator {
1172                     Some(ref tk) => {
1173                         try!(word(&mut self.s, &token_to_string(tk)[]));
1174                     }
1175                     None => {},
1176                 }
1177                 match seq.op {
1178                     ast::ZeroOrMore => word(&mut self.s, "*"),
1179                     ast::OneOrMore => word(&mut self.s, "+"),
1180                 }
1181             }
1182         }
1183     }
1184
1185     pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> IoResult<()> {
1186         try!(self.ibox(0));
1187         let mut suppress_space = false;
1188         for (i, tt) in tts.iter().enumerate() {
1189             if i != 0 && !suppress_space {
1190                 try!(space(&mut self.s));
1191             }
1192             try!(self.print_tt(tt));
1193             // There should be no space between the module name and the following `::` in paths,
1194             // otherwise imported macros get re-parsed from crate metadata incorrectly (#20701)
1195             suppress_space = match tt {
1196                 &ast::TtToken(_, token::Ident(_, token::ModName)) |
1197                 &ast::TtToken(_, token::MatchNt(_, _, _, token::ModName)) |
1198                 &ast::TtToken(_, token::SubstNt(_, token::ModName)) => true,
1199                 _ => false
1200             }
1201         }
1202         self.end()
1203     }
1204
1205     pub fn print_variant(&mut self, v: &ast::Variant) -> IoResult<()> {
1206         try!(self.print_visibility(v.node.vis));
1207         match v.node.kind {
1208             ast::TupleVariantKind(ref args) => {
1209                 try!(self.print_ident(v.node.name));
1210                 if !args.is_empty() {
1211                     try!(self.popen());
1212                     try!(self.commasep(Consistent,
1213                                        &args[],
1214                                        |s, arg| s.print_type(&*arg.ty)));
1215                     try!(self.pclose());
1216                 }
1217             }
1218             ast::StructVariantKind(ref struct_def) => {
1219                 try!(self.head(""));
1220                 let generics = ast_util::empty_generics();
1221                 try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
1222             }
1223         }
1224         match v.node.disr_expr {
1225             Some(ref d) => {
1226                 try!(space(&mut self.s));
1227                 try!(self.word_space("="));
1228                 self.print_expr(&**d)
1229             }
1230             _ => Ok(())
1231         }
1232     }
1233
1234     pub fn print_ty_method(&mut self, m: &ast::TypeMethod) -> IoResult<()> {
1235         try!(self.hardbreak_if_not_bol());
1236         try!(self.maybe_print_comment(m.span.lo));
1237         try!(self.print_outer_attributes(&m.attrs[]));
1238         try!(self.print_ty_fn(m.abi,
1239                               m.unsafety,
1240                               &*m.decl,
1241                               Some(m.ident),
1242                               &m.generics,
1243                               Some(&m.explicit_self.node)));
1244         word(&mut self.s, ";")
1245     }
1246
1247     pub fn print_trait_method(&mut self,
1248                               m: &ast::TraitItem) -> IoResult<()> {
1249         match *m {
1250             RequiredMethod(ref ty_m) => self.print_ty_method(ty_m),
1251             ProvidedMethod(ref m) => self.print_method(&**m),
1252             TypeTraitItem(ref t) => self.print_associated_type(&**t),
1253         }
1254     }
1255
1256     pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> IoResult<()> {
1257         match *ii {
1258             MethodImplItem(ref m) => self.print_method(&**m),
1259             TypeImplItem(ref td) => self.print_typedef(&**td),
1260         }
1261     }
1262
1263     pub fn print_method(&mut self, meth: &ast::Method) -> IoResult<()> {
1264         try!(self.hardbreak_if_not_bol());
1265         try!(self.maybe_print_comment(meth.span.lo));
1266         try!(self.print_outer_attributes(&meth.attrs[]));
1267         match meth.node {
1268             ast::MethDecl(ident,
1269                           ref generics,
1270                           abi,
1271                           ref explicit_self,
1272                           unsafety,
1273                           ref decl,
1274                           ref body,
1275                           vis) => {
1276                 try!(self.print_fn(&**decl,
1277                                    Some(unsafety),
1278                                    abi,
1279                                    ident,
1280                                    generics,
1281                                    Some(&explicit_self.node),
1282                                    vis));
1283                 try!(word(&mut self.s, " "));
1284                 self.print_block_with_attrs(&**body, &meth.attrs[])
1285             },
1286             ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
1287                                             ..}) => {
1288                 // code copied from ItemMac:
1289                 try!(self.print_path(pth, false));
1290                 try!(word(&mut self.s, "! "));
1291                 try!(self.cbox(indent_unit));
1292                 try!(self.popen());
1293                 try!(self.print_tts(&tts[]));
1294                 try!(self.pclose());
1295                 try!(word(&mut self.s, ";"));
1296                 self.end()
1297             }
1298         }
1299     }
1300
1301     pub fn print_outer_attributes(&mut self,
1302                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1303         let mut count = 0;
1304         for attr in attrs {
1305             match attr.node.style {
1306                 ast::AttrOuter => {
1307                     try!(self.print_attribute(attr));
1308                     count += 1;
1309                 }
1310                 _ => {/* fallthrough */ }
1311             }
1312         }
1313         if count > 0 {
1314             try!(self.hardbreak_if_not_bol());
1315         }
1316         Ok(())
1317     }
1318
1319     pub fn print_inner_attributes(&mut self,
1320                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1321         let mut count = 0;
1322         for attr in attrs {
1323             match attr.node.style {
1324                 ast::AttrInner => {
1325                     try!(self.print_attribute(attr));
1326                     count += 1;
1327                 }
1328                 _ => {/* fallthrough */ }
1329             }
1330         }
1331         if count > 0 {
1332             try!(self.hardbreak_if_not_bol());
1333         }
1334         Ok(())
1335     }
1336
1337     pub fn print_attribute(&mut self, attr: &ast::Attribute) -> IoResult<()> {
1338         try!(self.hardbreak_if_not_bol());
1339         try!(self.maybe_print_comment(attr.span.lo));
1340         if attr.node.is_sugared_doc {
1341             word(&mut self.s, &attr.value_str().unwrap())
1342         } else {
1343             match attr.node.style {
1344                 ast::AttrInner => try!(word(&mut self.s, "#![")),
1345                 ast::AttrOuter => try!(word(&mut self.s, "#[")),
1346             }
1347             try!(self.print_meta_item(&*attr.meta()));
1348             word(&mut self.s, "]")
1349         }
1350     }
1351
1352
1353     pub fn print_stmt(&mut self, st: &ast::Stmt) -> IoResult<()> {
1354         try!(self.maybe_print_comment(st.span.lo));
1355         match st.node {
1356             ast::StmtDecl(ref decl, _) => {
1357                 try!(self.print_decl(&**decl));
1358             }
1359             ast::StmtExpr(ref expr, _) => {
1360                 try!(self.space_if_not_bol());
1361                 try!(self.print_expr(&**expr));
1362             }
1363             ast::StmtSemi(ref expr, _) => {
1364                 try!(self.space_if_not_bol());
1365                 try!(self.print_expr(&**expr));
1366                 try!(word(&mut self.s, ";"));
1367             }
1368             ast::StmtMac(ref mac, style) => {
1369                 try!(self.space_if_not_bol());
1370                 let delim = match style {
1371                     ast::MacStmtWithBraces => token::Brace,
1372                     _ => token::Paren
1373                 };
1374                 try!(self.print_mac(&**mac, delim));
1375                 match style {
1376                     ast::MacStmtWithBraces => {}
1377                     _ => try!(word(&mut self.s, ";")),
1378                 }
1379             }
1380         }
1381         if parse::classify::stmt_ends_with_semi(&st.node) {
1382             try!(word(&mut self.s, ";"));
1383         }
1384         self.maybe_print_trailing_comment(st.span, None)
1385     }
1386
1387     pub fn print_block(&mut self, blk: &ast::Block) -> IoResult<()> {
1388         self.print_block_with_attrs(blk, &[])
1389     }
1390
1391     pub fn print_block_unclosed(&mut self, blk: &ast::Block) -> IoResult<()> {
1392         self.print_block_unclosed_indent(blk, indent_unit)
1393     }
1394
1395     pub fn print_block_unclosed_indent(&mut self, blk: &ast::Block,
1396                                        indented: usize) -> IoResult<()> {
1397         self.print_block_maybe_unclosed(blk, indented, &[], false)
1398     }
1399
1400     pub fn print_block_with_attrs(&mut self,
1401                                   blk: &ast::Block,
1402                                   attrs: &[ast::Attribute]) -> IoResult<()> {
1403         self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
1404     }
1405
1406     pub fn print_block_maybe_unclosed(&mut self,
1407                                       blk: &ast::Block,
1408                                       indented: usize,
1409                                       attrs: &[ast::Attribute],
1410                                       close_box: bool) -> IoResult<()> {
1411         match blk.rules {
1412             ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
1413             ast::DefaultBlock => ()
1414         }
1415         try!(self.maybe_print_comment(blk.span.lo));
1416         try!(self.ann.pre(self, NodeBlock(blk)));
1417         try!(self.bopen());
1418
1419         try!(self.print_inner_attributes(attrs));
1420
1421         for st in &blk.stmts {
1422             try!(self.print_stmt(&**st));
1423         }
1424         match blk.expr {
1425             Some(ref expr) => {
1426                 try!(self.space_if_not_bol());
1427                 try!(self.print_expr(&**expr));
1428                 try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
1429             }
1430             _ => ()
1431         }
1432         try!(self.bclose_maybe_open(blk.span, indented, close_box));
1433         self.ann.post(self, NodeBlock(blk))
1434     }
1435
1436     fn print_else(&mut self, els: Option<&ast::Expr>) -> IoResult<()> {
1437         match els {
1438             Some(_else) => {
1439                 match _else.node {
1440                     // "another else-if"
1441                     ast::ExprIf(ref i, ref then, ref e) => {
1442                         try!(self.cbox(indent_unit - 1));
1443                         try!(self.ibox(0));
1444                         try!(word(&mut self.s, " else if "));
1445                         try!(self.print_expr(&**i));
1446                         try!(space(&mut self.s));
1447                         try!(self.print_block(&**then));
1448                         self.print_else(e.as_ref().map(|e| &**e))
1449                     }
1450                     // "another else-if-let"
1451                     ast::ExprIfLet(ref pat, ref expr, ref then, ref e) => {
1452                         try!(self.cbox(indent_unit - 1));
1453                         try!(self.ibox(0));
1454                         try!(word(&mut self.s, " else if let "));
1455                         try!(self.print_pat(&**pat));
1456                         try!(space(&mut self.s));
1457                         try!(self.word_space("="));
1458                         try!(self.print_expr(&**expr));
1459                         try!(space(&mut self.s));
1460                         try!(self.print_block(&**then));
1461                         self.print_else(e.as_ref().map(|e| &**e))
1462                     }
1463                     // "final else"
1464                     ast::ExprBlock(ref b) => {
1465                         try!(self.cbox(indent_unit - 1));
1466                         try!(self.ibox(0));
1467                         try!(word(&mut self.s, " else "));
1468                         self.print_block(&**b)
1469                     }
1470                     // BLEAH, constraints would be great here
1471                     _ => {
1472                         panic!("print_if saw if with weird alternative");
1473                     }
1474                 }
1475             }
1476             _ => Ok(())
1477         }
1478     }
1479
1480     pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
1481                     elseopt: Option<&ast::Expr>) -> IoResult<()> {
1482         try!(self.head("if"));
1483         try!(self.print_expr(test));
1484         try!(space(&mut self.s));
1485         try!(self.print_block(blk));
1486         self.print_else(elseopt)
1487     }
1488
1489     pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
1490                         elseopt: Option<&ast::Expr>) -> IoResult<()> {
1491         try!(self.head("if let"));
1492         try!(self.print_pat(pat));
1493         try!(space(&mut self.s));
1494         try!(self.word_space("="));
1495         try!(self.print_expr(expr));
1496         try!(space(&mut self.s));
1497         try!(self.print_block(blk));
1498         self.print_else(elseopt)
1499     }
1500
1501     pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
1502                      -> IoResult<()> {
1503         match m.node {
1504             // I think it's reasonable to hide the ctxt here:
1505             ast::MacInvocTT(ref pth, ref tts, _) => {
1506                 try!(self.print_path(pth, false));
1507                 try!(word(&mut self.s, "!"));
1508                 match delim {
1509                     token::Paren => try!(self.popen()),
1510                     token::Bracket => try!(word(&mut self.s, "[")),
1511                     token::Brace => try!(self.bopen()),
1512                 }
1513                 try!(self.print_tts(tts));
1514                 match delim {
1515                     token::Paren => self.pclose(),
1516                     token::Bracket => word(&mut self.s, "]"),
1517                     token::Brace => self.bclose(m.span),
1518                 }
1519             }
1520         }
1521     }
1522
1523
1524     fn print_call_post(&mut self, args: &[P<ast::Expr>]) -> IoResult<()> {
1525         try!(self.popen());
1526         try!(self.commasep_exprs(Inconsistent, args));
1527         self.pclose()
1528     }
1529
1530     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
1531         let needs_par = needs_parentheses(expr);
1532         if needs_par {
1533             try!(self.popen());
1534         }
1535         try!(self.print_expr(expr));
1536         if needs_par {
1537             try!(self.pclose());
1538         }
1539         Ok(())
1540     }
1541
1542     fn print_expr_box(&mut self,
1543                       place: &Option<P<ast::Expr>>,
1544                       expr: &ast::Expr) -> IoResult<()> {
1545         try!(word(&mut self.s, "box"));
1546         try!(word(&mut self.s, "("));
1547         try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
1548         try!(self.word_space(")"));
1549         self.print_expr(expr)
1550     }
1551
1552     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
1553         try!(self.ibox(indent_unit));
1554         try!(word(&mut self.s, "["));
1555         try!(self.commasep_exprs(Inconsistent, &exprs[]));
1556         try!(word(&mut self.s, "]"));
1557         self.end()
1558     }
1559
1560     fn print_expr_repeat(&mut self,
1561                          element: &ast::Expr,
1562                          count: &ast::Expr) -> IoResult<()> {
1563         try!(self.ibox(indent_unit));
1564         try!(word(&mut self.s, "["));
1565         try!(self.print_expr(element));
1566         try!(self.word_space(";"));
1567         try!(self.print_expr(count));
1568         try!(word(&mut self.s, "]"));
1569         self.end()
1570     }
1571
1572     fn print_expr_struct(&mut self,
1573                          path: &ast::Path,
1574                          fields: &[ast::Field],
1575                          wth: &Option<P<ast::Expr>>) -> IoResult<()> {
1576         try!(self.print_path(path, true));
1577         if !(fields.is_empty() && wth.is_none()) {
1578             try!(word(&mut self.s, "{"));
1579             try!(self.commasep_cmnt(
1580                 Consistent,
1581                 &fields[],
1582                 |s, field| {
1583                     try!(s.ibox(indent_unit));
1584                     try!(s.print_ident(field.ident.node));
1585                     try!(s.word_space(":"));
1586                     try!(s.print_expr(&*field.expr));
1587                     s.end()
1588                 },
1589                 |f| f.span));
1590             match *wth {
1591                 Some(ref expr) => {
1592                     try!(self.ibox(indent_unit));
1593                     if !fields.is_empty() {
1594                         try!(word(&mut self.s, ","));
1595                         try!(space(&mut self.s));
1596                     }
1597                     try!(word(&mut self.s, ".."));
1598                     try!(self.print_expr(&**expr));
1599                     try!(self.end());
1600                 }
1601                 _ => try!(word(&mut self.s, ",")),
1602             }
1603             try!(word(&mut self.s, "}"));
1604         }
1605         Ok(())
1606     }
1607
1608     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
1609         try!(self.popen());
1610         try!(self.commasep_exprs(Inconsistent, &exprs[]));
1611         if exprs.len() == 1 {
1612             try!(word(&mut self.s, ","));
1613         }
1614         self.pclose()
1615     }
1616
1617     fn print_expr_call(&mut self,
1618                        func: &ast::Expr,
1619                        args: &[P<ast::Expr>]) -> IoResult<()> {
1620         try!(self.print_expr_maybe_paren(func));
1621         self.print_call_post(args)
1622     }
1623
1624     fn print_expr_method_call(&mut self,
1625                               ident: ast::SpannedIdent,
1626                               tys: &[P<ast::Ty>],
1627                               args: &[P<ast::Expr>]) -> IoResult<()> {
1628         let base_args = &args[1..];
1629         try!(self.print_expr(&*args[0]));
1630         try!(word(&mut self.s, "."));
1631         try!(self.print_ident(ident.node));
1632         if tys.len() > 0 {
1633             try!(word(&mut self.s, "::<"));
1634             try!(self.commasep(Inconsistent, tys,
1635                                |s, ty| s.print_type(&**ty)));
1636             try!(word(&mut self.s, ">"));
1637         }
1638         self.print_call_post(base_args)
1639     }
1640
1641     fn print_expr_binary(&mut self,
1642                          op: ast::BinOp,
1643                          lhs: &ast::Expr,
1644                          rhs: &ast::Expr) -> IoResult<()> {
1645         try!(self.print_expr(lhs));
1646         try!(space(&mut self.s));
1647         try!(self.word_space(ast_util::binop_to_string(op.node)));
1648         self.print_expr(rhs)
1649     }
1650
1651     fn print_expr_unary(&mut self,
1652                         op: ast::UnOp,
1653                         expr: &ast::Expr) -> IoResult<()> {
1654         try!(word(&mut self.s, ast_util::unop_to_string(op)));
1655         self.print_expr_maybe_paren(expr)
1656     }
1657
1658     fn print_expr_addr_of(&mut self,
1659                           mutability: ast::Mutability,
1660                           expr: &ast::Expr) -> IoResult<()> {
1661         try!(word(&mut self.s, "&"));
1662         try!(self.print_mutability(mutability));
1663         self.print_expr_maybe_paren(expr)
1664     }
1665
1666     pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
1667         try!(self.maybe_print_comment(expr.span.lo));
1668         try!(self.ibox(indent_unit));
1669         try!(self.ann.pre(self, NodeExpr(expr)));
1670         match expr.node {
1671             ast::ExprBox(ref place, ref expr) => {
1672                 try!(self.print_expr_box(place, &**expr));
1673             }
1674             ast::ExprVec(ref exprs) => {
1675                 try!(self.print_expr_vec(&exprs[]));
1676             }
1677             ast::ExprRepeat(ref element, ref count) => {
1678                 try!(self.print_expr_repeat(&**element, &**count));
1679             }
1680             ast::ExprStruct(ref path, ref fields, ref wth) => {
1681                 try!(self.print_expr_struct(path, &fields[], wth));
1682             }
1683             ast::ExprTup(ref exprs) => {
1684                 try!(self.print_expr_tup(&exprs[]));
1685             }
1686             ast::ExprCall(ref func, ref args) => {
1687                 try!(self.print_expr_call(&**func, &args[]));
1688             }
1689             ast::ExprMethodCall(ident, ref tys, ref args) => {
1690                 try!(self.print_expr_method_call(ident, &tys[], &args[]));
1691             }
1692             ast::ExprBinary(op, ref lhs, ref rhs) => {
1693                 try!(self.print_expr_binary(op, &**lhs, &**rhs));
1694             }
1695             ast::ExprUnary(op, ref expr) => {
1696                 try!(self.print_expr_unary(op, &**expr));
1697             }
1698             ast::ExprAddrOf(m, ref expr) => {
1699                 try!(self.print_expr_addr_of(m, &**expr));
1700             }
1701             ast::ExprLit(ref lit) => {
1702                 try!(self.print_literal(&**lit));
1703             }
1704             ast::ExprCast(ref expr, ref ty) => {
1705                 try!(self.print_expr(&**expr));
1706                 try!(space(&mut self.s));
1707                 try!(self.word_space("as"));
1708                 try!(self.print_type(&**ty));
1709             }
1710             ast::ExprIf(ref test, ref blk, ref elseopt) => {
1711                 try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
1712             }
1713             ast::ExprIfLet(ref pat, ref expr, ref blk, ref elseopt) => {
1714                 try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
1715             }
1716             ast::ExprWhile(ref test, ref blk, opt_ident) => {
1717                 if let Some(ident) = opt_ident {
1718                     try!(self.print_ident(ident));
1719                     try!(self.word_space(":"));
1720                 }
1721                 try!(self.head("while"));
1722                 try!(self.print_expr(&**test));
1723                 try!(space(&mut self.s));
1724                 try!(self.print_block(&**blk));
1725             }
1726             ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
1727                 if let Some(ident) = opt_ident {
1728                     try!(self.print_ident(ident));
1729                     try!(self.word_space(":"));
1730                 }
1731                 try!(self.head("while let"));
1732                 try!(self.print_pat(&**pat));
1733                 try!(space(&mut self.s));
1734                 try!(self.word_space("="));
1735                 try!(self.print_expr(&**expr));
1736                 try!(space(&mut self.s));
1737                 try!(self.print_block(&**blk));
1738             }
1739             ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
1740                 if let Some(ident) = opt_ident {
1741                     try!(self.print_ident(ident));
1742                     try!(self.word_space(":"));
1743                 }
1744                 try!(self.head("for"));
1745                 try!(self.print_pat(&**pat));
1746                 try!(space(&mut self.s));
1747                 try!(self.word_space("in"));
1748                 try!(self.print_expr(&**iter));
1749                 try!(space(&mut self.s));
1750                 try!(self.print_block(&**blk));
1751             }
1752             ast::ExprLoop(ref blk, opt_ident) => {
1753                 if let Some(ident) = opt_ident {
1754                     try!(self.print_ident(ident));
1755                     try!(self.word_space(":"));
1756                 }
1757                 try!(self.head("loop"));
1758                 try!(space(&mut self.s));
1759                 try!(self.print_block(&**blk));
1760             }
1761             ast::ExprMatch(ref expr, ref arms, _) => {
1762                 try!(self.cbox(indent_unit));
1763                 try!(self.ibox(4));
1764                 try!(self.word_nbsp("match"));
1765                 try!(self.print_expr(&**expr));
1766                 try!(space(&mut self.s));
1767                 try!(self.bopen());
1768                 for arm in arms {
1769                     try!(self.print_arm(arm));
1770                 }
1771                 try!(self.bclose_(expr.span, indent_unit));
1772             }
1773             ast::ExprClosure(capture_clause, ref decl, ref body) => {
1774                 try!(self.print_capture_clause(capture_clause));
1775
1776                 try!(self.print_fn_block_args(&**decl));
1777                 try!(space(&mut self.s));
1778
1779                 if !body.stmts.is_empty() || !body.expr.is_some() {
1780                     try!(self.print_block_unclosed(&**body));
1781                 } else {
1782                     // we extract the block, so as not to create another set of boxes
1783                     match body.expr.as_ref().unwrap().node {
1784                         ast::ExprBlock(ref blk) => {
1785                             try!(self.print_block_unclosed(&**blk));
1786                         }
1787                         _ => {
1788                             // this is a bare expression
1789                             try!(self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap()));
1790                             try!(self.end()); // need to close a box
1791                         }
1792                     }
1793                 }
1794                 // a box will be closed by print_expr, but we didn't want an overall
1795                 // wrapper so we closed the corresponding opening. so create an
1796                 // empty box to satisfy the close.
1797                 try!(self.ibox(0));
1798             }
1799             ast::ExprBlock(ref blk) => {
1800                 // containing cbox, will be closed by print-block at }
1801                 try!(self.cbox(indent_unit));
1802                 // head-box, will be closed by print-block after {
1803                 try!(self.ibox(0));
1804                 try!(self.print_block(&**blk));
1805             }
1806             ast::ExprAssign(ref lhs, ref rhs) => {
1807                 try!(self.print_expr(&**lhs));
1808                 try!(space(&mut self.s));
1809                 try!(self.word_space("="));
1810                 try!(self.print_expr(&**rhs));
1811             }
1812             ast::ExprAssignOp(op, ref lhs, ref rhs) => {
1813                 try!(self.print_expr(&**lhs));
1814                 try!(space(&mut self.s));
1815                 try!(word(&mut self.s, ast_util::binop_to_string(op.node)));
1816                 try!(self.word_space("="));
1817                 try!(self.print_expr(&**rhs));
1818             }
1819             ast::ExprField(ref expr, id) => {
1820                 try!(self.print_expr(&**expr));
1821                 try!(word(&mut self.s, "."));
1822                 try!(self.print_ident(id.node));
1823             }
1824             ast::ExprTupField(ref expr, id) => {
1825                 try!(self.print_expr(&**expr));
1826                 try!(word(&mut self.s, "."));
1827                 try!(self.print_usize(id.node));
1828             }
1829             ast::ExprIndex(ref expr, ref index) => {
1830                 try!(self.print_expr(&**expr));
1831                 try!(word(&mut self.s, "["));
1832                 try!(self.print_expr(&**index));
1833                 try!(word(&mut self.s, "]"));
1834             }
1835             ast::ExprRange(ref start, ref end) => {
1836                 if let &Some(ref e) = start {
1837                     try!(self.print_expr(&**e));
1838                 }
1839                 try!(word(&mut self.s, ".."));
1840                 if let &Some(ref e) = end {
1841                     try!(self.print_expr(&**e));
1842                 }
1843             }
1844             ast::ExprPath(ref path) => try!(self.print_path(path, true)),
1845             ast::ExprQPath(ref qpath) => try!(self.print_qpath(&**qpath, true)),
1846             ast::ExprBreak(opt_ident) => {
1847                 try!(word(&mut self.s, "break"));
1848                 try!(space(&mut self.s));
1849                 if let Some(ident) = opt_ident {
1850                     try!(self.print_ident(ident));
1851                     try!(space(&mut self.s));
1852                 }
1853             }
1854             ast::ExprAgain(opt_ident) => {
1855                 try!(word(&mut self.s, "continue"));
1856                 try!(space(&mut self.s));
1857                 if let Some(ident) = opt_ident {
1858                     try!(self.print_ident(ident));
1859                     try!(space(&mut self.s))
1860                 }
1861             }
1862             ast::ExprRet(ref result) => {
1863                 try!(word(&mut self.s, "return"));
1864                 match *result {
1865                     Some(ref expr) => {
1866                         try!(word(&mut self.s, " "));
1867                         try!(self.print_expr(&**expr));
1868                     }
1869                     _ => ()
1870                 }
1871             }
1872             ast::ExprInlineAsm(ref a) => {
1873                 try!(word(&mut self.s, "asm!"));
1874                 try!(self.popen());
1875                 try!(self.print_string(&a.asm, a.asm_str_style));
1876                 try!(self.word_space(":"));
1877
1878                 try!(self.commasep(Inconsistent, &a.outputs[],
1879                                    |s, &(ref co, ref o, is_rw)| {
1880                     match co.slice_shift_char() {
1881                         Some(('=', operand)) if is_rw => {
1882                             try!(s.print_string(&format!("+{}", operand)[],
1883                                                 ast::CookedStr))
1884                         }
1885                         _ => try!(s.print_string(&co, ast::CookedStr))
1886                     }
1887                     try!(s.popen());
1888                     try!(s.print_expr(&**o));
1889                     try!(s.pclose());
1890                     Ok(())
1891                 }));
1892                 try!(space(&mut self.s));
1893                 try!(self.word_space(":"));
1894
1895                 try!(self.commasep(Inconsistent, &a.inputs[],
1896                                    |s, &(ref co, ref o)| {
1897                     try!(s.print_string(&co, ast::CookedStr));
1898                     try!(s.popen());
1899                     try!(s.print_expr(&**o));
1900                     try!(s.pclose());
1901                     Ok(())
1902                 }));
1903                 try!(space(&mut self.s));
1904                 try!(self.word_space(":"));
1905
1906                 try!(self.commasep(Inconsistent, &a.clobbers[],
1907                                    |s, co| {
1908                     try!(s.print_string(&co, ast::CookedStr));
1909                     Ok(())
1910                 }));
1911
1912                 let mut options = vec!();
1913                 if a.volatile {
1914                     options.push("volatile");
1915                 }
1916                 if a.alignstack {
1917                     options.push("alignstack");
1918                 }
1919                 if a.dialect == ast::AsmDialect::AsmIntel {
1920                     options.push("intel");
1921                 }
1922
1923                 if options.len() > 0 {
1924                     try!(space(&mut self.s));
1925                     try!(self.word_space(":"));
1926                     try!(self.commasep(Inconsistent, &*options,
1927                                        |s, &co| {
1928                         try!(s.print_string(co, ast::CookedStr));
1929                         Ok(())
1930                     }));
1931                 }
1932
1933                 try!(self.pclose());
1934             }
1935             ast::ExprMac(ref m) => try!(self.print_mac(m, token::Paren)),
1936             ast::ExprParen(ref e) => {
1937                 try!(self.popen());
1938                 try!(self.print_expr(&**e));
1939                 try!(self.pclose());
1940             }
1941         }
1942         try!(self.ann.post(self, NodeExpr(expr)));
1943         self.end()
1944     }
1945
1946     pub fn print_local_decl(&mut self, loc: &ast::Local) -> IoResult<()> {
1947         try!(self.print_pat(&*loc.pat));
1948         if let Some(ref ty) = loc.ty {
1949             try!(self.word_space(":"));
1950             try!(self.print_type(&**ty));
1951         }
1952         Ok(())
1953     }
1954
1955     pub fn print_decl(&mut self, decl: &ast::Decl) -> IoResult<()> {
1956         try!(self.maybe_print_comment(decl.span.lo));
1957         match decl.node {
1958             ast::DeclLocal(ref loc) => {
1959                 try!(self.space_if_not_bol());
1960                 try!(self.ibox(indent_unit));
1961                 try!(self.word_nbsp("let"));
1962
1963                 try!(self.ibox(indent_unit));
1964                 try!(self.print_local_decl(&**loc));
1965                 try!(self.end());
1966                 if let Some(ref init) = loc.init {
1967                     try!(self.nbsp());
1968                     try!(self.word_space("="));
1969                     try!(self.print_expr(&**init));
1970                 }
1971                 self.end()
1972             }
1973             ast::DeclItem(ref item) => self.print_item(&**item)
1974         }
1975     }
1976
1977     pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
1978         if self.encode_idents_with_hygiene {
1979             let encoded = ident.encode_with_hygiene();
1980             try!(word(&mut self.s, &encoded[]))
1981         } else {
1982             try!(word(&mut self.s, &token::get_ident(ident)))
1983         }
1984         self.ann.post(self, NodeIdent(&ident))
1985     }
1986
1987     pub fn print_usize(&mut self, i: usize) -> IoResult<()> {
1988         word(&mut self.s, &i.to_string()[])
1989     }
1990
1991     pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
1992         try!(word(&mut self.s, &token::get_name(name)));
1993         self.ann.post(self, NodeName(&name))
1994     }
1995
1996     pub fn print_for_decl(&mut self, loc: &ast::Local,
1997                           coll: &ast::Expr) -> IoResult<()> {
1998         try!(self.print_local_decl(loc));
1999         try!(space(&mut self.s));
2000         try!(self.word_space("in"));
2001         self.print_expr(coll)
2002     }
2003
2004     fn print_path(&mut self,
2005                   path: &ast::Path,
2006                   colons_before_params: bool)
2007                   -> IoResult<()>
2008     {
2009         try!(self.maybe_print_comment(path.span.lo));
2010         if path.global {
2011             try!(word(&mut self.s, "::"));
2012         }
2013
2014         let mut first = true;
2015         for segment in &path.segments {
2016             if first {
2017                 first = false
2018             } else {
2019                 try!(word(&mut self.s, "::"))
2020             }
2021
2022             try!(self.print_ident(segment.identifier));
2023
2024             try!(self.print_path_parameters(&segment.parameters, colons_before_params));
2025         }
2026
2027         Ok(())
2028     }
2029
2030     fn print_qpath(&mut self,
2031                    qpath: &ast::QPath,
2032                    colons_before_params: bool)
2033                    -> IoResult<()>
2034     {
2035         try!(word(&mut self.s, "<"));
2036         try!(self.print_type(&*qpath.self_type));
2037         try!(space(&mut self.s));
2038         try!(self.word_space("as"));
2039         try!(self.print_trait_ref(&*qpath.trait_ref));
2040         try!(word(&mut self.s, ">"));
2041         try!(word(&mut self.s, "::"));
2042         try!(self.print_ident(qpath.item_path.identifier));
2043         self.print_path_parameters(&qpath.item_path.parameters, colons_before_params)
2044     }
2045
2046     fn print_path_parameters(&mut self,
2047                              parameters: &ast::PathParameters,
2048                              colons_before_params: bool)
2049                              -> IoResult<()>
2050     {
2051         if parameters.is_empty() {
2052             return Ok(());
2053         }
2054
2055         if colons_before_params {
2056             try!(word(&mut self.s, "::"))
2057         }
2058
2059         match *parameters {
2060             ast::AngleBracketedParameters(ref data) => {
2061                 try!(word(&mut self.s, "<"));
2062
2063                 let mut comma = false;
2064                 for lifetime in &data.lifetimes {
2065                     if comma {
2066                         try!(self.word_space(","))
2067                     }
2068                     try!(self.print_lifetime(lifetime));
2069                     comma = true;
2070                 }
2071
2072                 if !data.types.is_empty() {
2073                     if comma {
2074                         try!(self.word_space(","))
2075                     }
2076                     try!(self.commasep(
2077                         Inconsistent,
2078                         &data.types[],
2079                         |s, ty| s.print_type(&**ty)));
2080                         comma = true;
2081                 }
2082
2083                 for binding in &*data.bindings {
2084                     if comma {
2085                         try!(self.word_space(","))
2086                     }
2087                     try!(self.print_ident(binding.ident));
2088                     try!(space(&mut self.s));
2089                     try!(self.word_space("="));
2090                     try!(self.print_type(&*binding.ty));
2091                     comma = true;
2092                 }
2093
2094                 try!(word(&mut self.s, ">"))
2095             }
2096
2097             ast::ParenthesizedParameters(ref data) => {
2098                 try!(word(&mut self.s, "("));
2099                 try!(self.commasep(
2100                     Inconsistent,
2101                     &data.inputs[],
2102                     |s, ty| s.print_type(&**ty)));
2103                 try!(word(&mut self.s, ")"));
2104
2105                 match data.output {
2106                     None => { }
2107                     Some(ref ty) => {
2108                         try!(self.space_if_not_bol());
2109                         try!(self.word_space("->"));
2110                         try!(self.print_type(&**ty));
2111                     }
2112                 }
2113             }
2114         }
2115
2116         Ok(())
2117     }
2118
2119     pub fn print_pat(&mut self, pat: &ast::Pat) -> IoResult<()> {
2120         try!(self.maybe_print_comment(pat.span.lo));
2121         try!(self.ann.pre(self, NodePat(pat)));
2122         /* Pat isn't normalized, but the beauty of it
2123          is that it doesn't matter */
2124         match pat.node {
2125             ast::PatWild(ast::PatWildSingle) => try!(word(&mut self.s, "_")),
2126             ast::PatWild(ast::PatWildMulti) => try!(word(&mut self.s, "..")),
2127             ast::PatIdent(binding_mode, ref path1, ref sub) => {
2128                 match binding_mode {
2129                     ast::BindByRef(mutbl) => {
2130                         try!(self.word_nbsp("ref"));
2131                         try!(self.print_mutability(mutbl));
2132                     }
2133                     ast::BindByValue(ast::MutImmutable) => {}
2134                     ast::BindByValue(ast::MutMutable) => {
2135                         try!(self.word_nbsp("mut"));
2136                     }
2137                 }
2138                 try!(self.print_ident(path1.node));
2139                 match *sub {
2140                     Some(ref p) => {
2141                         try!(word(&mut self.s, "@"));
2142                         try!(self.print_pat(&**p));
2143                     }
2144                     None => ()
2145                 }
2146             }
2147             ast::PatEnum(ref path, ref args_) => {
2148                 try!(self.print_path(path, true));
2149                 match *args_ {
2150                     None => try!(word(&mut self.s, "(..)")),
2151                     Some(ref args) => {
2152                         if !args.is_empty() {
2153                             try!(self.popen());
2154                             try!(self.commasep(Inconsistent, &args[],
2155                                               |s, p| s.print_pat(&**p)));
2156                             try!(self.pclose());
2157                         }
2158                     }
2159                 }
2160             }
2161             ast::PatStruct(ref path, ref fields, etc) => {
2162                 try!(self.print_path(path, true));
2163                 try!(self.nbsp());
2164                 try!(self.word_space("{"));
2165                 try!(self.commasep_cmnt(
2166                     Consistent, &fields[],
2167                     |s, f| {
2168                         try!(s.cbox(indent_unit));
2169                         if !f.node.is_shorthand {
2170                             try!(s.print_ident(f.node.ident));
2171                             try!(s.word_nbsp(":"));
2172                         }
2173                         try!(s.print_pat(&*f.node.pat));
2174                         s.end()
2175                     },
2176                     |f| f.node.pat.span));
2177                 if etc {
2178                     if fields.len() != 0 { try!(self.word_space(",")); }
2179                     try!(word(&mut self.s, ".."));
2180                 }
2181                 try!(space(&mut self.s));
2182                 try!(word(&mut self.s, "}"));
2183             }
2184             ast::PatTup(ref elts) => {
2185                 try!(self.popen());
2186                 try!(self.commasep(Inconsistent,
2187                                    &elts[],
2188                                    |s, p| s.print_pat(&**p)));
2189                 if elts.len() == 1 {
2190                     try!(word(&mut self.s, ","));
2191                 }
2192                 try!(self.pclose());
2193             }
2194             ast::PatBox(ref inner) => {
2195                 try!(word(&mut self.s, "box "));
2196                 try!(self.print_pat(&**inner));
2197             }
2198             ast::PatRegion(ref inner, mutbl) => {
2199                 try!(word(&mut self.s, "&"));
2200                 if mutbl == ast::MutMutable {
2201                     try!(word(&mut self.s, "mut "));
2202                 }
2203                 try!(self.print_pat(&**inner));
2204             }
2205             ast::PatLit(ref e) => try!(self.print_expr(&**e)),
2206             ast::PatRange(ref begin, ref end) => {
2207                 try!(self.print_expr(&**begin));
2208                 try!(space(&mut self.s));
2209                 try!(word(&mut self.s, "..."));
2210                 try!(self.print_expr(&**end));
2211             }
2212             ast::PatVec(ref before, ref slice, ref after) => {
2213                 try!(word(&mut self.s, "["));
2214                 try!(self.commasep(Inconsistent,
2215                                    &before[],
2216                                    |s, p| s.print_pat(&**p)));
2217                 if let Some(ref p) = *slice {
2218                     if !before.is_empty() { try!(self.word_space(",")); }
2219                     try!(self.print_pat(&**p));
2220                     match **p {
2221                         ast::Pat { node: ast::PatWild(ast::PatWildMulti), .. } => {
2222                             // this case is handled by print_pat
2223                         }
2224                         _ => try!(word(&mut self.s, "..")),
2225                     }
2226                     if !after.is_empty() { try!(self.word_space(",")); }
2227                 }
2228                 try!(self.commasep(Inconsistent,
2229                                    &after[],
2230                                    |s, p| s.print_pat(&**p)));
2231                 try!(word(&mut self.s, "]"));
2232             }
2233             ast::PatMac(ref m) => try!(self.print_mac(m, token::Paren)),
2234         }
2235         self.ann.post(self, NodePat(pat))
2236     }
2237
2238     fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> {
2239         // I have no idea why this check is necessary, but here it
2240         // is :(
2241         if arm.attrs.is_empty() {
2242             try!(space(&mut self.s));
2243         }
2244         try!(self.cbox(indent_unit));
2245         try!(self.ibox(0));
2246         try!(self.print_outer_attributes(&arm.attrs[]));
2247         let mut first = true;
2248         for p in &arm.pats {
2249             if first {
2250                 first = false;
2251             } else {
2252                 try!(space(&mut self.s));
2253                 try!(self.word_space("|"));
2254             }
2255             try!(self.print_pat(&**p));
2256         }
2257         try!(space(&mut self.s));
2258         if let Some(ref e) = arm.guard {
2259             try!(self.word_space("if"));
2260             try!(self.print_expr(&**e));
2261             try!(space(&mut self.s));
2262         }
2263         try!(self.word_space("=>"));
2264
2265         match arm.body.node {
2266             ast::ExprBlock(ref blk) => {
2267                 // the block will close the pattern's ibox
2268                 try!(self.print_block_unclosed_indent(&**blk, indent_unit));
2269
2270                 // If it is a user-provided unsafe block, print a comma after it
2271                 if let ast::UnsafeBlock(ast::UserProvided) = blk.rules {
2272                     try!(word(&mut self.s, ","));
2273                 }
2274             }
2275             _ => {
2276                 try!(self.end()); // close the ibox for the pattern
2277                 try!(self.print_expr(&*arm.body));
2278                 try!(word(&mut self.s, ","));
2279             }
2280         }
2281         self.end() // close enclosing cbox
2282     }
2283
2284     // Returns whether it printed anything
2285     fn print_explicit_self(&mut self,
2286                            explicit_self: &ast::ExplicitSelf_,
2287                            mutbl: ast::Mutability) -> IoResult<bool> {
2288         try!(self.print_mutability(mutbl));
2289         match *explicit_self {
2290             ast::SelfStatic => { return Ok(false); }
2291             ast::SelfValue(_) => {
2292                 try!(word(&mut self.s, "self"));
2293             }
2294             ast::SelfRegion(ref lt, m, _) => {
2295                 try!(word(&mut self.s, "&"));
2296                 try!(self.print_opt_lifetime(lt));
2297                 try!(self.print_mutability(m));
2298                 try!(word(&mut self.s, "self"));
2299             }
2300             ast::SelfExplicit(ref typ, _) => {
2301                 try!(word(&mut self.s, "self"));
2302                 try!(self.word_space(":"));
2303                 try!(self.print_type(&**typ));
2304             }
2305         }
2306         return Ok(true);
2307     }
2308
2309     pub fn print_fn(&mut self,
2310                     decl: &ast::FnDecl,
2311                     unsafety: Option<ast::Unsafety>,
2312                     abi: abi::Abi,
2313                     name: ast::Ident,
2314                     generics: &ast::Generics,
2315                     opt_explicit_self: Option<&ast::ExplicitSelf_>,
2316                     vis: ast::Visibility) -> IoResult<()> {
2317         try!(self.head(""));
2318         try!(self.print_fn_header_info(unsafety, abi, vis));
2319         try!(self.nbsp());
2320         try!(self.print_ident(name));
2321         try!(self.print_generics(generics));
2322         try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
2323         self.print_where_clause(generics)
2324     }
2325
2326     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
2327                          opt_explicit_self: Option<&ast::ExplicitSelf_>)
2328         -> IoResult<()> {
2329         // It is unfortunate to duplicate the commasep logic, but we want the
2330         // self type and the args all in the same box.
2331         try!(self.rbox(0, Inconsistent));
2332         let mut first = true;
2333         if let Some(explicit_self) = opt_explicit_self {
2334             let m = match explicit_self {
2335                 &ast::SelfStatic => ast::MutImmutable,
2336                 _ => match decl.inputs[0].pat.node {
2337                     ast::PatIdent(ast::BindByValue(m), _, _) => m,
2338                     _ => ast::MutImmutable
2339                 }
2340             };
2341             first = !try!(self.print_explicit_self(explicit_self, m));
2342         }
2343
2344         // HACK(eddyb) ignore the separately printed self argument.
2345         let args = if first {
2346             &decl.inputs[]
2347         } else {
2348             &decl.inputs[1..]
2349         };
2350
2351         for arg in args {
2352             if first { first = false; } else { try!(self.word_space(",")); }
2353             try!(self.print_arg(arg));
2354         }
2355
2356         self.end()
2357     }
2358
2359     pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl,
2360                                  opt_explicit_self: Option<&ast::ExplicitSelf_>)
2361         -> IoResult<()> {
2362         try!(self.popen());
2363         try!(self.print_fn_args(decl, opt_explicit_self));
2364         if decl.variadic {
2365             try!(word(&mut self.s, ", ..."));
2366         }
2367         try!(self.pclose());
2368
2369         self.print_fn_output(decl)
2370     }
2371
2372     pub fn print_fn_block_args(
2373             &mut self,
2374             decl: &ast::FnDecl)
2375             -> IoResult<()> {
2376         try!(word(&mut self.s, "|"));
2377         try!(self.print_fn_args(decl, None));
2378         try!(word(&mut self.s, "|"));
2379
2380         if let ast::DefaultReturn(..) = decl.output {
2381             return Ok(());
2382         }
2383
2384         try!(self.space_if_not_bol());
2385         try!(self.word_space("->"));
2386         match decl.output {
2387             ast::Return(ref ty) => {
2388                 try!(self.print_type(&**ty));
2389                 self.maybe_print_comment(ty.span.lo)
2390             }
2391             ast::DefaultReturn(..) => unreachable!(),
2392             ast::NoReturn(span) => {
2393                 try!(self.word_nbsp("!"));
2394                 self.maybe_print_comment(span.lo)
2395             }
2396         }
2397     }
2398
2399     pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureClause)
2400                                 -> IoResult<()> {
2401         match capture_clause {
2402             ast::CaptureByValue => self.word_space("move"),
2403             ast::CaptureByRef => Ok(()),
2404         }
2405     }
2406
2407     pub fn print_bounds(&mut self,
2408                         prefix: &str,
2409                         bounds: &[ast::TyParamBound])
2410                         -> IoResult<()> {
2411         if !bounds.is_empty() {
2412             try!(word(&mut self.s, prefix));
2413             let mut first = true;
2414             for bound in bounds {
2415                 try!(self.nbsp());
2416                 if first {
2417                     first = false;
2418                 } else {
2419                     try!(self.word_space("+"));
2420                 }
2421
2422                 try!(match *bound {
2423                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
2424                         self.print_poly_trait_ref(tref)
2425                     }
2426                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
2427                         try!(word(&mut self.s, "?"));
2428                         self.print_poly_trait_ref(tref)
2429                     }
2430                     RegionTyParamBound(ref lt) => {
2431                         self.print_lifetime(lt)
2432                     }
2433                 })
2434             }
2435             Ok(())
2436         } else {
2437             Ok(())
2438         }
2439     }
2440
2441     pub fn print_lifetime(&mut self,
2442                           lifetime: &ast::Lifetime)
2443                           -> IoResult<()>
2444     {
2445         self.print_name(lifetime.name)
2446     }
2447
2448     pub fn print_lifetime_def(&mut self,
2449                               lifetime: &ast::LifetimeDef)
2450                               -> IoResult<()>
2451     {
2452         try!(self.print_lifetime(&lifetime.lifetime));
2453         let mut sep = ":";
2454         for v in &lifetime.bounds {
2455             try!(word(&mut self.s, sep));
2456             try!(self.print_lifetime(v));
2457             sep = "+";
2458         }
2459         Ok(())
2460     }
2461
2462     pub fn print_generics(&mut self,
2463                           generics: &ast::Generics)
2464                           -> IoResult<()>
2465     {
2466         let total = generics.lifetimes.len() + generics.ty_params.len();
2467         if total == 0 {
2468             return Ok(());
2469         }
2470
2471         try!(word(&mut self.s, "<"));
2472
2473         let mut ints = Vec::new();
2474         for i in 0..total {
2475             ints.push(i);
2476         }
2477
2478         try!(self.commasep(Inconsistent, &ints[], |s, &idx| {
2479             if idx < generics.lifetimes.len() {
2480                 let lifetime = &generics.lifetimes[idx];
2481                 s.print_lifetime_def(lifetime)
2482             } else {
2483                 let idx = idx - generics.lifetimes.len();
2484                 let param = &generics.ty_params[idx];
2485                 s.print_ty_param(param)
2486             }
2487         }));
2488
2489         try!(word(&mut self.s, ">"));
2490         Ok(())
2491     }
2492
2493     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> {
2494         try!(self.print_ident(param.ident));
2495         try!(self.print_bounds(":", &param.bounds[]));
2496         match param.default {
2497             Some(ref default) => {
2498                 try!(space(&mut self.s));
2499                 try!(self.word_space("="));
2500                 self.print_type(&**default)
2501             }
2502             _ => Ok(())
2503         }
2504     }
2505
2506     pub fn print_where_clause(&mut self, generics: &ast::Generics)
2507                               -> IoResult<()> {
2508         if generics.where_clause.predicates.len() == 0 {
2509             return Ok(())
2510         }
2511
2512         try!(space(&mut self.s));
2513         try!(self.word_space("where"));
2514
2515         for (i, predicate) in generics.where_clause
2516                                       .predicates
2517                                       .iter()
2518                                       .enumerate() {
2519             if i != 0 {
2520                 try!(self.word_space(","));
2521             }
2522
2523             match predicate {
2524                 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes,
2525                                                                               ref bounded_ty,
2526                                                                               ref bounds,
2527                                                                               ..}) => {
2528                     try!(self.print_formal_lifetime_list(bound_lifetimes));
2529                     try!(self.print_type(&**bounded_ty));
2530                     try!(self.print_bounds(":", bounds));
2531                 }
2532                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
2533                                                                                 ref bounds,
2534                                                                                 ..}) => {
2535                     try!(self.print_lifetime(lifetime));
2536                     try!(word(&mut self.s, ":"));
2537
2538                     for (i, bound) in bounds.iter().enumerate() {
2539                         try!(self.print_lifetime(bound));
2540
2541                         if i != 0 {
2542                             try!(word(&mut self.s, ":"));
2543                         }
2544                     }
2545                 }
2546                 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
2547                     try!(self.print_path(path, false));
2548                     try!(space(&mut self.s));
2549                     try!(self.word_space("="));
2550                     try!(self.print_type(&**ty));
2551                 }
2552             }
2553         }
2554
2555         Ok(())
2556     }
2557
2558     pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
2559         try!(self.ibox(indent_unit));
2560         match item.node {
2561             ast::MetaWord(ref name) => {
2562                 try!(word(&mut self.s, &name));
2563             }
2564             ast::MetaNameValue(ref name, ref value) => {
2565                 try!(self.word_space(&name[]));
2566                 try!(self.word_space("="));
2567                 try!(self.print_literal(value));
2568             }
2569             ast::MetaList(ref name, ref items) => {
2570                 try!(word(&mut self.s, &name));
2571                 try!(self.popen());
2572                 try!(self.commasep(Consistent,
2573                                    &items[],
2574                                    |s, i| s.print_meta_item(&**i)));
2575                 try!(self.pclose());
2576             }
2577         }
2578         self.end()
2579     }
2580
2581     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> IoResult<()> {
2582         match vp.node {
2583             ast::ViewPathSimple(ident, ref path) => {
2584                 try!(self.print_path(path, false));
2585
2586                 // FIXME(#6993) can't compare identifiers directly here
2587                 if path.segments.last().unwrap().identifier.name !=
2588                         ident.name {
2589                     try!(space(&mut self.s));
2590                     try!(self.word_space("as"));
2591                     try!(self.print_ident(ident));
2592                 }
2593
2594                 Ok(())
2595             }
2596
2597             ast::ViewPathGlob(ref path) => {
2598                 try!(self.print_path(path, false));
2599                 word(&mut self.s, "::*")
2600             }
2601
2602             ast::ViewPathList(ref path, ref idents) => {
2603                 if path.segments.is_empty() {
2604                     try!(word(&mut self.s, "{"));
2605                 } else {
2606                     try!(self.print_path(path, false));
2607                     try!(word(&mut self.s, "::{"));
2608                 }
2609                 try!(self.commasep(Inconsistent, &idents[], |s, w| {
2610                     match w.node {
2611                         ast::PathListIdent { name, .. } => {
2612                             s.print_ident(name)
2613                         },
2614                         ast::PathListMod { .. } => {
2615                             word(&mut s.s, "self")
2616                         }
2617                     }
2618                 }));
2619                 word(&mut self.s, "}")
2620             }
2621         }
2622     }
2623
2624     pub fn print_mutability(&mut self,
2625                             mutbl: ast::Mutability) -> IoResult<()> {
2626         match mutbl {
2627             ast::MutMutable => self.word_nbsp("mut"),
2628             ast::MutImmutable => Ok(()),
2629         }
2630     }
2631
2632     pub fn print_mt(&mut self, mt: &ast::MutTy) -> IoResult<()> {
2633         try!(self.print_mutability(mt.mutbl));
2634         self.print_type(&*mt.ty)
2635     }
2636
2637     pub fn print_arg(&mut self, input: &ast::Arg) -> IoResult<()> {
2638         try!(self.ibox(indent_unit));
2639         match input.ty.node {
2640             ast::TyInfer => try!(self.print_pat(&*input.pat)),
2641             _ => {
2642                 match input.pat.node {
2643                     ast::PatIdent(_, ref path1, _) if
2644                         path1.node.name ==
2645                             parse::token::special_idents::invalid.name => {
2646                         // Do nothing.
2647                     }
2648                     _ => {
2649                         try!(self.print_pat(&*input.pat));
2650                         try!(word(&mut self.s, ":"));
2651                         try!(space(&mut self.s));
2652                     }
2653                 }
2654                 try!(self.print_type(&*input.ty));
2655             }
2656         }
2657         self.end()
2658     }
2659
2660     pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
2661         if let ast::DefaultReturn(..) = decl.output {
2662             return Ok(());
2663         }
2664
2665         try!(self.space_if_not_bol());
2666         try!(self.ibox(indent_unit));
2667         try!(self.word_space("->"));
2668         match decl.output {
2669             ast::NoReturn(_) =>
2670                 try!(self.word_nbsp("!")),
2671             ast::DefaultReturn(..) => unreachable!(),
2672             ast::Return(ref ty) =>
2673                 try!(self.print_type(&**ty))
2674         }
2675         try!(self.end());
2676
2677         match decl.output {
2678             ast::Return(ref output) => self.maybe_print_comment(output.span.lo),
2679             _ => Ok(())
2680         }
2681     }
2682
2683     pub fn print_ty_fn(&mut self,
2684                        abi: abi::Abi,
2685                        unsafety: ast::Unsafety,
2686                        decl: &ast::FnDecl,
2687                        id: Option<ast::Ident>,
2688                        generics: &ast::Generics,
2689                        opt_explicit_self: Option<&ast::ExplicitSelf_>)
2690                        -> IoResult<()> {
2691         try!(self.ibox(indent_unit));
2692         try!(self.print_fn_header_info(Some(unsafety), abi, ast::Inherited));
2693
2694         match id {
2695             Some(id) => {
2696                 try!(word(&mut self.s, " "));
2697                 try!(self.print_ident(id));
2698             }
2699             _ => ()
2700         }
2701
2702         try!(self.print_generics(generics));
2703         try!(zerobreak(&mut self.s));
2704         try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
2705         try!(self.print_where_clause(generics));
2706         self.end()
2707     }
2708
2709     pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
2710                                         next_pos: Option<BytePos>)
2711         -> IoResult<()> {
2712         let cm = match self.cm {
2713             Some(cm) => cm,
2714             _ => return Ok(())
2715         };
2716         match self.next_comment() {
2717             Some(ref cmnt) => {
2718                 if (*cmnt).style != comments::Trailing { return Ok(()) }
2719                 let span_line = cm.lookup_char_pos(span.hi);
2720                 let comment_line = cm.lookup_char_pos((*cmnt).pos);
2721                 let mut next = (*cmnt).pos + BytePos(1);
2722                 match next_pos { None => (), Some(p) => next = p }
2723                 if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
2724                     span_line.line == comment_line.line {
2725                         try!(self.print_comment(cmnt));
2726                         self.cur_cmnt_and_lit.cur_cmnt += 1;
2727                     }
2728             }
2729             _ => ()
2730         }
2731         Ok(())
2732     }
2733
2734     pub fn print_remaining_comments(&mut self) -> IoResult<()> {
2735         // If there aren't any remaining comments, then we need to manually
2736         // make sure there is a line break at the end.
2737         if self.next_comment().is_none() {
2738             try!(hardbreak(&mut self.s));
2739         }
2740         loop {
2741             match self.next_comment() {
2742                 Some(ref cmnt) => {
2743                     try!(self.print_comment(cmnt));
2744                     self.cur_cmnt_and_lit.cur_cmnt += 1;
2745                 }
2746                 _ => break
2747             }
2748         }
2749         Ok(())
2750     }
2751
2752     pub fn print_literal(&mut self, lit: &ast::Lit) -> IoResult<()> {
2753         try!(self.maybe_print_comment(lit.span.lo));
2754         match self.next_lit(lit.span.lo) {
2755             Some(ref ltrl) => {
2756                 return word(&mut self.s, &(*ltrl).lit[]);
2757             }
2758             _ => ()
2759         }
2760         match lit.node {
2761             ast::LitStr(ref st, style) => self.print_string(&st, style),
2762             ast::LitByte(byte) => {
2763                 let mut res = String::from_str("b'");
2764                 res.extend(ascii::escape_default(byte).map(|c| c as char));
2765                 res.push('\'');
2766                 word(&mut self.s, &res[])
2767             }
2768             ast::LitChar(ch) => {
2769                 let mut res = String::from_str("'");
2770                 res.extend(ch.escape_default());
2771                 res.push('\'');
2772                 word(&mut self.s, &res[])
2773             }
2774             ast::LitInt(i, t) => {
2775                 match t {
2776                     ast::SignedIntLit(st, ast::Plus) => {
2777                         word(&mut self.s,
2778                              &ast_util::int_ty_to_string(st, Some(i as i64))[])
2779                     }
2780                     ast::SignedIntLit(st, ast::Minus) => {
2781                         let istr = ast_util::int_ty_to_string(st, Some(-(i as i64)));
2782                         word(&mut self.s,
2783                              &format!("-{}", istr)[])
2784                     }
2785                     ast::UnsignedIntLit(ut) => {
2786                         word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i)))
2787                     }
2788                     ast::UnsuffixedIntLit(ast::Plus) => {
2789                         word(&mut self.s, &format!("{}", i)[])
2790                     }
2791                     ast::UnsuffixedIntLit(ast::Minus) => {
2792                         word(&mut self.s, &format!("-{}", i)[])
2793                     }
2794                 }
2795             }
2796             ast::LitFloat(ref f, t) => {
2797                 word(&mut self.s,
2798                      &format!(
2799                          "{}{}",
2800                          &f,
2801                          &ast_util::float_ty_to_string(t)[])[])
2802             }
2803             ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[]),
2804             ast::LitBool(val) => {
2805                 if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
2806             }
2807             ast::LitBinary(ref v) => {
2808                 let mut escaped: String = String::new();
2809                 for &ch in &**v {
2810                     escaped.extend(ascii::escape_default(ch as u8)
2811                                          .map(|c| c as char));
2812                 }
2813                 word(&mut self.s, &format!("b\"{}\"", escaped)[])
2814             }
2815         }
2816     }
2817
2818     pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
2819         match self.literals {
2820             Some(ref lits) => {
2821                 while self.cur_cmnt_and_lit.cur_lit < lits.len() {
2822                     let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone();
2823                     if ltrl.pos > pos { return None; }
2824                     self.cur_cmnt_and_lit.cur_lit += 1;
2825                     if ltrl.pos == pos { return Some(ltrl); }
2826                 }
2827                 None
2828             }
2829             _ => None
2830         }
2831     }
2832
2833     pub fn maybe_print_comment(&mut self, pos: BytePos) -> IoResult<()> {
2834         loop {
2835             match self.next_comment() {
2836                 Some(ref cmnt) => {
2837                     if (*cmnt).pos < pos {
2838                         try!(self.print_comment(cmnt));
2839                         self.cur_cmnt_and_lit.cur_cmnt += 1;
2840                     } else { break; }
2841                 }
2842                 _ => break
2843             }
2844         }
2845         Ok(())
2846     }
2847
2848     pub fn print_comment(&mut self,
2849                          cmnt: &comments::Comment) -> IoResult<()> {
2850         match cmnt.style {
2851             comments::Mixed => {
2852                 assert_eq!(cmnt.lines.len(), 1);
2853                 try!(zerobreak(&mut self.s));
2854                 try!(word(&mut self.s, &cmnt.lines[0][]));
2855                 zerobreak(&mut self.s)
2856             }
2857             comments::Isolated => {
2858                 try!(self.hardbreak_if_not_bol());
2859                 for line in &cmnt.lines {
2860                     // Don't print empty lines because they will end up as trailing
2861                     // whitespace
2862                     if !line.is_empty() {
2863                         try!(word(&mut self.s, &line[]));
2864                     }
2865                     try!(hardbreak(&mut self.s));
2866                 }
2867                 Ok(())
2868             }
2869             comments::Trailing => {
2870                 try!(word(&mut self.s, " "));
2871                 if cmnt.lines.len() == 1 {
2872                     try!(word(&mut self.s, &cmnt.lines[0][]));
2873                     hardbreak(&mut self.s)
2874                 } else {
2875                     try!(self.ibox(0));
2876                     for line in &cmnt.lines {
2877                         if !line.is_empty() {
2878                             try!(word(&mut self.s, &line[]));
2879                         }
2880                         try!(hardbreak(&mut self.s));
2881                     }
2882                     self.end()
2883                 }
2884             }
2885             comments::BlankLine => {
2886                 // We need to do at least one, possibly two hardbreaks.
2887                 let is_semi = match self.s.last_token() {
2888                     pp::Token::String(s, _) => ";" == s,
2889                     _ => false
2890                 };
2891                 if is_semi || self.is_begin() || self.is_end() {
2892                     try!(hardbreak(&mut self.s));
2893                 }
2894                 hardbreak(&mut self.s)
2895             }
2896         }
2897     }
2898
2899     pub fn print_string(&mut self, st: &str,
2900                         style: ast::StrStyle) -> IoResult<()> {
2901         let st = match style {
2902             ast::CookedStr => {
2903                 (format!("\"{}\"", st.escape_default()))
2904             }
2905             ast::RawStr(n) => {
2906                 (format!("r{delim}\"{string}\"{delim}",
2907                          delim=repeat("#", n),
2908                          string=st))
2909             }
2910         };
2911         word(&mut self.s, &st[])
2912     }
2913
2914     pub fn next_comment(&mut self) -> Option<comments::Comment> {
2915         match self.comments {
2916             Some(ref cmnts) => {
2917                 if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
2918                     Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone())
2919                 } else {
2920                     None
2921                 }
2922             }
2923             _ => None
2924         }
2925     }
2926
2927     pub fn print_opt_unsafety(&mut self,
2928                             opt_unsafety: Option<ast::Unsafety>) -> IoResult<()> {
2929         match opt_unsafety {
2930             Some(unsafety) => self.print_unsafety(unsafety),
2931             None => Ok(())
2932         }
2933     }
2934
2935     pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
2936                                                   opt_abi: Option<abi::Abi>)
2937         -> IoResult<()> {
2938         match opt_abi {
2939             Some(abi::Rust) => Ok(()),
2940             Some(abi) => {
2941                 try!(self.word_nbsp("extern"));
2942                 self.word_nbsp(&abi.to_string()[])
2943             }
2944             None => Ok(())
2945         }
2946     }
2947
2948     pub fn print_extern_opt_abi(&mut self,
2949                                 opt_abi: Option<abi::Abi>) -> IoResult<()> {
2950         match opt_abi {
2951             Some(abi) => {
2952                 try!(self.word_nbsp("extern"));
2953                 self.word_nbsp(&abi.to_string()[])
2954             }
2955             None => Ok(())
2956         }
2957     }
2958
2959     pub fn print_fn_header_info(&mut self,
2960                                 opt_unsafety: Option<ast::Unsafety>,
2961                                 abi: abi::Abi,
2962                                 vis: ast::Visibility) -> IoResult<()> {
2963         try!(word(&mut self.s, &visibility_qualified(vis, "")));
2964         try!(self.print_opt_unsafety(opt_unsafety));
2965
2966         if abi != abi::Rust {
2967             try!(self.word_nbsp("extern"));
2968             try!(self.word_nbsp(&abi.to_string()[]));
2969         }
2970
2971         word(&mut self.s, "fn")
2972     }
2973
2974     pub fn print_unsafety(&mut self, s: ast::Unsafety) -> IoResult<()> {
2975         match s {
2976             ast::Unsafety::Normal => Ok(()),
2977             ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
2978         }
2979     }
2980 }
2981
2982 fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
2983
2984 #[cfg(test)]
2985 mod test {
2986     use super::*;
2987
2988     use ast;
2989     use ast_util;
2990     use codemap;
2991     use parse::token;
2992
2993     #[test]
2994     fn test_fun_to_string() {
2995         let abba_ident = token::str_to_ident("abba");
2996
2997         let decl = ast::FnDecl {
2998             inputs: Vec::new(),
2999             output: ast::DefaultReturn(codemap::DUMMY_SP),
3000             variadic: false
3001         };
3002         let generics = ast_util::empty_generics();
3003         assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, abba_ident,
3004                                None, &generics),
3005                    "fn abba()");
3006     }
3007
3008     #[test]
3009     fn test_variant_to_string() {
3010         let ident = token::str_to_ident("principal_skinner");
3011
3012         let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ {
3013             name: ident,
3014             attrs: Vec::new(),
3015             // making this up as I go.... ?
3016             kind: ast::TupleVariantKind(Vec::new()),
3017             id: 0,
3018             disr_expr: None,
3019             vis: ast::Public,
3020         });
3021
3022         let varstr = variant_to_string(&var);
3023         assert_eq!(varstr, "pub principal_skinner");
3024     }
3025
3026     #[test]
3027     fn test_signed_int_to_string() {
3028         let pos_int = ast::LitInt(42, ast::SignedIntLit(ast::TyI32, ast::Plus));
3029         let neg_int = ast::LitInt((-42) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
3030         assert_eq!(format!("-{}", lit_to_string(&codemap::dummy_spanned(pos_int))),
3031                    lit_to_string(&codemap::dummy_spanned(neg_int)));
3032     }
3033 }