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