1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::iter::Peekable; |
4 | |
5 | use proc_macro::{ |
6 | token_stream::IntoIter as ProcIter, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, |
7 | TokenStream, TokenTree, |
8 | }; |
9 | |
10 | use crate::utils::crate_ident_new; |
11 | |
12 | struct PeekableProcIter { |
13 | inner: Peekable<ProcIter>, |
14 | current_span: Option<Span>, |
15 | next_span: Option<Span>, |
16 | } |
17 | |
18 | impl<'a> From<&'a Group> for PeekableProcIter { |
19 | fn from(f: &'a Group) -> Self { |
20 | let current_span: Option = Some(f.span()); |
21 | let mut inner: impl Iterator = f.stream().into_iter().peekable(); |
22 | let next_span: Option = inner.peek().map(|n: &TokenTree| n.span()); |
23 | Self { |
24 | inner, |
25 | current_span, |
26 | next_span, |
27 | } |
28 | } |
29 | } |
30 | |
31 | impl From<TokenStream> for PeekableProcIter { |
32 | fn from(f: TokenStream) -> Self { |
33 | let mut inner: impl Iterator = f.into_iter().peekable(); |
34 | let next_span: Option = inner.peek().map(|n: &TokenTree| n.span()); |
35 | Self { |
36 | inner, |
37 | current_span: None, |
38 | next_span, |
39 | } |
40 | } |
41 | } |
42 | |
43 | impl Iterator for PeekableProcIter { |
44 | type Item = TokenTree; |
45 | |
46 | fn next(&mut self) -> Option<Self::Item> { |
47 | let next: TokenTree = self.inner.next()?; |
48 | self.current_span = Some(next.span()); |
49 | self.next_span = self.inner.peek().map(|n: &TokenTree| n.span()); |
50 | Some(next) |
51 | } |
52 | } |
53 | |
54 | impl PeekableProcIter { |
55 | fn peek(&mut self) -> Option<&TokenTree> { |
56 | self.inner.peek() |
57 | } |
58 | |
59 | fn generate_error(&self, message: &str) -> TokenStream { |
60 | self.generate_error_with_span(message, self.current_span) |
61 | } |
62 | |
63 | fn generate_error_with_next_span(&self, message: &str) -> TokenStream { |
64 | self.generate_error_with_span(message, self.next_span) |
65 | } |
66 | |
67 | fn generate_error_with_span(&self, message: &str, span: Option<Span>) -> TokenStream { |
68 | let span = span.unwrap_or_else(Span::call_site); |
69 | // We generate a `compile_error` macro and assign it to the current span so the error |
70 | // displayed by rustc points to the right location. |
71 | let mut stream = TokenStream::new(); |
72 | stream.extend(vec![TokenTree::Literal(Literal::string(message))]); |
73 | |
74 | let mut tokens = vec![ |
75 | TokenTree::Ident(Ident::new("compile_error" , span)), |
76 | TokenTree::Punct(Punct::new('!' , Spacing::Alone)), |
77 | TokenTree::Group(Group::new(Delimiter::Parenthesis, stream)), |
78 | TokenTree::Punct(Punct::new(';' , Spacing::Alone)), |
79 | ]; |
80 | |
81 | for tok in &mut tokens { |
82 | tok.set_span(span); |
83 | } |
84 | |
85 | let mut stream = TokenStream::new(); |
86 | stream.extend(tokens); |
87 | let mut t = TokenTree::Group(Group::new(Delimiter::Brace, stream)); |
88 | t.set_span(span); |
89 | |
90 | let mut stream = TokenStream::new(); |
91 | stream.extend(vec![t]); |
92 | stream |
93 | } |
94 | } |
95 | |
96 | #[derive (Clone, Copy, Debug)] |
97 | enum BorrowKind { |
98 | Weak, |
99 | WeakAllowNone, |
100 | Strong, |
101 | ToOwned, |
102 | } |
103 | |
104 | impl BorrowKind { |
105 | fn to_str(self) -> &'static str { |
106 | match self { |
107 | Self::Weak => "@weak" , |
108 | Self::WeakAllowNone => "@weak-allow-none" , |
109 | Self::Strong => "@strong" , |
110 | Self::ToOwned => "@to-owned" , |
111 | } |
112 | } |
113 | } |
114 | |
115 | enum WrapperKind { |
116 | DefaultPanic, |
117 | DefaultReturn(String), |
118 | } |
119 | |
120 | impl WrapperKind { |
121 | fn to_str(&self) -> String { |
122 | match *self { |
123 | Self::DefaultPanic => "@default-panic" .to_owned(), |
124 | Self::DefaultReturn(ref r: &String) => format!("@default-return {r}" ), |
125 | } |
126 | } |
127 | |
128 | fn keyword(&self) -> &'static str { |
129 | match *self { |
130 | Self::DefaultPanic => "default-panic" , |
131 | Self::DefaultReturn(_) => "default-return" , |
132 | } |
133 | } |
134 | } |
135 | |
136 | #[derive (Debug)] |
137 | struct ElemToClone { |
138 | name: String, |
139 | alias: Option<String>, |
140 | borrow_kind: BorrowKind, |
141 | } |
142 | |
143 | impl ElemToClone { |
144 | fn to_str_before(&self) -> String { |
145 | match self.borrow_kind { |
146 | BorrowKind::Weak | BorrowKind::WeakAllowNone => format!( |
147 | "let {} = {}::clone::Downgrade::downgrade(& {});" , |
148 | if let Some(ref a) = self.alias { |
149 | a |
150 | } else { |
151 | &self.name |
152 | }, |
153 | crate_ident_new(), |
154 | self.name, |
155 | ), |
156 | BorrowKind::Strong => format!( |
157 | "let {} = {}.clone();" , |
158 | if let Some(ref a) = self.alias { |
159 | a |
160 | } else { |
161 | &self.name |
162 | }, |
163 | self.name, |
164 | ), |
165 | BorrowKind::ToOwned => format!( |
166 | "let {} = ::std::borrow::ToOwned::to_owned(&* {});" , |
167 | if let Some(ref a) = self.alias { |
168 | a |
169 | } else { |
170 | &self.name |
171 | }, |
172 | self.name, |
173 | ), |
174 | } |
175 | } |
176 | |
177 | fn to_str_after(&self, wrapper_kind: &Option<WrapperKind>) -> String { |
178 | let name = if let Some(ref a) = self.alias { |
179 | a |
180 | } else { |
181 | &self.name |
182 | }; |
183 | match (self.borrow_kind, wrapper_kind) { |
184 | (BorrowKind::Weak, Some(WrapperKind::DefaultPanic)) => { |
185 | format!( |
186 | "\ |
187 | let {0} = match {1}::clone::Upgrade::upgrade(& {0}) {{ |
188 | Some(val) => val, |
189 | None => panic!( |
190 | \"failed to upgrade ` {0}` (if you don't want to panic, use @default-return) \", |
191 | ), |
192 | }};" , |
193 | name, |
194 | crate_ident_new(), |
195 | ) |
196 | } |
197 | (BorrowKind::Weak, Some(WrapperKind::DefaultReturn(ref r))) => { |
198 | let not_unit_ret = r.chars().any(|c| c != '(' && c != ')' && c != ' ' ); |
199 | format!( |
200 | "\ |
201 | let {0} = match {1}::clone::Upgrade::upgrade(& {0}) {{ |
202 | Some(val) => val, |
203 | None => {{ |
204 | {1}::g_debug!( |
205 | {1}::CLONE_MACRO_LOG_DOMAIN, |
206 | \"Failed to upgrade {0}\", |
207 | ); |
208 | let ___return_value = || {{ {2} }}; |
209 | return ___return_value(); |
210 | }} |
211 | }};" , |
212 | name, |
213 | crate_ident_new(), |
214 | if not_unit_ret { r } else { "" }, |
215 | ) |
216 | } |
217 | (BorrowKind::Weak, None) => { |
218 | format!( |
219 | "\ |
220 | let {0} = match {1}::clone::Upgrade::upgrade(& {0}) {{ |
221 | Some(val) => val, |
222 | None => {{ |
223 | {1}::g_debug!( |
224 | {1}::CLONE_MACRO_LOG_DOMAIN, |
225 | \"Failed to upgrade {0}\", |
226 | ); |
227 | return; |
228 | }} |
229 | }};" , |
230 | name, |
231 | crate_ident_new(), |
232 | ) |
233 | } |
234 | (BorrowKind::WeakAllowNone, _) => format!( |
235 | "let {0} = {1}::clone::Upgrade::upgrade(& {0});" , |
236 | name, |
237 | crate_ident_new(), |
238 | ), |
239 | _ => String::new(), |
240 | } |
241 | } |
242 | } |
243 | |
244 | enum SimpleToken { |
245 | Punct(&'static str), |
246 | Ident(&'static str), |
247 | } |
248 | |
249 | impl SimpleToken { |
250 | fn to_str(&self) -> &str { |
251 | match *self { |
252 | Self::Punct(p: &str) => p, |
253 | Self::Ident(i: &str) => i, |
254 | } |
255 | } |
256 | } |
257 | |
258 | impl PartialEq<TokenTree> for SimpleToken { |
259 | fn eq(&self, other: &TokenTree) -> bool { |
260 | match (self, other) { |
261 | (SimpleToken::Punct(p1: &&str), TokenTree::Punct(ref p2: &Punct)) => *p1 == p2.to_string(), |
262 | (SimpleToken::Ident(i1: &&str), TokenTree::Ident(ref i2: &Ident)) => *i1 == i2.to_string(), |
263 | _ => false, |
264 | } |
265 | } |
266 | } |
267 | |
268 | fn is_punct(elem: &TokenTree, punct: &str) -> bool { |
269 | match elem { |
270 | TokenTree::Punct(ref p: &Punct) => p.to_string() == punct, |
271 | _ => false, |
272 | } |
273 | } |
274 | |
275 | enum TokenCheck { |
276 | UnexpectedToken(String, String), |
277 | UnexpectedEnd(String), |
278 | } |
279 | |
280 | fn check_tokens( |
281 | tokens_to_check: &[SimpleToken], |
282 | parts: &mut PeekableProcIter, |
283 | ) -> Result<(), TokenCheck> { |
284 | let mut tokens: String = String::new(); |
285 | |
286 | for token: &SimpleToken in tokens_to_check { |
287 | if let Some(next: &TokenTree) = parts.peek() { |
288 | if token != next { |
289 | return Err(TokenCheck::UnexpectedToken(tokens, next.to_string())); |
290 | } |
291 | tokens.push_str(string:token.to_str()); |
292 | parts.next(); |
293 | } else { |
294 | return Err(TokenCheck::UnexpectedEnd(tokens)); |
295 | } |
296 | } |
297 | Ok(()) |
298 | } |
299 | |
300 | #[doc (alias = "get_full_ident" )] |
301 | fn full_ident( |
302 | parts: &mut PeekableProcIter, |
303 | borrow_kind: BorrowKind, |
304 | ) -> Result<String, TokenStream> { |
305 | let mut name = String::new(); |
306 | let mut prev_is_ident = false; |
307 | |
308 | loop { |
309 | match parts.peek() { |
310 | Some(TokenTree::Punct(p)) => { |
311 | let p_s = p.to_string(); |
312 | if p_s == "," || p_s == "=" { |
313 | break; |
314 | } else if p_s == "." { |
315 | if !prev_is_ident { |
316 | return Err(parts.generate_error_with_next_span(&format!( |
317 | "Unexpected `.` after ` {}`" , |
318 | borrow_kind.to_str() |
319 | ))); |
320 | } |
321 | prev_is_ident = false; |
322 | name.push('.' ); |
323 | parts.next(); |
324 | } else if name.is_empty() { |
325 | return Err(parts |
326 | .generate_error_with_next_span(&format!("Expected ident, found ` {p_s}`" ))); |
327 | } else { |
328 | return Err(parts.generate_error_with_next_span(&format!( |
329 | "Expected ident, found ` {p_s}` after ` {name}`" |
330 | ))); |
331 | } |
332 | } |
333 | Some(TokenTree::Ident(i)) => { |
334 | if prev_is_ident { |
335 | break; |
336 | } |
337 | prev_is_ident = true; |
338 | name.push_str(&i.to_string()); |
339 | parts.next(); |
340 | } |
341 | Some(x) if name.is_empty() => { |
342 | let err = format!("Expected ident, found ` {x}`" ); |
343 | return Err(parts.generate_error_with_next_span(&err)); |
344 | } |
345 | Some(x) => { |
346 | let err = &format!("Expected ident, found ` {x}` after ` {name}`" ); |
347 | return Err(parts.generate_error_with_next_span(err)); |
348 | } |
349 | None => { |
350 | return Err(parts.generate_error(&format!("Unexpected end after ident ` {name}`" ))); |
351 | } |
352 | } |
353 | } |
354 | if name.is_empty() { |
355 | if let Some(next) = parts.next() { |
356 | return Err(parts.generate_error(&format!("Expected ident, found ` {next}`" ))); |
357 | } |
358 | return Err(parts.generate_error("Expected something after, found nothing" )); |
359 | } |
360 | Ok(name) |
361 | } |
362 | |
363 | #[doc (alias = "get_keyword" )] |
364 | fn keyword(parts: &mut PeekableProcIter) -> Result<BorrowKind, TokenStream> { |
365 | let mut ret = String::new(); |
366 | let mut prev_is_ident = false; |
367 | let mut stored = false; |
368 | // We unfortunately can't join spans since the `Span::join` method is nightly-only. Well, we'll |
369 | // do our best... |
370 | let start_span = parts.next_span; |
371 | |
372 | loop { |
373 | match parts.peek() { |
374 | Some(TokenTree::Ident(i)) => { |
375 | if prev_is_ident { |
376 | break; |
377 | } |
378 | prev_is_ident = true; |
379 | if stored { |
380 | ret.push('-' ); |
381 | stored = false; |
382 | } |
383 | ret.push_str(&i.to_string()); |
384 | } |
385 | Some(TokenTree::Punct(p)) if p.to_string() == "-" => { |
386 | if !prev_is_ident { |
387 | break; |
388 | } |
389 | // This is to prevent to push `-` if the next item isn't an ident. |
390 | prev_is_ident = false; |
391 | stored = true; |
392 | } |
393 | _ => break, |
394 | } |
395 | parts.next(); |
396 | } |
397 | let ret = match ret.as_str() { |
398 | "strong" => BorrowKind::Strong, |
399 | "weak" => BorrowKind::Weak, |
400 | "weak-allow-none" => BorrowKind::WeakAllowNone, |
401 | "to-owned" => BorrowKind::ToOwned, |
402 | "default-return" => { |
403 | return Err(parts |
404 | .generate_error_with_span("`@default-return` should be after `=>`" , start_span)); |
405 | } |
406 | "default-panic" => { |
407 | return Err( |
408 | parts.generate_error_with_span("`@default-panic` should be after `=>`" , start_span) |
409 | ); |
410 | } |
411 | k => { |
412 | return Err(parts.generate_error_with_span( |
413 | &format!( |
414 | "Unknown keyword ` {k}`, only `weak`, `weak-allow-none`, `to-owned` and \ |
415 | `strong` are allowed" |
416 | ), |
417 | start_span, |
418 | )); |
419 | } |
420 | }; |
421 | Ok(ret) |
422 | } |
423 | |
424 | fn parse_ident( |
425 | parts: &mut PeekableProcIter, |
426 | elements: &mut Vec<ElemToClone>, |
427 | ) -> Result<(), TokenStream> { |
428 | let borrow_kind = keyword(parts)?; |
429 | let name = full_ident(parts, borrow_kind)?; |
430 | let name_span = parts.current_span; |
431 | if name.ends_with('.' ) { |
432 | return Err( |
433 | parts.generate_error_with_span(&format!("Invalid variable name: ` {name}`" ), name_span) |
434 | ); |
435 | } |
436 | let alias = match parts.peek() { |
437 | Some(TokenTree::Ident(p)) if p.to_string() == "as" => { |
438 | parts.next(); |
439 | let current_span = parts.current_span; |
440 | match parts.next() { |
441 | Some(TokenTree::Ident(i)) => Some(i.to_string()), |
442 | Some(x) => { |
443 | let err = format!("Expected ident after `as` keyword, found ` {x}`" ); |
444 | return Err(parts.generate_error(&err)); |
445 | } |
446 | None => { |
447 | return Err(parts.generate_error_with_span( |
448 | "Unexpected end after `as` keyword" , |
449 | current_span, |
450 | )) |
451 | } |
452 | } |
453 | } |
454 | Some(TokenTree::Ident(p)) => { |
455 | let err = format!("Unexpected ` {p}`" ); |
456 | return Err(parts.generate_error(&err)); |
457 | } |
458 | _ => None, |
459 | }; |
460 | if name == "self" && alias.is_none() { |
461 | return Err(parts.generate_error_with_span( |
462 | "Can't use `self` as variable name. Try storing it in a temporary variable or \ |
463 | rename it using `as`." , |
464 | name_span, |
465 | )); |
466 | } else if name.contains('.' ) && alias.is_none() { |
467 | let err = format!("` {name}`: Field accesses are not allowed as is, you must rename it!" ); |
468 | return Err(parts.generate_error_with_span(&err, name_span)); |
469 | } |
470 | |
471 | elements.push(ElemToClone { |
472 | name, |
473 | alias, |
474 | borrow_kind, |
475 | }); |
476 | Ok(()) |
477 | } |
478 | |
479 | fn delimiter_to_string(delimiter: Delimiter, open: bool) -> &'static str { |
480 | match delimiter { |
481 | Delimiter::Parenthesis => { |
482 | if open { |
483 | "(" |
484 | } else { |
485 | ")" |
486 | } |
487 | } |
488 | Delimiter::Brace => { |
489 | if open { |
490 | "{" |
491 | } else { |
492 | "}" |
493 | } |
494 | } |
495 | Delimiter::Bracket => { |
496 | if open { |
497 | "[" |
498 | } else { |
499 | "]" |
500 | } |
501 | } |
502 | Delimiter::None => "" , |
503 | } |
504 | } |
505 | |
506 | fn group_to_string(g: &Group) -> String { |
507 | format!( |
508 | " {}{}{}" , |
509 | delimiter_to_string(g.delimiter(), true), |
510 | tokens_to_string(PeekableProcIter::from(g)), |
511 | delimiter_to_string(g.delimiter(), false), |
512 | ) |
513 | } |
514 | |
515 | #[doc (alias = "get_expr" )] |
516 | fn expr(parts: &mut PeekableProcIter) -> Result<String, TokenStream> { |
517 | let mut ret = String::new(); |
518 | let mut total = 0; |
519 | let span = parts.current_span; |
520 | match parts.next() { |
521 | Some(TokenTree::Literal(l)) => ret.push_str(&l.to_string()), |
522 | Some(TokenTree::Ident(i)) => ret.push_str(&i.to_string()), |
523 | Some(TokenTree::Punct(p)) => match p.to_string().as_str() { |
524 | "[" | "{" | "(" => { |
525 | total += 1; |
526 | } |
527 | x => { |
528 | return Err(parts |
529 | .generate_error(&format!("Unexpected token ` {x}` after `@default-return`" ))) |
530 | } |
531 | }, |
532 | Some(TokenTree::Group(g)) => return Ok(group_to_string(&g)), |
533 | None => { |
534 | return Err( |
535 | parts.generate_error_with_span("Unexpected end after `@default-return`" , span) |
536 | ) |
537 | } |
538 | }; |
539 | loop { |
540 | match parts.peek() { |
541 | Some(TokenTree::Punct(p)) => { |
542 | let p_s = p.to_string(); |
543 | if p_s == "{" || p_s == "(" || p_s == "[" || p_s == "<" { |
544 | total += 1; |
545 | } else if p_s == "}" || p_s == ")" || p_s == "]" || p_s == ">" { |
546 | total -= 1; |
547 | } else if p_s == "," && total == 0 { |
548 | return Ok(ret); |
549 | } |
550 | ret.push_str(&p_s); |
551 | } |
552 | Some(TokenTree::Group(g)) => { |
553 | ret.push_str(&group_to_string(g)); |
554 | } |
555 | Some(x) => { |
556 | if total == 0 && !ret.ends_with(':' ) { |
557 | return Ok(ret); |
558 | } |
559 | ret.push_str(&x.to_string()) |
560 | } |
561 | None => return Err(parts.generate_error( |
562 | "Unexpected end after `{ret}`. Did you forget a `,` after the @default-return value?" , |
563 | )), |
564 | } |
565 | parts.next(); |
566 | } |
567 | } |
568 | |
569 | #[doc (alias = "get_return_kind" )] |
570 | fn return_kind(parts: &mut PeekableProcIter) -> Result<WrapperKind, TokenStream> { |
571 | match check_tokens( |
572 | &[SimpleToken::Ident("default" ), SimpleToken::Punct("-" )], |
573 | parts, |
574 | ) { |
575 | Err(TokenCheck::UnexpectedToken(tokens, unexpected_token)) => { |
576 | return Err( |
577 | parts.generate_error(&format!("Unknown keyword ` {tokens}{unexpected_token}`" )) |
578 | ); |
579 | } |
580 | Err(TokenCheck::UnexpectedEnd(tokens)) => { |
581 | return Err(parts.generate_error(&format!("Unexpected end after tokens ` {tokens}`" ))); |
582 | } |
583 | Ok(()) => {} |
584 | } |
585 | let prev = parts.current_span; |
586 | match parts.next() { |
587 | Some(TokenTree::Ident(i)) => { |
588 | let i_s = i.to_string(); |
589 | if i_s == "panic" { |
590 | return Ok(WrapperKind::DefaultPanic); |
591 | } |
592 | assert!(i_s == "return" , "Unknown keyword `@default- {i_s}`" ); |
593 | } |
594 | Some(x) => { |
595 | let err = format!("Unknown token ` {x}` after `@default-`" ); |
596 | return Err(parts.generate_error(&err)); |
597 | } |
598 | None => { |
599 | return Err(parts.generate_error_with_span("Unexpected end after `@default-`" , prev)) |
600 | } |
601 | } |
602 | Ok(WrapperKind::DefaultReturn(expr(parts)?)) |
603 | } |
604 | |
605 | fn parse_return_kind(parts: &mut PeekableProcIter) -> Result<Option<WrapperKind>, TokenStream> { |
606 | match parts.peek() { |
607 | Some(TokenTree::Punct(p: &Punct)) if p.to_string() == "@" => {} |
608 | None => return Err(parts.generate_error(message:"Unexpected end 2" )), |
609 | _ => return Ok(None), |
610 | } |
611 | parts.next(); |
612 | let ret: WrapperKind = return_kind(parts)?; |
613 | match check_tokens(&[SimpleToken::Punct("," )], parts) { |
614 | Err(TokenCheck::UnexpectedToken(_, unexpected_token: String)) => { |
615 | let err: String = format!( |
616 | "Expected `,` after ` {}`, found ` {unexpected_token}`" , |
617 | ret.to_str(), |
618 | ); |
619 | return Err(parts.generate_error_with_next_span(&err)); |
620 | } |
621 | Err(TokenCheck::UnexpectedEnd(tokens: String)) => { |
622 | let err: String = format!("Expected `,` after ` {}{tokens}`" , ret.to_str()); |
623 | return Err(parts.generate_error(&err)); |
624 | } |
625 | Ok(()) => {} |
626 | } |
627 | Ok(Some(ret)) |
628 | } |
629 | |
630 | enum BlockKind { |
631 | Closure(Vec<TokenTree>), |
632 | ClosureWrappingAsync(Vec<TokenTree>), |
633 | AsyncClosure(Vec<TokenTree>), |
634 | AsyncBlock, |
635 | } |
636 | |
637 | impl BlockKind { |
638 | #[doc (alias = "get_closure" )] |
639 | fn closure(self) -> Option<Vec<TokenTree>> { |
640 | match self { |
641 | Self::AsyncBlock => None, |
642 | Self::Closure(c: Vec) | Self::ClosureWrappingAsync(c: Vec) | Self::AsyncClosure(c: Vec) => Some(c), |
643 | } |
644 | } |
645 | } |
646 | |
647 | fn check_move_after_async(parts: &mut PeekableProcIter) -> Result<(), TokenStream> { |
648 | let span: Option = parts.current_span; |
649 | match parts.next() { |
650 | Some(TokenTree::Ident(i: Ident)) if i.to_string() == "move" => Ok(()), |
651 | // The next checks are just for better error messages. |
652 | Some(TokenTree::Ident(i: Ident)) => { |
653 | let err: String = format!("Expected `move` after `async`, found ` {i}`" ); |
654 | Err(parts.generate_error(&err)) |
655 | } |
656 | Some(TokenTree::Punct(p: Punct)) => { |
657 | let err: String = format!("Expected `move` after `async`, found ` {p}`" ); |
658 | Err(parts.generate_error(&err)) |
659 | } |
660 | Some(TokenTree::Group(g: Group)) => { |
661 | let err: String = format!( |
662 | "Expected `move` after `async`, found ` {}`" , |
663 | delimiter_to_string(g.delimiter(), true), |
664 | ); |
665 | Err(parts.generate_error(&err)) |
666 | } |
667 | _ => Err(parts.generate_error_with_span(message:"Expected `move` after `async`" , span)), |
668 | } |
669 | } |
670 | |
671 | fn check_async_syntax(parts: &mut PeekableProcIter) -> Result<BlockKind, TokenStream> { |
672 | check_move_after_async(parts)?; |
673 | match parts.peek() { |
674 | Some(TokenTree::Punct(p: &Punct)) if p.to_string() == "|" => { |
675 | parts.next(); |
676 | Ok(BlockKind::AsyncClosure(closure(parts)?)) |
677 | } |
678 | Some(TokenTree::Punct(p: &Punct)) => { |
679 | let err: String = format!("Expected closure or block after `async move`, found ` {p}`" ); |
680 | Err(parts.generate_error_with_next_span(&err)) |
681 | } |
682 | Some(TokenTree::Group(g: &Group)) if g.delimiter() == Delimiter::Brace => Ok(BlockKind::AsyncBlock), |
683 | Some(TokenTree::Group(g: &Group)) => { |
684 | let err: String = format!( |
685 | "Expected closure or block after `async move`, found ` {}`" , |
686 | delimiter_to_string(g.delimiter(), true), |
687 | ); |
688 | Err(parts.generate_error_with_next_span(&err)) |
689 | } |
690 | _ => Err(parts.generate_error(message:"Expected closure or block after `async move`" )), |
691 | } |
692 | } |
693 | |
694 | // Returns `true` if this is an async context. |
695 | fn check_before_closure(parts: &mut PeekableProcIter) -> Result<BlockKind, TokenStream> { |
696 | let is_async = match parts.peek() { |
697 | Some(TokenTree::Ident(i)) if i.to_string() == "move" => false, |
698 | Some(TokenTree::Ident(i)) if i.to_string() == "async" => true, |
699 | Some(TokenTree::Ident(i)) if i.to_string() == "default" => { |
700 | let span = parts.next_span; |
701 | let ret = return_kind(parts)?; |
702 | let err = format!("Missing `@` before ` {}`" , ret.keyword()); |
703 | return Err(parts.generate_error_with_span(&err, span)); |
704 | } |
705 | Some(TokenTree::Punct(p)) if p.to_string() == "|" => { |
706 | return Err(parts.generate_error_with_next_span( |
707 | "Closure needs to be \"moved \" so please add `move` before closure" , |
708 | )); |
709 | } |
710 | _ => { |
711 | return Err( |
712 | parts.generate_error_with_next_span("Missing `move` and closure declaration" ) |
713 | ) |
714 | } |
715 | }; |
716 | parts.next(); |
717 | if is_async { |
718 | return check_async_syntax(parts); |
719 | } |
720 | match parts.peek() { |
721 | Some(TokenTree::Punct(p)) if p.to_string() == "|" => {} |
722 | Some(x) => { |
723 | let err = format!("Expected closure, found ` {x}`" ); |
724 | return Err(parts.generate_error_with_next_span(&err)); |
725 | } |
726 | None => return Err(parts.generate_error("Expected closure" )), |
727 | } |
728 | parts.next(); |
729 | |
730 | let closure = closure(parts)?; |
731 | match parts.peek() { |
732 | Some(TokenTree::Ident(i)) if i.to_string() == "async" => { |
733 | parts.next(); |
734 | check_move_after_async(parts)?; |
735 | match parts.peek() { |
736 | Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => { |
737 | Ok(BlockKind::ClosureWrappingAsync(closure)) |
738 | } |
739 | // The next matchings are for better error messages. |
740 | Some(TokenTree::Punct(p)) => { |
741 | let err = format!("Expected block after `| async move`, found ` {p}`" ); |
742 | Err(parts.generate_error_with_next_span(&err)) |
743 | } |
744 | Some(TokenTree::Group(g)) => { |
745 | let err = format!( |
746 | "Expected block after `| async move`, found ` {}`" , |
747 | delimiter_to_string(g.delimiter(), true), |
748 | ); |
749 | Err(parts.generate_error_with_next_span(&err)) |
750 | } |
751 | _ => { |
752 | Err(parts.generate_error_with_next_span("Expected block after `| async move`" )) |
753 | } |
754 | } |
755 | } |
756 | _ => Ok(BlockKind::Closure(closure)), |
757 | } |
758 | } |
759 | |
760 | #[doc (alias = "get_closure" )] |
761 | fn closure(parts: &mut PeekableProcIter) -> Result<Vec<TokenTree>, TokenStream> { |
762 | let mut ret: Vec = Vec::new(); |
763 | |
764 | loop { |
765 | let span: Option = parts.current_span; |
766 | match parts.next() { |
767 | Some(TokenTree::Punct(p: Punct)) if p.to_string() == "|" => break, |
768 | Some(x: TokenTree) => ret.push(x), |
769 | None => return Err(parts.generate_error_with_span(message:"Unexpected end 3" , span)), |
770 | } |
771 | } |
772 | Ok(ret) |
773 | } |
774 | |
775 | pub fn tokens_to_string(parts: impl Iterator<Item = TokenTree>) -> String { |
776 | let mut ret = String::new(); |
777 | // This is used in case of "if ident" or other similar cases. |
778 | let mut prev_is_ident = false; |
779 | let handle_ident_like = |i: String, ret: &mut String, prev_is_ident: &mut bool| { |
780 | if *prev_is_ident { |
781 | ret.push(' ' ); |
782 | } |
783 | ret.push_str(&i); |
784 | *prev_is_ident = true; |
785 | }; |
786 | |
787 | for token in parts { |
788 | match token { |
789 | TokenTree::Punct(p) => { |
790 | prev_is_ident = false; |
791 | ret.push_str(&p.to_string()); |
792 | } |
793 | TokenTree::Ident(i) => handle_ident_like(i.to_string(), &mut ret, &mut prev_is_ident), |
794 | TokenTree::Literal(l) => handle_ident_like(l.to_string(), &mut ret, &mut prev_is_ident), |
795 | TokenTree::Group(g) => { |
796 | prev_is_ident = false; |
797 | ret.push_str(&group_to_string(&g)); |
798 | } |
799 | } |
800 | } |
801 | ret |
802 | } |
803 | |
804 | fn build_closure( |
805 | parts: PeekableProcIter, |
806 | elements: Vec<ElemToClone>, |
807 | return_kind: Option<WrapperKind>, |
808 | kind: BlockKind, |
809 | ) -> TokenStream { |
810 | let mut body = TokenStream::new(); |
811 | |
812 | for el in &elements { |
813 | let stream: TokenStream = el |
814 | .to_str_after(&return_kind) |
815 | .parse() |
816 | .expect("failed to convert element after" ); |
817 | body.extend(stream.into_iter().collect::<Vec<_>>()); |
818 | } |
819 | body.extend(parts.collect::<Vec<_>>()); |
820 | |
821 | // To prevent to lose the spans in case some errors occur in the code, we need to keep `body`! |
822 | // |
823 | // If we replaced everything that follows with a `format!`, it'd look like this: |
824 | // |
825 | // format!( |
826 | // "{{\n{}\nmove |{}| {{\n{}\nlet ____ret = {{ {} }};\n____ret\n}}\n}}", |
827 | // elements |
828 | // .iter() |
829 | // .map(|x| x.to_str_before()) |
830 | // .collect::<Vec<_>>() |
831 | // .join("\n"), |
832 | // closure, |
833 | // elements |
834 | // .iter() |
835 | // .map(|x| x.to_str_after(&return_kind)) |
836 | // .collect::<Vec<_>>() |
837 | // .join("\n"), |
838 | // body, |
839 | // ) |
840 | let mut ret: Vec<TokenTree> = vec![]; |
841 | for el in elements { |
842 | let stream: TokenStream = el |
843 | .to_str_before() |
844 | .parse() |
845 | .expect("failed to convert element" ); |
846 | ret.extend(stream.into_iter().collect::<Vec<_>>()); |
847 | } |
848 | |
849 | // This part is creating the TokenStream using the variables that needs to be cloned (from the |
850 | // @weak and @strong annotations). |
851 | let mut inner: Vec<TokenTree> = Vec::new(); |
852 | if matches!(kind, BlockKind::ClosureWrappingAsync(_)) { |
853 | inner.extend(vec![ |
854 | TokenTree::Ident(Ident::new("async" , Span::call_site())), |
855 | TokenTree::Ident(Ident::new("move" , Span::call_site())), |
856 | ]); |
857 | } |
858 | |
859 | let is_async_closure_kind = matches!(kind, BlockKind::AsyncClosure(_)); |
860 | if let Some(closure) = kind.closure() { |
861 | if is_async_closure_kind { |
862 | ret.push(TokenTree::Ident(Ident::new("async" , Span::call_site()))); |
863 | } |
864 | ret.extend(vec![ |
865 | TokenTree::Ident(Ident::new("move" , Span::call_site())), |
866 | TokenTree::Punct(Punct::new('|' , Spacing::Alone)), |
867 | ]); |
868 | ret.extend(closure); |
869 | ret.extend(vec![TokenTree::Punct(Punct::new('|' , Spacing::Alone))]); |
870 | } else { |
871 | ret.extend(vec![ |
872 | TokenTree::Ident(Ident::new("async" , Span::call_site())), |
873 | TokenTree::Ident(Ident::new("move" , Span::call_site())), |
874 | ]); |
875 | } |
876 | // The commented lines that follow *might* be useful, don't know. Just in case, I'm keeping |
877 | // them around. You're welcome future me! |
878 | inner.extend(vec![ |
879 | // TokenTree::Ident(Ident::new("let", Span::call_site())), |
880 | // TokenTree::Ident(Ident::new("____ret", Span::call_site())), |
881 | // TokenTree::Punct(Punct::new('=', Spacing::Alone)), |
882 | TokenTree::Group(Group::new(Delimiter::Brace, body)), |
883 | // TokenTree::Punct(Punct::new(';', Spacing::Alone)), |
884 | // TokenTree::Ident(Ident::new("____ret", Span::call_site())), |
885 | ]); |
886 | let mut inners = TokenStream::new(); |
887 | inners.extend(inner); |
888 | ret.extend(vec![TokenTree::Group(Group::new(Delimiter::Brace, inners))]); |
889 | |
890 | let mut rets = TokenStream::new(); |
891 | rets.extend(ret); |
892 | |
893 | TokenTree::Group(Group::new(Delimiter::Brace, rets)).into() |
894 | } |
895 | |
896 | pub(crate) fn clone_inner(item: TokenStream) -> TokenStream { |
897 | let mut parts: PeekableProcIter = item.into(); |
898 | let mut elements = Vec::new(); |
899 | let mut prev_is_ident = false; |
900 | |
901 | loop { |
902 | let prev = parts.current_span; |
903 | match parts.next() { |
904 | Some(TokenTree::Punct(ref p)) => { |
905 | let p_s = p.to_string(); |
906 | if p_s == "=" && parts.peek().map_or_else(|| false, |n| is_punct(n, ">" )) { |
907 | parts.next(); |
908 | break; |
909 | } else if p_s == "@" { |
910 | if let Err(e) = parse_ident(&mut parts, &mut elements) { |
911 | return e; |
912 | } |
913 | prev_is_ident = true; |
914 | } else if p_s == "," { |
915 | assert!(prev_is_ident, "Unexpected `,`" ); |
916 | prev_is_ident = false; |
917 | } else if p_s == "|" { |
918 | assert!( |
919 | !elements.is_empty(), |
920 | "If you have nothing to clone, no need to use this macro!" |
921 | ); |
922 | return parts.generate_error("Expected `=>` before closure" ); |
923 | } |
924 | } |
925 | Some(TokenTree::Ident(i)) => { |
926 | let err = format!( |
927 | "Unexpected ident ` {i}`: you need to specify if this is a weak or a strong \ |
928 | clone." , |
929 | ); |
930 | return parts.generate_error(&err); |
931 | } |
932 | Some(t) => { |
933 | let err = format!("Unexpected token ` {t}`" ); |
934 | return parts.generate_error(&err); |
935 | } |
936 | None => return parts.generate_error_with_span("Unexpected end 4" , prev), |
937 | } |
938 | } |
939 | assert!( |
940 | !elements.is_empty(), |
941 | "If you have nothing to clone, no need to use this macro!" |
942 | ); |
943 | let return_kind = match parse_return_kind(&mut parts) { |
944 | Ok(r) => r, |
945 | Err(e) => return e, |
946 | }; |
947 | let kind = match check_before_closure(&mut parts) { |
948 | Ok(r) => r, |
949 | Err(e) => return e, |
950 | }; |
951 | build_closure(parts, elements, return_kind, kind) |
952 | } |
953 | |