]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/print/pprust.rs
555fdc1ff864759a62e01f9790d08a2d79227d7d
[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::ByteStr(v)         => format!("b\"{}\"", v),
263                 token::ByteStrRaw(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 check_expr_bin_needs_paren(&mut self, sub_expr: &ast::Expr,
1559                                       binop: ast::BinOp) -> bool {
1560         match sub_expr.node {
1561             ast::ExprBinary(ref sub_op, _, _) => {
1562                 if ast_util::operator_prec(sub_op.node) <
1563                     ast_util::operator_prec(binop.node) {
1564                     true
1565                 } else {
1566                     false
1567                 }
1568             }
1569             _ => true
1570         }
1571     }
1572
1573     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> io::Result<()> {
1574         let needs_par = needs_parentheses(expr);
1575         if needs_par {
1576             try!(self.popen());
1577         }
1578         try!(self.print_expr(expr));
1579         if needs_par {
1580             try!(self.pclose());
1581         }
1582         Ok(())
1583     }
1584
1585     fn print_expr_box(&mut self,
1586                       place: &Option<P<ast::Expr>>,
1587                       expr: &ast::Expr) -> io::Result<()> {
1588         try!(word(&mut self.s, "box"));
1589         try!(word(&mut self.s, "("));
1590         try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
1591         try!(self.word_space(")"));
1592         self.print_expr(expr)
1593     }
1594
1595     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> io::Result<()> {
1596         try!(self.ibox(indent_unit));
1597         try!(word(&mut self.s, "["));
1598         try!(self.commasep_exprs(Inconsistent, &exprs[..]));
1599         try!(word(&mut self.s, "]"));
1600         self.end()
1601     }
1602
1603     fn print_expr_repeat(&mut self,
1604                          element: &ast::Expr,
1605                          count: &ast::Expr) -> io::Result<()> {
1606         try!(self.ibox(indent_unit));
1607         try!(word(&mut self.s, "["));
1608         try!(self.print_expr(element));
1609         try!(self.word_space(";"));
1610         try!(self.print_expr(count));
1611         try!(word(&mut self.s, "]"));
1612         self.end()
1613     }
1614
1615     fn print_expr_struct(&mut self,
1616                          path: &ast::Path,
1617                          fields: &[ast::Field],
1618                          wth: &Option<P<ast::Expr>>) -> io::Result<()> {
1619         try!(self.print_path(path, true, 0));
1620         if !(fields.is_empty() && wth.is_none()) {
1621             try!(word(&mut self.s, "{"));
1622             try!(self.commasep_cmnt(
1623                 Consistent,
1624                 &fields[..],
1625                 |s, field| {
1626                     try!(s.ibox(indent_unit));
1627                     try!(s.print_ident(field.ident.node));
1628                     try!(s.word_space(":"));
1629                     try!(s.print_expr(&*field.expr));
1630                     s.end()
1631                 },
1632                 |f| f.span));
1633             match *wth {
1634                 Some(ref expr) => {
1635                     try!(self.ibox(indent_unit));
1636                     if !fields.is_empty() {
1637                         try!(word(&mut self.s, ","));
1638                         try!(space(&mut self.s));
1639                     }
1640                     try!(word(&mut self.s, ".."));
1641                     try!(self.print_expr(&**expr));
1642                     try!(self.end());
1643                 }
1644                 _ => try!(word(&mut self.s, ",")),
1645             }
1646             try!(word(&mut self.s, "}"));
1647         }
1648         Ok(())
1649     }
1650
1651     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> io::Result<()> {
1652         try!(self.popen());
1653         try!(self.commasep_exprs(Inconsistent, &exprs[..]));
1654         if exprs.len() == 1 {
1655             try!(word(&mut self.s, ","));
1656         }
1657         self.pclose()
1658     }
1659
1660     fn print_expr_call(&mut self,
1661                        func: &ast::Expr,
1662                        args: &[P<ast::Expr>]) -> io::Result<()> {
1663         try!(self.print_expr_maybe_paren(func));
1664         self.print_call_post(args)
1665     }
1666
1667     fn print_expr_method_call(&mut self,
1668                               ident: ast::SpannedIdent,
1669                               tys: &[P<ast::Ty>],
1670                               args: &[P<ast::Expr>]) -> io::Result<()> {
1671         let base_args = &args[1..];
1672         try!(self.print_expr(&*args[0]));
1673         try!(word(&mut self.s, "."));
1674         try!(self.print_ident(ident.node));
1675         if !tys.is_empty() {
1676             try!(word(&mut self.s, "::<"));
1677             try!(self.commasep(Inconsistent, tys,
1678                                |s, ty| s.print_type(&**ty)));
1679             try!(word(&mut self.s, ">"));
1680         }
1681         self.print_call_post(base_args)
1682     }
1683
1684     fn print_expr_binary(&mut self,
1685                          op: ast::BinOp,
1686                          lhs: &ast::Expr,
1687                          rhs: &ast::Expr) -> io::Result<()> {
1688         if self.check_expr_bin_needs_paren(lhs, op) {
1689             try!(self.print_expr_maybe_paren(lhs));
1690         } else {
1691             try!(self.print_expr(lhs));
1692         }
1693         try!(space(&mut self.s));
1694         try!(self.word_space(ast_util::binop_to_string(op.node)));
1695         if self.check_expr_bin_needs_paren(rhs, op) {
1696             self.print_expr_maybe_paren(rhs)
1697         } else {
1698             self.print_expr(rhs)
1699         }
1700     }
1701
1702     fn print_expr_unary(&mut self,
1703                         op: ast::UnOp,
1704                         expr: &ast::Expr) -> io::Result<()> {
1705         try!(word(&mut self.s, ast_util::unop_to_string(op)));
1706         self.print_expr_maybe_paren(expr)
1707     }
1708
1709     fn print_expr_addr_of(&mut self,
1710                           mutability: ast::Mutability,
1711                           expr: &ast::Expr) -> io::Result<()> {
1712         try!(word(&mut self.s, "&"));
1713         try!(self.print_mutability(mutability));
1714         self.print_expr_maybe_paren(expr)
1715     }
1716
1717     pub fn print_expr(&mut self, expr: &ast::Expr) -> io::Result<()> {
1718         try!(self.maybe_print_comment(expr.span.lo));
1719         try!(self.ibox(indent_unit));
1720         try!(self.ann.pre(self, NodeExpr(expr)));
1721         match expr.node {
1722             ast::ExprBox(ref place, ref expr) => {
1723                 try!(self.print_expr_box(place, &**expr));
1724             }
1725             ast::ExprVec(ref exprs) => {
1726                 try!(self.print_expr_vec(&exprs[..]));
1727             }
1728             ast::ExprRepeat(ref element, ref count) => {
1729                 try!(self.print_expr_repeat(&**element, &**count));
1730             }
1731             ast::ExprStruct(ref path, ref fields, ref wth) => {
1732                 try!(self.print_expr_struct(path, &fields[..], wth));
1733             }
1734             ast::ExprTup(ref exprs) => {
1735                 try!(self.print_expr_tup(&exprs[..]));
1736             }
1737             ast::ExprCall(ref func, ref args) => {
1738                 try!(self.print_expr_call(&**func, &args[..]));
1739             }
1740             ast::ExprMethodCall(ident, ref tys, ref args) => {
1741                 try!(self.print_expr_method_call(ident, &tys[..], &args[..]));
1742             }
1743             ast::ExprBinary(op, ref lhs, ref rhs) => {
1744                 try!(self.print_expr_binary(op, &**lhs, &**rhs));
1745             }
1746             ast::ExprUnary(op, ref expr) => {
1747                 try!(self.print_expr_unary(op, &**expr));
1748             }
1749             ast::ExprAddrOf(m, ref expr) => {
1750                 try!(self.print_expr_addr_of(m, &**expr));
1751             }
1752             ast::ExprLit(ref lit) => {
1753                 try!(self.print_literal(&**lit));
1754             }
1755             ast::ExprCast(ref expr, ref ty) => {
1756                 if let ast::ExprCast(..) = expr.node {
1757                     try!(self.print_expr(&**expr));
1758                 } else {
1759                     try!(self.print_expr_maybe_paren(&**expr));
1760                 }
1761                 try!(space(&mut self.s));
1762                 try!(self.word_space("as"));
1763                 try!(self.print_type(&**ty));
1764             }
1765             ast::ExprIf(ref test, ref blk, ref elseopt) => {
1766                 try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
1767             }
1768             ast::ExprIfLet(ref pat, ref expr, ref blk, ref elseopt) => {
1769                 try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
1770             }
1771             ast::ExprWhile(ref test, ref blk, opt_ident) => {
1772                 if let Some(ident) = opt_ident {
1773                     try!(self.print_ident(ident));
1774                     try!(self.word_space(":"));
1775                 }
1776                 try!(self.head("while"));
1777                 try!(self.print_expr(&**test));
1778                 try!(space(&mut self.s));
1779                 try!(self.print_block(&**blk));
1780             }
1781             ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
1782                 if let Some(ident) = opt_ident {
1783                     try!(self.print_ident(ident));
1784                     try!(self.word_space(":"));
1785                 }
1786                 try!(self.head("while let"));
1787                 try!(self.print_pat(&**pat));
1788                 try!(space(&mut self.s));
1789                 try!(self.word_space("="));
1790                 try!(self.print_expr(&**expr));
1791                 try!(space(&mut self.s));
1792                 try!(self.print_block(&**blk));
1793             }
1794             ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
1795                 if let Some(ident) = opt_ident {
1796                     try!(self.print_ident(ident));
1797                     try!(self.word_space(":"));
1798                 }
1799                 try!(self.head("for"));
1800                 try!(self.print_pat(&**pat));
1801                 try!(space(&mut self.s));
1802                 try!(self.word_space("in"));
1803                 try!(self.print_expr(&**iter));
1804                 try!(space(&mut self.s));
1805                 try!(self.print_block(&**blk));
1806             }
1807             ast::ExprLoop(ref blk, opt_ident) => {
1808                 if let Some(ident) = opt_ident {
1809                     try!(self.print_ident(ident));
1810                     try!(self.word_space(":"));
1811                 }
1812                 try!(self.head("loop"));
1813                 try!(space(&mut self.s));
1814                 try!(self.print_block(&**blk));
1815             }
1816             ast::ExprMatch(ref expr, ref arms, _) => {
1817                 try!(self.cbox(indent_unit));
1818                 try!(self.ibox(4));
1819                 try!(self.word_nbsp("match"));
1820                 try!(self.print_expr(&**expr));
1821                 try!(space(&mut self.s));
1822                 try!(self.bopen());
1823                 for arm in arms {
1824                     try!(self.print_arm(arm));
1825                 }
1826                 try!(self.bclose_(expr.span, indent_unit));
1827             }
1828             ast::ExprClosure(capture_clause, ref decl, ref body) => {
1829                 try!(self.print_capture_clause(capture_clause));
1830
1831                 try!(self.print_fn_block_args(&**decl));
1832                 try!(space(&mut self.s));
1833
1834                 let default_return = match decl.output {
1835                     ast::DefaultReturn(..) => true,
1836                     _ => false
1837                 };
1838
1839                 if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
1840                     try!(self.print_block_unclosed(&**body));
1841                 } else {
1842                     // we extract the block, so as not to create another set of boxes
1843                     match body.expr.as_ref().unwrap().node {
1844                         ast::ExprBlock(ref blk) => {
1845                             try!(self.print_block_unclosed(&**blk));
1846                         }
1847                         _ => {
1848                             // this is a bare expression
1849                             try!(self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap()));
1850                             try!(self.end()); // need to close a box
1851                         }
1852                     }
1853                 }
1854                 // a box will be closed by print_expr, but we didn't want an overall
1855                 // wrapper so we closed the corresponding opening. so create an
1856                 // empty box to satisfy the close.
1857                 try!(self.ibox(0));
1858             }
1859             ast::ExprBlock(ref blk) => {
1860                 // containing cbox, will be closed by print-block at }
1861                 try!(self.cbox(indent_unit));
1862                 // head-box, will be closed by print-block after {
1863                 try!(self.ibox(0));
1864                 try!(self.print_block(&**blk));
1865             }
1866             ast::ExprAssign(ref lhs, ref rhs) => {
1867                 try!(self.print_expr(&**lhs));
1868                 try!(space(&mut self.s));
1869                 try!(self.word_space("="));
1870                 try!(self.print_expr(&**rhs));
1871             }
1872             ast::ExprAssignOp(op, ref lhs, ref rhs) => {
1873                 try!(self.print_expr(&**lhs));
1874                 try!(space(&mut self.s));
1875                 try!(word(&mut self.s, ast_util::binop_to_string(op.node)));
1876                 try!(self.word_space("="));
1877                 try!(self.print_expr(&**rhs));
1878             }
1879             ast::ExprField(ref expr, id) => {
1880                 try!(self.print_expr(&**expr));
1881                 try!(word(&mut self.s, "."));
1882                 try!(self.print_ident(id.node));
1883             }
1884             ast::ExprTupField(ref expr, id) => {
1885                 try!(self.print_expr(&**expr));
1886                 try!(word(&mut self.s, "."));
1887                 try!(self.print_usize(id.node));
1888             }
1889             ast::ExprIndex(ref expr, ref index) => {
1890                 try!(self.print_expr(&**expr));
1891                 try!(word(&mut self.s, "["));
1892                 try!(self.print_expr(&**index));
1893                 try!(word(&mut self.s, "]"));
1894             }
1895             ast::ExprRange(ref start, ref end) => {
1896                 if let &Some(ref e) = start {
1897                     try!(self.print_expr(&**e));
1898                 }
1899                 try!(word(&mut self.s, ".."));
1900                 if let &Some(ref e) = end {
1901                     try!(self.print_expr(&**e));
1902                 }
1903             }
1904             ast::ExprPath(None, ref path) => {
1905                 try!(self.print_path(path, true, 0))
1906             }
1907             ast::ExprPath(Some(ref qself), ref path) => {
1908                 try!(self.print_qpath(path, qself, true))
1909             }
1910             ast::ExprBreak(opt_ident) => {
1911                 try!(word(&mut self.s, "break"));
1912                 try!(space(&mut self.s));
1913                 if let Some(ident) = opt_ident {
1914                     try!(self.print_ident(ident.node));
1915                     try!(space(&mut self.s));
1916                 }
1917             }
1918             ast::ExprAgain(opt_ident) => {
1919                 try!(word(&mut self.s, "continue"));
1920                 try!(space(&mut self.s));
1921                 if let Some(ident) = opt_ident {
1922                     try!(self.print_ident(ident.node));
1923                     try!(space(&mut self.s))
1924                 }
1925             }
1926             ast::ExprRet(ref result) => {
1927                 try!(word(&mut self.s, "return"));
1928                 match *result {
1929                     Some(ref expr) => {
1930                         try!(word(&mut self.s, " "));
1931                         try!(self.print_expr(&**expr));
1932                     }
1933                     _ => ()
1934                 }
1935             }
1936             ast::ExprInlineAsm(ref a) => {
1937                 try!(word(&mut self.s, "asm!"));
1938                 try!(self.popen());
1939                 try!(self.print_string(&a.asm, a.asm_str_style));
1940                 try!(self.word_space(":"));
1941
1942                 try!(self.commasep(Inconsistent, &a.outputs,
1943                                    |s, &(ref co, ref o, is_rw)| {
1944                     match co.slice_shift_char() {
1945                         Some(('=', operand)) if is_rw => {
1946                             try!(s.print_string(&format!("+{}", operand),
1947                                                 ast::CookedStr))
1948                         }
1949                         _ => try!(s.print_string(&co, ast::CookedStr))
1950                     }
1951                     try!(s.popen());
1952                     try!(s.print_expr(&**o));
1953                     try!(s.pclose());
1954                     Ok(())
1955                 }));
1956                 try!(space(&mut self.s));
1957                 try!(self.word_space(":"));
1958
1959                 try!(self.commasep(Inconsistent, &a.inputs,
1960                                    |s, &(ref co, ref o)| {
1961                     try!(s.print_string(&co, ast::CookedStr));
1962                     try!(s.popen());
1963                     try!(s.print_expr(&**o));
1964                     try!(s.pclose());
1965                     Ok(())
1966                 }));
1967                 try!(space(&mut self.s));
1968                 try!(self.word_space(":"));
1969
1970                 try!(self.commasep(Inconsistent, &a.clobbers,
1971                                    |s, co| {
1972                     try!(s.print_string(&co, ast::CookedStr));
1973                     Ok(())
1974                 }));
1975
1976                 let mut options = vec!();
1977                 if a.volatile {
1978                     options.push("volatile");
1979                 }
1980                 if a.alignstack {
1981                     options.push("alignstack");
1982                 }
1983                 if a.dialect == ast::AsmDialect::AsmIntel {
1984                     options.push("intel");
1985                 }
1986
1987                 if !options.is_empty() {
1988                     try!(space(&mut self.s));
1989                     try!(self.word_space(":"));
1990                     try!(self.commasep(Inconsistent, &*options,
1991                                        |s, &co| {
1992                         try!(s.print_string(co, ast::CookedStr));
1993                         Ok(())
1994                     }));
1995                 }
1996
1997                 try!(self.pclose());
1998             }
1999             ast::ExprMac(ref m) => try!(self.print_mac(m, token::Paren)),
2000             ast::ExprParen(ref e) => {
2001                 try!(self.popen());
2002                 try!(self.print_expr(&**e));
2003                 try!(self.pclose());
2004             }
2005         }
2006         try!(self.ann.post(self, NodeExpr(expr)));
2007         self.end()
2008     }
2009
2010     pub fn print_local_decl(&mut self, loc: &ast::Local) -> io::Result<()> {
2011         try!(self.print_pat(&*loc.pat));
2012         if let Some(ref ty) = loc.ty {
2013             try!(self.word_space(":"));
2014             try!(self.print_type(&**ty));
2015         }
2016         Ok(())
2017     }
2018
2019     pub fn print_decl(&mut self, decl: &ast::Decl) -> io::Result<()> {
2020         try!(self.maybe_print_comment(decl.span.lo));
2021         match decl.node {
2022             ast::DeclLocal(ref loc) => {
2023                 try!(self.space_if_not_bol());
2024                 try!(self.ibox(indent_unit));
2025                 try!(self.word_nbsp("let"));
2026
2027                 try!(self.ibox(indent_unit));
2028                 try!(self.print_local_decl(&**loc));
2029                 try!(self.end());
2030                 if let Some(ref init) = loc.init {
2031                     try!(self.nbsp());
2032                     try!(self.word_space("="));
2033                     try!(self.print_expr(&**init));
2034                 }
2035                 self.end()
2036             }
2037             ast::DeclItem(ref item) => self.print_item(&**item)
2038         }
2039     }
2040
2041     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
2042         try!(word(&mut self.s, &ident.name.as_str()));
2043         self.ann.post(self, NodeIdent(&ident))
2044     }
2045
2046     pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
2047         word(&mut self.s, &i.to_string())
2048     }
2049
2050     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
2051         try!(word(&mut self.s, &name.as_str()));
2052         self.ann.post(self, NodeName(&name))
2053     }
2054
2055     pub fn print_for_decl(&mut self, loc: &ast::Local,
2056                           coll: &ast::Expr) -> io::Result<()> {
2057         try!(self.print_local_decl(loc));
2058         try!(space(&mut self.s));
2059         try!(self.word_space("in"));
2060         self.print_expr(coll)
2061     }
2062
2063     fn print_path(&mut self,
2064                   path: &ast::Path,
2065                   colons_before_params: bool,
2066                   depth: usize)
2067                   -> io::Result<()>
2068     {
2069         try!(self.maybe_print_comment(path.span.lo));
2070
2071         let mut first = !path.global;
2072         for segment in &path.segments[..path.segments.len()-depth] {
2073             if first {
2074                 first = false
2075             } else {
2076                 try!(word(&mut self.s, "::"))
2077             }
2078
2079             try!(self.print_ident(segment.identifier));
2080
2081             try!(self.print_path_parameters(&segment.parameters, colons_before_params));
2082         }
2083
2084         Ok(())
2085     }
2086
2087     fn print_qpath(&mut self,
2088                    path: &ast::Path,
2089                    qself: &ast::QSelf,
2090                    colons_before_params: bool)
2091                    -> io::Result<()>
2092     {
2093         try!(word(&mut self.s, "<"));
2094         try!(self.print_type(&qself.ty));
2095         if qself.position > 0 {
2096             try!(space(&mut self.s));
2097             try!(self.word_space("as"));
2098             let depth = path.segments.len() - qself.position;
2099             try!(self.print_path(&path, false, depth));
2100         }
2101         try!(word(&mut self.s, ">"));
2102         try!(word(&mut self.s, "::"));
2103         let item_segment = path.segments.last().unwrap();
2104         try!(self.print_ident(item_segment.identifier));
2105         self.print_path_parameters(&item_segment.parameters, colons_before_params)
2106     }
2107
2108     fn print_path_parameters(&mut self,
2109                              parameters: &ast::PathParameters,
2110                              colons_before_params: bool)
2111                              -> io::Result<()>
2112     {
2113         if parameters.is_empty() {
2114             return Ok(());
2115         }
2116
2117         if colons_before_params {
2118             try!(word(&mut self.s, "::"))
2119         }
2120
2121         match *parameters {
2122             ast::AngleBracketedParameters(ref data) => {
2123                 try!(word(&mut self.s, "<"));
2124
2125                 let mut comma = false;
2126                 for lifetime in &data.lifetimes {
2127                     if comma {
2128                         try!(self.word_space(","))
2129                     }
2130                     try!(self.print_lifetime(lifetime));
2131                     comma = true;
2132                 }
2133
2134                 if !data.types.is_empty() {
2135                     if comma {
2136                         try!(self.word_space(","))
2137                     }
2138                     try!(self.commasep(
2139                         Inconsistent,
2140                         &data.types,
2141                         |s, ty| s.print_type(&**ty)));
2142                         comma = true;
2143                 }
2144
2145                 for binding in data.bindings.iter() {
2146                     if comma {
2147                         try!(self.word_space(","))
2148                     }
2149                     try!(self.print_ident(binding.ident));
2150                     try!(space(&mut self.s));
2151                     try!(self.word_space("="));
2152                     try!(self.print_type(&*binding.ty));
2153                     comma = true;
2154                 }
2155
2156                 try!(word(&mut self.s, ">"))
2157             }
2158
2159             ast::ParenthesizedParameters(ref data) => {
2160                 try!(word(&mut self.s, "("));
2161                 try!(self.commasep(
2162                     Inconsistent,
2163                     &data.inputs,
2164                     |s, ty| s.print_type(&**ty)));
2165                 try!(word(&mut self.s, ")"));
2166
2167                 match data.output {
2168                     None => { }
2169                     Some(ref ty) => {
2170                         try!(self.space_if_not_bol());
2171                         try!(self.word_space("->"));
2172                         try!(self.print_type(&**ty));
2173                     }
2174                 }
2175             }
2176         }
2177
2178         Ok(())
2179     }
2180
2181     pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
2182         try!(self.maybe_print_comment(pat.span.lo));
2183         try!(self.ann.pre(self, NodePat(pat)));
2184         /* Pat isn't normalized, but the beauty of it
2185          is that it doesn't matter */
2186         match pat.node {
2187             ast::PatWild(ast::PatWildSingle) => try!(word(&mut self.s, "_")),
2188             ast::PatWild(ast::PatWildMulti) => try!(word(&mut self.s, "..")),
2189             ast::PatIdent(binding_mode, ref path1, ref sub) => {
2190                 match binding_mode {
2191                     ast::BindByRef(mutbl) => {
2192                         try!(self.word_nbsp("ref"));
2193                         try!(self.print_mutability(mutbl));
2194                     }
2195                     ast::BindByValue(ast::MutImmutable) => {}
2196                     ast::BindByValue(ast::MutMutable) => {
2197                         try!(self.word_nbsp("mut"));
2198                     }
2199                 }
2200                 try!(self.print_ident(path1.node));
2201                 match *sub {
2202                     Some(ref p) => {
2203                         try!(word(&mut self.s, "@"));
2204                         try!(self.print_pat(&**p));
2205                     }
2206                     None => ()
2207                 }
2208             }
2209             ast::PatEnum(ref path, ref args_) => {
2210                 try!(self.print_path(path, true, 0));
2211                 match *args_ {
2212                     None => try!(word(&mut self.s, "(..)")),
2213                     Some(ref args) => {
2214                         if !args.is_empty() {
2215                             try!(self.popen());
2216                             try!(self.commasep(Inconsistent, &args[..],
2217                                               |s, p| s.print_pat(&**p)));
2218                             try!(self.pclose());
2219                         }
2220                     }
2221                 }
2222             }
2223             ast::PatQPath(ref qself, ref path) => {
2224                 try!(self.print_qpath(path, qself, false));
2225             }
2226             ast::PatStruct(ref path, ref fields, etc) => {
2227                 try!(self.print_path(path, true, 0));
2228                 try!(self.nbsp());
2229                 try!(self.word_space("{"));
2230                 try!(self.commasep_cmnt(
2231                     Consistent, &fields[..],
2232                     |s, f| {
2233                         try!(s.cbox(indent_unit));
2234                         if !f.node.is_shorthand {
2235                             try!(s.print_ident(f.node.ident));
2236                             try!(s.word_nbsp(":"));
2237                         }
2238                         try!(s.print_pat(&*f.node.pat));
2239                         s.end()
2240                     },
2241                     |f| f.node.pat.span));
2242                 if etc {
2243                     if !fields.is_empty() { try!(self.word_space(",")); }
2244                     try!(word(&mut self.s, ".."));
2245                 }
2246                 try!(space(&mut self.s));
2247                 try!(word(&mut self.s, "}"));
2248             }
2249             ast::PatTup(ref elts) => {
2250                 try!(self.popen());
2251                 try!(self.commasep(Inconsistent,
2252                                    &elts[..],
2253                                    |s, p| s.print_pat(&**p)));
2254                 if elts.len() == 1 {
2255                     try!(word(&mut self.s, ","));
2256                 }
2257                 try!(self.pclose());
2258             }
2259             ast::PatBox(ref inner) => {
2260                 try!(word(&mut self.s, "box "));
2261                 try!(self.print_pat(&**inner));
2262             }
2263             ast::PatRegion(ref inner, mutbl) => {
2264                 try!(word(&mut self.s, "&"));
2265                 if mutbl == ast::MutMutable {
2266                     try!(word(&mut self.s, "mut "));
2267                 }
2268                 try!(self.print_pat(&**inner));
2269             }
2270             ast::PatLit(ref e) => try!(self.print_expr(&**e)),
2271             ast::PatRange(ref begin, ref end) => {
2272                 try!(self.print_expr(&**begin));
2273                 try!(space(&mut self.s));
2274                 try!(word(&mut self.s, "..."));
2275                 try!(self.print_expr(&**end));
2276             }
2277             ast::PatVec(ref before, ref slice, ref after) => {
2278                 try!(word(&mut self.s, "["));
2279                 try!(self.commasep(Inconsistent,
2280                                    &before[..],
2281                                    |s, p| s.print_pat(&**p)));
2282                 if let Some(ref p) = *slice {
2283                     if !before.is_empty() { try!(self.word_space(",")); }
2284                     try!(self.print_pat(&**p));
2285                     match **p {
2286                         ast::Pat { node: ast::PatWild(ast::PatWildMulti), .. } => {
2287                             // this case is handled by print_pat
2288                         }
2289                         _ => try!(word(&mut self.s, "..")),
2290                     }
2291                     if !after.is_empty() { try!(self.word_space(",")); }
2292                 }
2293                 try!(self.commasep(Inconsistent,
2294                                    &after[..],
2295                                    |s, p| s.print_pat(&**p)));
2296                 try!(word(&mut self.s, "]"));
2297             }
2298             ast::PatMac(ref m) => try!(self.print_mac(m, token::Paren)),
2299         }
2300         self.ann.post(self, NodePat(pat))
2301     }
2302
2303     fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
2304         // I have no idea why this check is necessary, but here it
2305         // is :(
2306         if arm.attrs.is_empty() {
2307             try!(space(&mut self.s));
2308         }
2309         try!(self.cbox(indent_unit));
2310         try!(self.ibox(0));
2311         try!(self.print_outer_attributes(&arm.attrs));
2312         let mut first = true;
2313         for p in &arm.pats {
2314             if first {
2315                 first = false;
2316             } else {
2317                 try!(space(&mut self.s));
2318                 try!(self.word_space("|"));
2319             }
2320             try!(self.print_pat(&**p));
2321         }
2322         try!(space(&mut self.s));
2323         if let Some(ref e) = arm.guard {
2324             try!(self.word_space("if"));
2325             try!(self.print_expr(&**e));
2326             try!(space(&mut self.s));
2327         }
2328         try!(self.word_space("=>"));
2329
2330         match arm.body.node {
2331             ast::ExprBlock(ref blk) => {
2332                 // the block will close the pattern's ibox
2333                 try!(self.print_block_unclosed_indent(&**blk, indent_unit));
2334
2335                 // If it is a user-provided unsafe block, print a comma after it
2336                 if let ast::UnsafeBlock(ast::UserProvided) = blk.rules {
2337                     try!(word(&mut self.s, ","));
2338                 }
2339             }
2340             _ => {
2341                 try!(self.end()); // close the ibox for the pattern
2342                 try!(self.print_expr(&*arm.body));
2343                 try!(word(&mut self.s, ","));
2344             }
2345         }
2346         self.end() // close enclosing cbox
2347     }
2348
2349     // Returns whether it printed anything
2350     fn print_explicit_self(&mut self,
2351                            explicit_self: &ast::ExplicitSelf_,
2352                            mutbl: ast::Mutability) -> io::Result<bool> {
2353         try!(self.print_mutability(mutbl));
2354         match *explicit_self {
2355             ast::SelfStatic => { return Ok(false); }
2356             ast::SelfValue(_) => {
2357                 try!(word(&mut self.s, "self"));
2358             }
2359             ast::SelfRegion(ref lt, m, _) => {
2360                 try!(word(&mut self.s, "&"));
2361                 try!(self.print_opt_lifetime(lt));
2362                 try!(self.print_mutability(m));
2363                 try!(word(&mut self.s, "self"));
2364             }
2365             ast::SelfExplicit(ref typ, _) => {
2366                 try!(word(&mut self.s, "self"));
2367                 try!(self.word_space(":"));
2368                 try!(self.print_type(&**typ));
2369             }
2370         }
2371         return Ok(true);
2372     }
2373
2374     pub fn print_fn(&mut self,
2375                     decl: &ast::FnDecl,
2376                     unsafety: ast::Unsafety,
2377                     constness: ast::Constness,
2378                     abi: abi::Abi,
2379                     name: Option<ast::Ident>,
2380                     generics: &ast::Generics,
2381                     opt_explicit_self: Option<&ast::ExplicitSelf_>,
2382                     vis: ast::Visibility) -> io::Result<()> {
2383         try!(self.print_fn_header_info(unsafety, constness, abi, vis));
2384
2385         if let Some(name) = name {
2386             try!(self.nbsp());
2387             try!(self.print_ident(name));
2388         }
2389         try!(self.print_generics(generics));
2390         try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
2391         self.print_where_clause(&generics.where_clause)
2392     }
2393
2394     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
2395                          opt_explicit_self: Option<&ast::ExplicitSelf_>)
2396         -> io::Result<()> {
2397         // It is unfortunate to duplicate the commasep logic, but we want the
2398         // self type and the args all in the same box.
2399         try!(self.rbox(0, Inconsistent));
2400         let mut first = true;
2401         if let Some(explicit_self) = opt_explicit_self {
2402             let m = match explicit_self {
2403                 &ast::SelfStatic => ast::MutImmutable,
2404                 _ => match decl.inputs[0].pat.node {
2405                     ast::PatIdent(ast::BindByValue(m), _, _) => m,
2406                     _ => ast::MutImmutable
2407                 }
2408             };
2409             first = !try!(self.print_explicit_self(explicit_self, m));
2410         }
2411
2412         // HACK(eddyb) ignore the separately printed self argument.
2413         let args = if first {
2414             &decl.inputs[..]
2415         } else {
2416             &decl.inputs[1..]
2417         };
2418
2419         for arg in args {
2420             if first { first = false; } else { try!(self.word_space(",")); }
2421             try!(self.print_arg(arg));
2422         }
2423
2424         self.end()
2425     }
2426
2427     pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl,
2428                                  opt_explicit_self: Option<&ast::ExplicitSelf_>)
2429         -> io::Result<()> {
2430         try!(self.popen());
2431         try!(self.print_fn_args(decl, opt_explicit_self));
2432         if decl.variadic {
2433             try!(word(&mut self.s, ", ..."));
2434         }
2435         try!(self.pclose());
2436
2437         self.print_fn_output(decl)
2438     }
2439
2440     pub fn print_fn_block_args(
2441             &mut self,
2442             decl: &ast::FnDecl)
2443             -> io::Result<()> {
2444         try!(word(&mut self.s, "|"));
2445         try!(self.print_fn_args(decl, None));
2446         try!(word(&mut self.s, "|"));
2447
2448         if let ast::DefaultReturn(..) = decl.output {
2449             return Ok(());
2450         }
2451
2452         try!(self.space_if_not_bol());
2453         try!(self.word_space("->"));
2454         match decl.output {
2455             ast::Return(ref ty) => {
2456                 try!(self.print_type(&**ty));
2457                 self.maybe_print_comment(ty.span.lo)
2458             }
2459             ast::DefaultReturn(..) => unreachable!(),
2460             ast::NoReturn(span) => {
2461                 try!(self.word_nbsp("!"));
2462                 self.maybe_print_comment(span.lo)
2463             }
2464         }
2465     }
2466
2467     pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureClause)
2468                                 -> io::Result<()> {
2469         match capture_clause {
2470             ast::CaptureByValue => self.word_space("move"),
2471             ast::CaptureByRef => Ok(()),
2472         }
2473     }
2474
2475     pub fn print_bounds(&mut self,
2476                         prefix: &str,
2477                         bounds: &[ast::TyParamBound])
2478                         -> io::Result<()> {
2479         if !bounds.is_empty() {
2480             try!(word(&mut self.s, prefix));
2481             let mut first = true;
2482             for bound in bounds {
2483                 try!(self.nbsp());
2484                 if first {
2485                     first = false;
2486                 } else {
2487                     try!(self.word_space("+"));
2488                 }
2489
2490                 try!(match *bound {
2491                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
2492                         self.print_poly_trait_ref(tref)
2493                     }
2494                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
2495                         try!(word(&mut self.s, "?"));
2496                         self.print_poly_trait_ref(tref)
2497                     }
2498                     RegionTyParamBound(ref lt) => {
2499                         self.print_lifetime(lt)
2500                     }
2501                 })
2502             }
2503             Ok(())
2504         } else {
2505             Ok(())
2506         }
2507     }
2508
2509     pub fn print_lifetime(&mut self,
2510                           lifetime: &ast::Lifetime)
2511                           -> io::Result<()>
2512     {
2513         self.print_name(lifetime.name)
2514     }
2515
2516     pub fn print_lifetime_def(&mut self,
2517                               lifetime: &ast::LifetimeDef)
2518                               -> io::Result<()>
2519     {
2520         try!(self.print_lifetime(&lifetime.lifetime));
2521         let mut sep = ":";
2522         for v in &lifetime.bounds {
2523             try!(word(&mut self.s, sep));
2524             try!(self.print_lifetime(v));
2525             sep = "+";
2526         }
2527         Ok(())
2528     }
2529
2530     pub fn print_generics(&mut self,
2531                           generics: &ast::Generics)
2532                           -> io::Result<()>
2533     {
2534         let total = generics.lifetimes.len() + generics.ty_params.len();
2535         if total == 0 {
2536             return Ok(());
2537         }
2538
2539         try!(word(&mut self.s, "<"));
2540
2541         let mut ints = Vec::new();
2542         for i in 0..total {
2543             ints.push(i);
2544         }
2545
2546         try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
2547             if idx < generics.lifetimes.len() {
2548                 let lifetime = &generics.lifetimes[idx];
2549                 s.print_lifetime_def(lifetime)
2550             } else {
2551                 let idx = idx - generics.lifetimes.len();
2552                 let param = &generics.ty_params[idx];
2553                 s.print_ty_param(param)
2554             }
2555         }));
2556
2557         try!(word(&mut self.s, ">"));
2558         Ok(())
2559     }
2560
2561     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
2562         try!(self.print_ident(param.ident));
2563         try!(self.print_bounds(":", &param.bounds));
2564         match param.default {
2565             Some(ref default) => {
2566                 try!(space(&mut self.s));
2567                 try!(self.word_space("="));
2568                 self.print_type(&**default)
2569             }
2570             _ => Ok(())
2571         }
2572     }
2573
2574     pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
2575                               -> io::Result<()> {
2576         if where_clause.predicates.is_empty() {
2577             return Ok(())
2578         }
2579
2580         try!(space(&mut self.s));
2581         try!(self.word_space("where"));
2582
2583         for (i, predicate) in where_clause.predicates.iter().enumerate() {
2584             if i != 0 {
2585                 try!(self.word_space(","));
2586             }
2587
2588             match predicate {
2589                 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes,
2590                                                                               ref bounded_ty,
2591                                                                               ref bounds,
2592                                                                               ..}) => {
2593                     try!(self.print_formal_lifetime_list(bound_lifetimes));
2594                     try!(self.print_type(&**bounded_ty));
2595                     try!(self.print_bounds(":", bounds));
2596                 }
2597                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
2598                                                                                 ref bounds,
2599                                                                                 ..}) => {
2600                     try!(self.print_lifetime(lifetime));
2601                     try!(word(&mut self.s, ":"));
2602
2603                     for (i, bound) in bounds.iter().enumerate() {
2604                         try!(self.print_lifetime(bound));
2605
2606                         if i != 0 {
2607                             try!(word(&mut self.s, ":"));
2608                         }
2609                     }
2610                 }
2611                 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
2612                     try!(self.print_path(path, false, 0));
2613                     try!(space(&mut self.s));
2614                     try!(self.word_space("="));
2615                     try!(self.print_type(&**ty));
2616                 }
2617             }
2618         }
2619
2620         Ok(())
2621     }
2622
2623     pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
2624         try!(self.ibox(indent_unit));
2625         match item.node {
2626             ast::MetaWord(ref name) => {
2627                 try!(word(&mut self.s, &name));
2628             }
2629             ast::MetaNameValue(ref name, ref value) => {
2630                 try!(self.word_space(&name[..]));
2631                 try!(self.word_space("="));
2632                 try!(self.print_literal(value));
2633             }
2634             ast::MetaList(ref name, ref items) => {
2635                 try!(word(&mut self.s, &name));
2636                 try!(self.popen());
2637                 try!(self.commasep(Consistent,
2638                                    &items[..],
2639                                    |s, i| s.print_meta_item(&**i)));
2640                 try!(self.pclose());
2641             }
2642         }
2643         self.end()
2644     }
2645
2646     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
2647         match vp.node {
2648             ast::ViewPathSimple(ident, ref path) => {
2649                 try!(self.print_path(path, false, 0));
2650
2651                 // FIXME(#6993) can't compare identifiers directly here
2652                 if path.segments.last().unwrap().identifier.name !=
2653                         ident.name {
2654                     try!(space(&mut self.s));
2655                     try!(self.word_space("as"));
2656                     try!(self.print_ident(ident));
2657                 }
2658
2659                 Ok(())
2660             }
2661
2662             ast::ViewPathGlob(ref path) => {
2663                 try!(self.print_path(path, false, 0));
2664                 word(&mut self.s, "::*")
2665             }
2666
2667             ast::ViewPathList(ref path, ref idents) => {
2668                 if path.segments.is_empty() {
2669                     try!(word(&mut self.s, "{"));
2670                 } else {
2671                     try!(self.print_path(path, false, 0));
2672                     try!(word(&mut self.s, "::{"));
2673                 }
2674                 try!(self.commasep(Inconsistent, &idents[..], |s, w| {
2675                     match w.node {
2676                         ast::PathListIdent { name, rename, .. } => {
2677                             try!(s.print_ident(name));
2678                             if let Some(ident) = rename {
2679                                 try!(space(&mut s.s));
2680                                 try!(s.word_space("as"));
2681                                 try!(s.print_ident(ident));
2682                             }
2683                             Ok(())
2684                         },
2685                         ast::PathListMod { rename, .. } => {
2686                             try!(word(&mut s.s, "self"));
2687                             if let Some(ident) = rename {
2688                                 try!(space(&mut s.s));
2689                                 try!(s.word_space("as"));
2690                                 try!(s.print_ident(ident));
2691                             }
2692                             Ok(())
2693                         }
2694                     }
2695                 }));
2696                 word(&mut self.s, "}")
2697             }
2698         }
2699     }
2700
2701     pub fn print_mutability(&mut self,
2702                             mutbl: ast::Mutability) -> io::Result<()> {
2703         match mutbl {
2704             ast::MutMutable => self.word_nbsp("mut"),
2705             ast::MutImmutable => Ok(()),
2706         }
2707     }
2708
2709     pub fn print_mt(&mut self, mt: &ast::MutTy) -> io::Result<()> {
2710         try!(self.print_mutability(mt.mutbl));
2711         self.print_type(&*mt.ty)
2712     }
2713
2714     pub fn print_arg(&mut self, input: &ast::Arg) -> io::Result<()> {
2715         try!(self.ibox(indent_unit));
2716         match input.ty.node {
2717             ast::TyInfer => try!(self.print_pat(&*input.pat)),
2718             _ => {
2719                 match input.pat.node {
2720                     ast::PatIdent(_, ref path1, _) if
2721                         path1.node.name ==
2722                             parse::token::special_idents::invalid.name => {
2723                         // Do nothing.
2724                     }
2725                     _ => {
2726                         try!(self.print_pat(&*input.pat));
2727                         try!(word(&mut self.s, ":"));
2728                         try!(space(&mut self.s));
2729                     }
2730                 }
2731                 try!(self.print_type(&*input.ty));
2732             }
2733         }
2734         self.end()
2735     }
2736
2737     pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> io::Result<()> {
2738         if let ast::DefaultReturn(..) = decl.output {
2739             return Ok(());
2740         }
2741
2742         try!(self.space_if_not_bol());
2743         try!(self.ibox(indent_unit));
2744         try!(self.word_space("->"));
2745         match decl.output {
2746             ast::NoReturn(_) =>
2747                 try!(self.word_nbsp("!")),
2748             ast::DefaultReturn(..) => unreachable!(),
2749             ast::Return(ref ty) =>
2750                 try!(self.print_type(&**ty))
2751         }
2752         try!(self.end());
2753
2754         match decl.output {
2755             ast::Return(ref output) => self.maybe_print_comment(output.span.lo),
2756             _ => Ok(())
2757         }
2758     }
2759
2760     pub fn print_ty_fn(&mut self,
2761                        abi: abi::Abi,
2762                        unsafety: ast::Unsafety,
2763                        decl: &ast::FnDecl,
2764                        name: Option<ast::Ident>,
2765                        generics: &ast::Generics,
2766                        opt_explicit_self: Option<&ast::ExplicitSelf_>)
2767                        -> io::Result<()> {
2768         try!(self.ibox(indent_unit));
2769         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
2770             try!(word(&mut self.s, "for"));
2771             try!(self.print_generics(generics));
2772         }
2773         let generics = ast::Generics {
2774             lifetimes: Vec::new(),
2775             ty_params: OwnedSlice::empty(),
2776             where_clause: ast::WhereClause {
2777                 id: ast::DUMMY_NODE_ID,
2778                 predicates: Vec::new(),
2779             },
2780         };
2781         try!(self.print_fn(decl,
2782                            unsafety,
2783                            ast::Constness::NotConst,
2784                            abi,
2785                            name,
2786                            &generics,
2787                            opt_explicit_self,
2788                            ast::Inherited));
2789         self.end()
2790     }
2791
2792     pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
2793                                         next_pos: Option<BytePos>)
2794         -> io::Result<()> {
2795         let cm = match self.cm {
2796             Some(cm) => cm,
2797             _ => return Ok(())
2798         };
2799         match self.next_comment() {
2800             Some(ref cmnt) => {
2801                 if (*cmnt).style != comments::Trailing { return Ok(()) }
2802                 let span_line = cm.lookup_char_pos(span.hi);
2803                 let comment_line = cm.lookup_char_pos((*cmnt).pos);
2804                 let mut next = (*cmnt).pos + BytePos(1);
2805                 match next_pos { None => (), Some(p) => next = p }
2806                 if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
2807                     span_line.line == comment_line.line {
2808                         try!(self.print_comment(cmnt));
2809                         self.cur_cmnt_and_lit.cur_cmnt += 1;
2810                     }
2811             }
2812             _ => ()
2813         }
2814         Ok(())
2815     }
2816
2817     pub fn print_remaining_comments(&mut self) -> io::Result<()> {
2818         // If there aren't any remaining comments, then we need to manually
2819         // make sure there is a line break at the end.
2820         if self.next_comment().is_none() {
2821             try!(hardbreak(&mut self.s));
2822         }
2823         loop {
2824             match self.next_comment() {
2825                 Some(ref cmnt) => {
2826                     try!(self.print_comment(cmnt));
2827                     self.cur_cmnt_and_lit.cur_cmnt += 1;
2828                 }
2829                 _ => break
2830             }
2831         }
2832         Ok(())
2833     }
2834
2835     pub fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
2836         try!(self.maybe_print_comment(lit.span.lo));
2837         match self.next_lit(lit.span.lo) {
2838             Some(ref ltrl) => {
2839                 return word(&mut self.s, &(*ltrl).lit);
2840             }
2841             _ => ()
2842         }
2843         match lit.node {
2844             ast::LitStr(ref st, style) => self.print_string(&st, style),
2845             ast::LitByte(byte) => {
2846                 let mut res = String::from("b'");
2847                 res.extend(ascii::escape_default(byte).map(|c| c as char));
2848                 res.push('\'');
2849                 word(&mut self.s, &res[..])
2850             }
2851             ast::LitChar(ch) => {
2852                 let mut res = String::from("'");
2853                 res.extend(ch.escape_default());
2854                 res.push('\'');
2855                 word(&mut self.s, &res[..])
2856             }
2857             ast::LitInt(i, t) => {
2858                 match t {
2859                     ast::SignedIntLit(st, ast::Plus) => {
2860                         word(&mut self.s,
2861                              &ast_util::int_ty_to_string(st, Some(i as i64)))
2862                     }
2863                     ast::SignedIntLit(st, ast::Minus) => {
2864                         let istr = ast_util::int_ty_to_string(st, Some(-(i as i64)));
2865                         word(&mut self.s,
2866                              &format!("-{}", istr))
2867                     }
2868                     ast::UnsignedIntLit(ut) => {
2869                         word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i)))
2870                     }
2871                     ast::UnsuffixedIntLit(ast::Plus) => {
2872                         word(&mut self.s, &format!("{}", i))
2873                     }
2874                     ast::UnsuffixedIntLit(ast::Minus) => {
2875                         word(&mut self.s, &format!("-{}", i))
2876                     }
2877                 }
2878             }
2879             ast::LitFloat(ref f, t) => {
2880                 word(&mut self.s,
2881                      &format!(
2882                          "{}{}",
2883                          &f,
2884                          &ast_util::float_ty_to_string(t)))
2885             }
2886             ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]),
2887             ast::LitBool(val) => {
2888                 if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
2889             }
2890             ast::LitByteStr(ref v) => {
2891                 let mut escaped: String = String::new();
2892                 for &ch in v.iter() {
2893                     escaped.extend(ascii::escape_default(ch)
2894                                          .map(|c| c as char));
2895                 }
2896                 word(&mut self.s, &format!("b\"{}\"", escaped))
2897             }
2898         }
2899     }
2900
2901     pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
2902         match self.literals {
2903             Some(ref lits) => {
2904                 while self.cur_cmnt_and_lit.cur_lit < lits.len() {
2905                     let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone();
2906                     if ltrl.pos > pos { return None; }
2907                     self.cur_cmnt_and_lit.cur_lit += 1;
2908                     if ltrl.pos == pos { return Some(ltrl); }
2909                 }
2910                 None
2911             }
2912             _ => None
2913         }
2914     }
2915
2916     pub fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
2917         loop {
2918             match self.next_comment() {
2919                 Some(ref cmnt) => {
2920                     if (*cmnt).pos < pos {
2921                         try!(self.print_comment(cmnt));
2922                         self.cur_cmnt_and_lit.cur_cmnt += 1;
2923                     } else { break; }
2924                 }
2925                 _ => break
2926             }
2927         }
2928         Ok(())
2929     }
2930
2931     pub fn print_comment(&mut self,
2932                          cmnt: &comments::Comment) -> io::Result<()> {
2933         match cmnt.style {
2934             comments::Mixed => {
2935                 assert_eq!(cmnt.lines.len(), 1);
2936                 try!(zerobreak(&mut self.s));
2937                 try!(word(&mut self.s, &cmnt.lines[0]));
2938                 zerobreak(&mut self.s)
2939             }
2940             comments::Isolated => {
2941                 try!(self.hardbreak_if_not_bol());
2942                 for line in &cmnt.lines {
2943                     // Don't print empty lines because they will end up as trailing
2944                     // whitespace
2945                     if !line.is_empty() {
2946                         try!(word(&mut self.s, &line[..]));
2947                     }
2948                     try!(hardbreak(&mut self.s));
2949                 }
2950                 Ok(())
2951             }
2952             comments::Trailing => {
2953                 try!(word(&mut self.s, " "));
2954                 if cmnt.lines.len() == 1 {
2955                     try!(word(&mut self.s, &cmnt.lines[0]));
2956                     hardbreak(&mut self.s)
2957                 } else {
2958                     try!(self.ibox(0));
2959                     for line in &cmnt.lines {
2960                         if !line.is_empty() {
2961                             try!(word(&mut self.s, &line[..]));
2962                         }
2963                         try!(hardbreak(&mut self.s));
2964                     }
2965                     self.end()
2966                 }
2967             }
2968             comments::BlankLine => {
2969                 // We need to do at least one, possibly two hardbreaks.
2970                 let is_semi = match self.s.last_token() {
2971                     pp::Token::String(s, _) => ";" == s,
2972                     _ => false
2973                 };
2974                 if is_semi || self.is_begin() || self.is_end() {
2975                     try!(hardbreak(&mut self.s));
2976                 }
2977                 hardbreak(&mut self.s)
2978             }
2979         }
2980     }
2981
2982     pub fn print_string(&mut self, st: &str,
2983                         style: ast::StrStyle) -> io::Result<()> {
2984         let st = match style {
2985             ast::CookedStr => {
2986                 (format!("\"{}\"", st.escape_default()))
2987             }
2988             ast::RawStr(n) => {
2989                 (format!("r{delim}\"{string}\"{delim}",
2990                          delim=repeat("#", n),
2991                          string=st))
2992             }
2993         };
2994         word(&mut self.s, &st[..])
2995     }
2996
2997     pub fn next_comment(&mut self) -> Option<comments::Comment> {
2998         match self.comments {
2999             Some(ref cmnts) => {
3000                 if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
3001                     Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone())
3002                 } else {
3003                     None
3004                 }
3005             }
3006             _ => None
3007         }
3008     }
3009
3010     pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
3011                                                   opt_abi: Option<abi::Abi>)
3012         -> io::Result<()> {
3013         match opt_abi {
3014             Some(abi::Rust) => Ok(()),
3015             Some(abi) => {
3016                 try!(self.word_nbsp("extern"));
3017                 self.word_nbsp(&abi.to_string())
3018             }
3019             None => Ok(())
3020         }
3021     }
3022
3023     pub fn print_extern_opt_abi(&mut self,
3024                                 opt_abi: Option<abi::Abi>) -> io::Result<()> {
3025         match opt_abi {
3026             Some(abi) => {
3027                 try!(self.word_nbsp("extern"));
3028                 self.word_nbsp(&abi.to_string())
3029             }
3030             None => Ok(())
3031         }
3032     }
3033
3034     pub fn print_fn_header_info(&mut self,
3035                                 unsafety: ast::Unsafety,
3036                                 constness: ast::Constness,
3037                                 abi: abi::Abi,
3038                                 vis: ast::Visibility) -> io::Result<()> {
3039         try!(word(&mut self.s, &visibility_qualified(vis, "")));
3040         try!(self.print_unsafety(unsafety));
3041
3042         match constness {
3043             ast::Constness::NotConst => {}
3044             ast::Constness::Const => try!(self.word_nbsp("const"))
3045         }
3046
3047         if abi != abi::Rust {
3048             try!(self.word_nbsp("extern"));
3049             try!(self.word_nbsp(&abi.to_string()));
3050         }
3051
3052         word(&mut self.s, "fn")
3053     }
3054
3055     pub fn print_unsafety(&mut self, s: ast::Unsafety) -> io::Result<()> {
3056         match s {
3057             ast::Unsafety::Normal => Ok(()),
3058             ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
3059         }
3060     }
3061 }
3062
3063 fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
3064
3065 #[cfg(test)]
3066 mod tests {
3067     use super::*;
3068
3069     use ast;
3070     use ast_util;
3071     use codemap;
3072     use parse::token;
3073
3074     #[test]
3075     fn test_fun_to_string() {
3076         let abba_ident = token::str_to_ident("abba");
3077
3078         let decl = ast::FnDecl {
3079             inputs: Vec::new(),
3080             output: ast::DefaultReturn(codemap::DUMMY_SP),
3081             variadic: false
3082         };
3083         let generics = ast_util::empty_generics();
3084         assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal,
3085                                  ast::Constness::NotConst,
3086                                  abba_ident,
3087                                  None, &generics),
3088                    "fn abba()");
3089     }
3090
3091     #[test]
3092     fn test_variant_to_string() {
3093         let ident = token::str_to_ident("principal_skinner");
3094
3095         let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ {
3096             name: ident,
3097             attrs: Vec::new(),
3098             // making this up as I go.... ?
3099             kind: ast::TupleVariantKind(Vec::new()),
3100             id: 0,
3101             disr_expr: None,
3102             vis: ast::Public,
3103         });
3104
3105         let varstr = variant_to_string(&var);
3106         assert_eq!(varstr, "pub principal_skinner");
3107     }
3108
3109     #[test]
3110     fn test_signed_int_to_string() {
3111         let pos_int = ast::LitInt(42, ast::SignedIntLit(ast::TyI32, ast::Plus));
3112         let neg_int = ast::LitInt((!42 + 1) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
3113         assert_eq!(format!("-{}", lit_to_string(&codemap::dummy_spanned(pos_int))),
3114                    lit_to_string(&codemap::dummy_spanned(neg_int)));
3115     }
3116 }