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