1 | use crate::algorithm::Printer; |
2 | use crate::path::PathKind; |
3 | use crate::token::Token; |
4 | use crate::INDENT; |
5 | use proc_macro2::{Delimiter, Spacing, TokenStream}; |
6 | use syn::{Ident, Macro, MacroDelimiter}; |
7 | |
8 | impl Printer { |
9 | pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>, semicolon: bool) { |
10 | if mac.path.is_ident("macro_rules" ) { |
11 | if let Some(ident) = ident { |
12 | self.macro_rules(ident, &mac.tokens); |
13 | return; |
14 | } |
15 | } |
16 | #[cfg (feature = "verbatim" )] |
17 | if ident.is_none() && self.standard_library_macro(mac, semicolon) { |
18 | return; |
19 | } |
20 | self.path(&mac.path, PathKind::Simple); |
21 | self.word("!" ); |
22 | if let Some(ident) = ident { |
23 | self.nbsp(); |
24 | self.ident(ident); |
25 | } |
26 | let (open, close, delimiter_break) = match mac.delimiter { |
27 | MacroDelimiter::Paren(_) => ("(" , ")" , Self::zerobreak as fn(&mut Self)), |
28 | MacroDelimiter::Brace(_) => (" {" , "}" , Self::hardbreak as fn(&mut Self)), |
29 | MacroDelimiter::Bracket(_) => ("[" , "]" , Self::zerobreak as fn(&mut Self)), |
30 | }; |
31 | self.word(open); |
32 | if !mac.tokens.is_empty() { |
33 | self.cbox(INDENT); |
34 | delimiter_break(self); |
35 | self.ibox(0); |
36 | self.macro_rules_tokens(mac.tokens.clone(), false); |
37 | self.end(); |
38 | delimiter_break(self); |
39 | self.offset(-INDENT); |
40 | self.end(); |
41 | } |
42 | self.word(close); |
43 | if semicolon { |
44 | self.word(";" ); |
45 | } |
46 | } |
47 | |
48 | fn macro_rules(&mut self, name: &Ident, rules: &TokenStream) { |
49 | enum State { |
50 | Start, |
51 | Matcher, |
52 | Equal, |
53 | Greater, |
54 | Expander, |
55 | } |
56 | |
57 | use State::*; |
58 | |
59 | self.word("macro_rules! " ); |
60 | self.ident(name); |
61 | self.word(" {" ); |
62 | self.cbox(INDENT); |
63 | self.hardbreak_if_nonempty(); |
64 | let mut state = State::Start; |
65 | for tt in rules.clone() { |
66 | let token = Token::from(tt); |
67 | match (state, token) { |
68 | (Start, Token::Group(delimiter, stream)) => { |
69 | self.delimiter_open(delimiter); |
70 | if !stream.is_empty() { |
71 | self.cbox(INDENT); |
72 | self.zerobreak(); |
73 | self.ibox(0); |
74 | self.macro_rules_tokens(stream, true); |
75 | self.end(); |
76 | self.zerobreak(); |
77 | self.offset(-INDENT); |
78 | self.end(); |
79 | } |
80 | self.delimiter_close(delimiter); |
81 | state = Matcher; |
82 | } |
83 | (Matcher, Token::Punct('=' , Spacing::Joint)) => { |
84 | self.word(" =" ); |
85 | state = Equal; |
86 | } |
87 | (Equal, Token::Punct('>' , Spacing::Alone)) => { |
88 | self.word(">" ); |
89 | state = Greater; |
90 | } |
91 | (Greater, Token::Group(_delimiter, stream)) => { |
92 | self.word(" {" ); |
93 | self.neverbreak(); |
94 | if !stream.is_empty() { |
95 | self.cbox(INDENT); |
96 | self.hardbreak(); |
97 | self.ibox(0); |
98 | self.macro_rules_tokens(stream, false); |
99 | self.end(); |
100 | self.hardbreak(); |
101 | self.offset(-INDENT); |
102 | self.end(); |
103 | } |
104 | self.word("}" ); |
105 | state = Expander; |
106 | } |
107 | (Expander, Token::Punct(';' , Spacing::Alone)) => { |
108 | self.word(";" ); |
109 | self.hardbreak(); |
110 | state = Start; |
111 | } |
112 | _ => unimplemented!("bad macro_rules syntax" ), |
113 | } |
114 | } |
115 | match state { |
116 | Start => {} |
117 | Expander => { |
118 | self.word(";" ); |
119 | self.hardbreak(); |
120 | } |
121 | _ => self.hardbreak(), |
122 | } |
123 | self.offset(-INDENT); |
124 | self.end(); |
125 | self.word("}" ); |
126 | } |
127 | |
128 | pub fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) { |
129 | #[derive (PartialEq)] |
130 | enum State { |
131 | Start, |
132 | Dollar, |
133 | DollarIdent, |
134 | DollarIdentColon, |
135 | DollarParen, |
136 | DollarParenSep, |
137 | Pound, |
138 | PoundBang, |
139 | Dot, |
140 | Colon, |
141 | Colon2, |
142 | Ident, |
143 | IdentBang, |
144 | Delim, |
145 | Other, |
146 | } |
147 | |
148 | use State::*; |
149 | |
150 | let mut state = Start; |
151 | let mut previous_is_joint = true; |
152 | for tt in stream { |
153 | let token = Token::from(tt); |
154 | let (needs_space, next_state) = match (&state, &token) { |
155 | (Dollar, Token::Ident(_)) => (false, if matcher { DollarIdent } else { Other }), |
156 | (DollarIdent, Token::Punct(':' , Spacing::Alone)) => (false, DollarIdentColon), |
157 | (DollarIdentColon, Token::Ident(_)) => (false, Other), |
158 | (DollarParen, Token::Punct('+' | '*' | '?' , Spacing::Alone)) => (false, Other), |
159 | (DollarParen, Token::Ident(_) | Token::Literal(_)) => (false, DollarParenSep), |
160 | (DollarParen, Token::Punct(_, Spacing::Joint)) => (false, DollarParen), |
161 | (DollarParen, Token::Punct(_, Spacing::Alone)) => (false, DollarParenSep), |
162 | (DollarParenSep, Token::Punct('+' | '*' , _)) => (false, Other), |
163 | (Pound, Token::Punct('!' , _)) => (false, PoundBang), |
164 | (Dollar, Token::Group(Delimiter::Parenthesis, _)) => (false, DollarParen), |
165 | (Pound | PoundBang, Token::Group(Delimiter::Bracket, _)) => (false, Other), |
166 | (Ident, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { |
167 | (false, Delim) |
168 | } |
169 | (Ident, Token::Punct('!' , Spacing::Alone)) => (false, IdentBang), |
170 | (IdentBang, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { |
171 | (false, Other) |
172 | } |
173 | (Colon, Token::Punct(':' , _)) => (false, Colon2), |
174 | (_, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => (true, Delim), |
175 | (_, Token::Group(Delimiter::Brace | Delimiter::None, _)) => (true, Other), |
176 | (_, Token::Ident(ident)) if !is_keyword(ident) => { |
177 | (state != Dot && state != Colon2, Ident) |
178 | } |
179 | (_, Token::Literal(lit)) if lit.to_string().ends_with('.' ) => (state != Dot, Other), |
180 | (_, Token::Literal(_)) => (state != Dot, Ident), |
181 | (_, Token::Punct(',' | ';' , _)) => (false, Other), |
182 | (_, Token::Punct('.' , _)) if !matcher => (state != Ident && state != Delim, Dot), |
183 | (_, Token::Punct(':' , Spacing::Joint)) => (state != Ident, Colon), |
184 | (_, Token::Punct('$' , _)) => (true, Dollar), |
185 | (_, Token::Punct('#' , _)) => (true, Pound), |
186 | (_, _) => (true, Other), |
187 | }; |
188 | if !previous_is_joint { |
189 | if needs_space { |
190 | self.space(); |
191 | } else if let Token::Punct('.' , _) = token { |
192 | self.zerobreak(); |
193 | } |
194 | } |
195 | previous_is_joint = match token { |
196 | Token::Punct(_, Spacing::Joint) | Token::Punct('$' , _) => true, |
197 | _ => false, |
198 | }; |
199 | self.single_token( |
200 | token, |
201 | if matcher { |
202 | |printer, stream| printer.macro_rules_tokens(stream, true) |
203 | } else { |
204 | |printer, stream| printer.macro_rules_tokens(stream, false) |
205 | }, |
206 | ); |
207 | state = next_state; |
208 | } |
209 | } |
210 | } |
211 | |
212 | pub(crate) fn requires_semi(delimiter: &MacroDelimiter) -> bool { |
213 | match delimiter { |
214 | MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true, |
215 | MacroDelimiter::Brace(_) => false, |
216 | } |
217 | } |
218 | |
219 | fn is_keyword(ident: &Ident) -> bool { |
220 | match ident.to_string().as_str() { |
221 | "as" | "async" | "await" | "box" | "break" | "const" | "continue" | "crate" | "dyn" |
222 | | "else" | "enum" | "extern" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" |
223 | | "macro" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "static" |
224 | | "struct" | "trait" | "type" | "unsafe" | "use" | "where" | "while" | "yield" => true, |
225 | _ => false, |
226 | } |
227 | } |
228 | |
229 | #[cfg (feature = "verbatim" )] |
230 | mod standard_library { |
231 | use crate::algorithm::Printer; |
232 | use crate::expr; |
233 | use crate::fixup::FixupContext; |
234 | use crate::iter::IterDelimited; |
235 | use crate::path::PathKind; |
236 | use crate::INDENT; |
237 | use syn::ext::IdentExt; |
238 | use syn::parse::{Parse, ParseStream, Parser, Result}; |
239 | use syn::punctuated::Punctuated; |
240 | use syn::{ |
241 | parenthesized, token, Attribute, Expr, ExprAssign, ExprPath, Ident, Lit, Macro, Pat, Path, |
242 | Token, Type, Visibility, |
243 | }; |
244 | |
245 | enum KnownMacro { |
246 | Expr(Expr), |
247 | Exprs(Vec<Expr>), |
248 | Cfg(Cfg), |
249 | Matches(Matches), |
250 | ThreadLocal(Vec<ThreadLocal>), |
251 | VecArray(Punctuated<Expr, Token![,]>), |
252 | VecRepeat { elem: Expr, n: Expr }, |
253 | } |
254 | |
255 | enum Cfg { |
256 | Eq(Ident, Option<Lit>), |
257 | Call(Ident, Vec<Cfg>), |
258 | } |
259 | |
260 | struct Matches { |
261 | expression: Expr, |
262 | pattern: Pat, |
263 | guard: Option<Expr>, |
264 | } |
265 | |
266 | struct ThreadLocal { |
267 | attrs: Vec<Attribute>, |
268 | vis: Visibility, |
269 | name: Ident, |
270 | ty: Type, |
271 | init: Expr, |
272 | } |
273 | |
274 | struct FormatArgs { |
275 | format_string: Expr, |
276 | args: Vec<Expr>, |
277 | } |
278 | |
279 | impl Parse for FormatArgs { |
280 | fn parse(input: ParseStream) -> Result<Self> { |
281 | let format_string: Expr = input.parse()?; |
282 | |
283 | let mut args = Vec::new(); |
284 | while !input.is_empty() { |
285 | input.parse::<Token![,]>()?; |
286 | if input.is_empty() { |
287 | break; |
288 | } |
289 | let arg = if input.peek(Ident::peek_any) |
290 | && input.peek2(Token![=]) |
291 | && !input.peek2(Token![==]) |
292 | { |
293 | let key = input.call(Ident::parse_any)?; |
294 | let eq_token: Token![=] = input.parse()?; |
295 | let value: Expr = input.parse()?; |
296 | Expr::Assign(ExprAssign { |
297 | attrs: Vec::new(), |
298 | left: Box::new(Expr::Path(ExprPath { |
299 | attrs: Vec::new(), |
300 | qself: None, |
301 | path: Path::from(key), |
302 | })), |
303 | eq_token, |
304 | right: Box::new(value), |
305 | }) |
306 | } else { |
307 | input.parse()? |
308 | }; |
309 | args.push(arg); |
310 | } |
311 | |
312 | Ok(FormatArgs { |
313 | format_string, |
314 | args, |
315 | }) |
316 | } |
317 | } |
318 | |
319 | impl KnownMacro { |
320 | fn parse_expr(input: ParseStream) -> Result<Self> { |
321 | let expr: Expr = input.parse()?; |
322 | Ok(KnownMacro::Expr(expr)) |
323 | } |
324 | |
325 | fn parse_expr_comma(input: ParseStream) -> Result<Self> { |
326 | let expr: Expr = input.parse()?; |
327 | input.parse::<Option<Token![,]>>()?; |
328 | Ok(KnownMacro::Exprs(vec![expr])) |
329 | } |
330 | |
331 | fn parse_exprs(input: ParseStream) -> Result<Self> { |
332 | let exprs = input.parse_terminated(Expr::parse, Token![,])?; |
333 | Ok(KnownMacro::Exprs(Vec::from_iter(exprs))) |
334 | } |
335 | |
336 | fn parse_assert(input: ParseStream) -> Result<Self> { |
337 | let mut exprs = Vec::new(); |
338 | let cond: Expr = input.parse()?; |
339 | exprs.push(cond); |
340 | if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() { |
341 | let format_args: FormatArgs = input.parse()?; |
342 | exprs.push(format_args.format_string); |
343 | exprs.extend(format_args.args); |
344 | } |
345 | Ok(KnownMacro::Exprs(exprs)) |
346 | } |
347 | |
348 | fn parse_assert_cmp(input: ParseStream) -> Result<Self> { |
349 | let mut exprs = Vec::new(); |
350 | let left: Expr = input.parse()?; |
351 | exprs.push(left); |
352 | input.parse::<Token![,]>()?; |
353 | let right: Expr = input.parse()?; |
354 | exprs.push(right); |
355 | if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() { |
356 | let format_args: FormatArgs = input.parse()?; |
357 | exprs.push(format_args.format_string); |
358 | exprs.extend(format_args.args); |
359 | } |
360 | Ok(KnownMacro::Exprs(exprs)) |
361 | } |
362 | |
363 | fn parse_cfg(input: ParseStream) -> Result<Self> { |
364 | fn parse_single(input: ParseStream) -> Result<Cfg> { |
365 | let ident: Ident = input.parse()?; |
366 | if input.peek(token::Paren) && (ident == "all" || ident == "any" ) { |
367 | let content; |
368 | parenthesized!(content in input); |
369 | let list = content.call(parse_multiple)?; |
370 | Ok(Cfg::Call(ident, list)) |
371 | } else if input.peek(token::Paren) && ident == "not" { |
372 | let content; |
373 | parenthesized!(content in input); |
374 | let cfg = content.call(parse_single)?; |
375 | content.parse::<Option<Token![,]>>()?; |
376 | Ok(Cfg::Call(ident, vec![cfg])) |
377 | } else if input.peek(Token![=]) { |
378 | input.parse::<Token![=]>()?; |
379 | let string: Lit = input.parse()?; |
380 | Ok(Cfg::Eq(ident, Some(string))) |
381 | } else { |
382 | Ok(Cfg::Eq(ident, None)) |
383 | } |
384 | } |
385 | |
386 | fn parse_multiple(input: ParseStream) -> Result<Vec<Cfg>> { |
387 | let mut vec = Vec::new(); |
388 | while !input.is_empty() { |
389 | let cfg = input.call(parse_single)?; |
390 | vec.push(cfg); |
391 | if input.is_empty() { |
392 | break; |
393 | } |
394 | input.parse::<Token![,]>()?; |
395 | } |
396 | Ok(vec) |
397 | } |
398 | |
399 | let cfg = input.call(parse_single)?; |
400 | input.parse::<Option<Token![,]>>()?; |
401 | Ok(KnownMacro::Cfg(cfg)) |
402 | } |
403 | |
404 | fn parse_env(input: ParseStream) -> Result<Self> { |
405 | let mut exprs = Vec::new(); |
406 | let name: Expr = input.parse()?; |
407 | exprs.push(name); |
408 | if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() { |
409 | let error_msg: Expr = input.parse()?; |
410 | exprs.push(error_msg); |
411 | input.parse::<Option<Token![,]>>()?; |
412 | } |
413 | Ok(KnownMacro::Exprs(exprs)) |
414 | } |
415 | |
416 | fn parse_format_args(input: ParseStream) -> Result<Self> { |
417 | let format_args: FormatArgs = input.parse()?; |
418 | let mut exprs = format_args.args; |
419 | exprs.insert(0, format_args.format_string); |
420 | Ok(KnownMacro::Exprs(exprs)) |
421 | } |
422 | |
423 | fn parse_matches(input: ParseStream) -> Result<Self> { |
424 | let expression: Expr = input.parse()?; |
425 | input.parse::<Token![,]>()?; |
426 | let pattern = input.call(Pat::parse_multi_with_leading_vert)?; |
427 | let guard = if input.parse::<Option<Token![if]>>()?.is_some() { |
428 | Some(input.parse()?) |
429 | } else { |
430 | None |
431 | }; |
432 | input.parse::<Option<Token![,]>>()?; |
433 | Ok(KnownMacro::Matches(Matches { |
434 | expression, |
435 | pattern, |
436 | guard, |
437 | })) |
438 | } |
439 | |
440 | fn parse_thread_local(input: ParseStream) -> Result<Self> { |
441 | let mut items = Vec::new(); |
442 | while !input.is_empty() { |
443 | let attrs = input.call(Attribute::parse_outer)?; |
444 | let vis: Visibility = input.parse()?; |
445 | input.parse::<Token![static]>()?; |
446 | let name: Ident = input.parse()?; |
447 | input.parse::<Token![:]>()?; |
448 | let ty: Type = input.parse()?; |
449 | input.parse::<Token![=]>()?; |
450 | let init: Expr = input.parse()?; |
451 | if input.is_empty() { |
452 | break; |
453 | } |
454 | input.parse::<Token![;]>()?; |
455 | items.push(ThreadLocal { |
456 | attrs, |
457 | vis, |
458 | name, |
459 | ty, |
460 | init, |
461 | }); |
462 | } |
463 | Ok(KnownMacro::ThreadLocal(items)) |
464 | } |
465 | |
466 | fn parse_vec(input: ParseStream) -> Result<Self> { |
467 | if input.is_empty() { |
468 | return Ok(KnownMacro::VecArray(Punctuated::new())); |
469 | } |
470 | let first: Expr = input.parse()?; |
471 | if input.parse::<Option<Token![;]>>()?.is_some() { |
472 | let len: Expr = input.parse()?; |
473 | Ok(KnownMacro::VecRepeat { |
474 | elem: first, |
475 | n: len, |
476 | }) |
477 | } else { |
478 | let mut vec = Punctuated::new(); |
479 | vec.push_value(first); |
480 | while !input.is_empty() { |
481 | let comma: Token![,] = input.parse()?; |
482 | vec.push_punct(comma); |
483 | if input.is_empty() { |
484 | break; |
485 | } |
486 | let next: Expr = input.parse()?; |
487 | vec.push_value(next); |
488 | } |
489 | Ok(KnownMacro::VecArray(vec)) |
490 | } |
491 | } |
492 | |
493 | fn parse_write(input: ParseStream) -> Result<Self> { |
494 | let mut exprs = Vec::new(); |
495 | let dst: Expr = input.parse()?; |
496 | exprs.push(dst); |
497 | input.parse::<Token![,]>()?; |
498 | let format_args: FormatArgs = input.parse()?; |
499 | exprs.push(format_args.format_string); |
500 | exprs.extend(format_args.args); |
501 | Ok(KnownMacro::Exprs(exprs)) |
502 | } |
503 | |
504 | fn parse_writeln(input: ParseStream) -> Result<Self> { |
505 | let mut exprs = Vec::new(); |
506 | let dst: Expr = input.parse()?; |
507 | exprs.push(dst); |
508 | if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() { |
509 | let format_args: FormatArgs = input.parse()?; |
510 | exprs.push(format_args.format_string); |
511 | exprs.extend(format_args.args); |
512 | } |
513 | Ok(KnownMacro::Exprs(exprs)) |
514 | } |
515 | } |
516 | |
517 | impl Printer { |
518 | pub fn standard_library_macro(&mut self, mac: &Macro, mut semicolon: bool) -> bool { |
519 | let name = mac.path.segments.last().unwrap().ident.to_string(); |
520 | let parser = match name.as_str() { |
521 | "addr_of" | "addr_of_mut" => KnownMacro::parse_expr, |
522 | "assert" | "debug_assert" => KnownMacro::parse_assert, |
523 | "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" => { |
524 | KnownMacro::parse_assert_cmp |
525 | } |
526 | "cfg" => KnownMacro::parse_cfg, |
527 | "compile_error" | "include" | "include_bytes" | "include_str" | "option_env" => { |
528 | KnownMacro::parse_expr_comma |
529 | } |
530 | "concat" | "concat_bytes" | "dbg" => KnownMacro::parse_exprs, |
531 | "const_format_args" | "eprint" | "eprintln" | "format" | "format_args" |
532 | | "format_args_nl" | "panic" | "print" | "println" | "todo" | "unimplemented" |
533 | | "unreachable" => KnownMacro::parse_format_args, |
534 | "env" => KnownMacro::parse_env, |
535 | "matches" => KnownMacro::parse_matches, |
536 | "thread_local" => KnownMacro::parse_thread_local, |
537 | "vec" => KnownMacro::parse_vec, |
538 | "write" => KnownMacro::parse_write, |
539 | "writeln" => KnownMacro::parse_writeln, |
540 | _ => return false, |
541 | }; |
542 | |
543 | let known_macro = match parser.parse2(mac.tokens.clone()) { |
544 | Ok(known_macro) => known_macro, |
545 | Err(_) => return false, |
546 | }; |
547 | |
548 | self.path(&mac.path, PathKind::Simple); |
549 | self.word("!" ); |
550 | |
551 | match &known_macro { |
552 | KnownMacro::Expr(expr) => { |
553 | self.word("(" ); |
554 | self.cbox(INDENT); |
555 | self.zerobreak(); |
556 | self.expr(expr, FixupContext::NONE); |
557 | self.zerobreak(); |
558 | self.offset(-INDENT); |
559 | self.end(); |
560 | self.word(")" ); |
561 | } |
562 | KnownMacro::Exprs(exprs) => { |
563 | self.word("(" ); |
564 | self.cbox(INDENT); |
565 | self.zerobreak(); |
566 | for elem in exprs.iter().delimited() { |
567 | self.expr(&elem, FixupContext::NONE); |
568 | self.trailing_comma(elem.is_last); |
569 | } |
570 | self.offset(-INDENT); |
571 | self.end(); |
572 | self.word(")" ); |
573 | } |
574 | KnownMacro::Cfg(cfg) => { |
575 | self.word("(" ); |
576 | self.cfg(cfg); |
577 | self.word(")" ); |
578 | } |
579 | KnownMacro::Matches(matches) => { |
580 | self.word("(" ); |
581 | self.cbox(INDENT); |
582 | self.zerobreak(); |
583 | self.expr(&matches.expression, FixupContext::NONE); |
584 | self.word("," ); |
585 | self.space(); |
586 | self.pat(&matches.pattern); |
587 | if let Some(guard) = &matches.guard { |
588 | self.space(); |
589 | self.word("if " ); |
590 | self.expr(guard, FixupContext::NONE); |
591 | } |
592 | self.zerobreak(); |
593 | self.offset(-INDENT); |
594 | self.end(); |
595 | self.word(")" ); |
596 | } |
597 | KnownMacro::ThreadLocal(items) => { |
598 | self.word(" {" ); |
599 | self.cbox(INDENT); |
600 | self.hardbreak_if_nonempty(); |
601 | for item in items { |
602 | self.outer_attrs(&item.attrs); |
603 | self.cbox(0); |
604 | self.visibility(&item.vis); |
605 | self.word("static " ); |
606 | self.ident(&item.name); |
607 | self.word(": " ); |
608 | self.ty(&item.ty); |
609 | self.word(" = " ); |
610 | self.neverbreak(); |
611 | self.expr(&item.init, FixupContext::NONE); |
612 | self.word(";" ); |
613 | self.end(); |
614 | self.hardbreak(); |
615 | } |
616 | self.offset(-INDENT); |
617 | self.end(); |
618 | self.word("}" ); |
619 | semicolon = false; |
620 | } |
621 | KnownMacro::VecArray(vec) => { |
622 | if vec.is_empty() { |
623 | self.word("[]" ); |
624 | } else if expr::simple_array(vec) { |
625 | self.cbox(INDENT); |
626 | self.word("[" ); |
627 | self.zerobreak(); |
628 | self.ibox(0); |
629 | for elem in vec.iter().delimited() { |
630 | self.expr(&elem, FixupContext::NONE); |
631 | if !elem.is_last { |
632 | self.word("," ); |
633 | self.space(); |
634 | } |
635 | } |
636 | self.end(); |
637 | self.trailing_comma(true); |
638 | self.offset(-INDENT); |
639 | self.word("]" ); |
640 | self.end(); |
641 | } else { |
642 | self.word("[" ); |
643 | self.cbox(INDENT); |
644 | self.zerobreak(); |
645 | for elem in vec.iter().delimited() { |
646 | self.expr(&elem, FixupContext::NONE); |
647 | self.trailing_comma(elem.is_last); |
648 | } |
649 | self.offset(-INDENT); |
650 | self.end(); |
651 | self.word("]" ); |
652 | } |
653 | } |
654 | KnownMacro::VecRepeat { elem, n } => { |
655 | self.word("[" ); |
656 | self.cbox(INDENT); |
657 | self.zerobreak(); |
658 | self.expr(elem, FixupContext::NONE); |
659 | self.word(";" ); |
660 | self.space(); |
661 | self.expr(n, FixupContext::NONE); |
662 | self.zerobreak(); |
663 | self.offset(-INDENT); |
664 | self.end(); |
665 | self.word("]" ); |
666 | } |
667 | } |
668 | |
669 | if semicolon { |
670 | self.word(";" ); |
671 | } |
672 | |
673 | true |
674 | } |
675 | |
676 | fn cfg(&mut self, cfg: &Cfg) { |
677 | match cfg { |
678 | Cfg::Eq(ident, value) => { |
679 | self.ident(ident); |
680 | if let Some(value) = value { |
681 | self.word(" = " ); |
682 | self.lit(value); |
683 | } |
684 | } |
685 | Cfg::Call(ident, args) => { |
686 | self.ident(ident); |
687 | self.word("(" ); |
688 | self.cbox(INDENT); |
689 | self.zerobreak(); |
690 | for arg in args.iter().delimited() { |
691 | self.cfg(&arg); |
692 | self.trailing_comma(arg.is_last); |
693 | } |
694 | self.offset(-INDENT); |
695 | self.end(); |
696 | self.word(")" ); |
697 | } |
698 | } |
699 | } |
700 | } |
701 | } |
702 | |