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