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