1use std::cell::{Cell, RefCell};
7
8use proc_macro::TokenStream;
9use proc_macro_crate::{FoundCrate, crate_name};
10use proc_macro2::Span;
11use quote::{quote, quote_spanned};
12use syn::parse::{Parse, ParseStream, Result as ParseResult};
13use syn::visit::{self, Visit};
14use syn::visit_mut::{self, VisitMut};
15use syn::{Expr, ExprClosure, Ident, Index, Pat, Path, Token, Type, parse_quote};
16
17struct CaptureInput {
22 grammar: Expr,
23 _arrow: Token![=>],
24 result_expr: Expr,
25}
26
27impl Parse for CaptureInput {
28 fn parse(input: ParseStream) -> ParseResult<Self> {
29 let grammar = input.parse()?;
30 let _arrow = input.parse::<Token![=>]>()?;
31 let result_expr = input.parse()?;
32 if !input.is_empty() {
33 return Err(input.error("unexpected tokens after `capture!( … => … )`"));
34 }
35 Ok(CaptureInput {
36 grammar,
37 _arrow,
38 result_expr,
39 })
40 }
41}
42
43#[derive(Clone, PartialEq)]
44enum BindKind {
45 Single,
46 Multiple,
47 Optional,
48}
49
50fn parse_kind_and_ident(input: ParseStream) -> ParseResult<(BindKind, Ident)> {
52 if input.peek(Token![*]) {
53 input.parse::<Token![*]>()?;
54 Ok((BindKind::Multiple, input.parse()?))
55 } else if input.peek(Token![?]) {
56 input.parse::<Token![?]>()?;
57 Ok((BindKind::Optional, input.parse()?))
58 } else {
59 Ok((BindKind::Single, input.parse()?))
60 }
61}
62
63#[derive(Clone)]
64struct TypedBindTarget {
65 kind: BindKind,
66 ident: Ident,
67 ty: Option<Type>,
68}
69
70fn parse_typed_target(input: ParseStream) -> ParseResult<TypedBindTarget> {
71 let (kind, ident) = parse_kind_and_ident(input)?;
72 let ty = if input.peek(Token![as]) {
73 input.parse::<Token![as]>()?;
74 Some(input.parse::<Type>()?)
75 } else {
76 None
77 };
78 Ok(TypedBindTarget { kind, ident, ty })
79}
80
81struct BindInfo {
83 parser: Expr,
84 ident: Ident,
85 kind: BindKind,
86 value_ty: Option<Type>,
87 span_ident: Option<Ident>,
88 span_kind: Option<BindKind>,
89 span_ty: Option<Type>,
90}
91
92impl Parse for BindInfo {
93 fn parse(input: ParseStream) -> ParseResult<Self> {
94 let parser: Expr = input.parse()?;
95 let _: Token![,] = input.parse()?;
96 let value_target = parse_typed_target(input)?;
97
98 let (span_ident, span_kind, span_ty) = if input.peek(Token![,]) {
99 let _: Token![,] = input.parse()?;
100 let span_target = parse_typed_target(input)?;
101 (
102 Some(span_target.ident),
103 Some(span_target.kind),
104 span_target.ty,
105 )
106 } else {
107 (None, None, None)
108 };
109
110 if !input.is_empty() {
111 return Err(input.error(
112 "unexpected tokens in `bind!` (expected `bind!(parser, target [, span_target])`)",
113 ));
114 }
115
116 Ok(BindInfo {
117 parser,
118 ident: value_target.ident,
119 kind: value_target.kind,
120 value_ty: value_target.ty,
121 span_ident,
122 span_kind,
123 span_ty,
124 })
125 }
126}
127
128struct BindSpanInfo {
130 parser: Expr,
131 span_ident: Ident,
132 kind: BindKind,
133 ty: Option<Type>,
134}
135
136impl Parse for BindSpanInfo {
137 fn parse(input: ParseStream) -> ParseResult<Self> {
138 let parser: Expr = input.parse()?;
139 let _: Token![,] = input.parse()?;
140 let target = parse_typed_target(input)?;
141 if !input.is_empty() {
142 return Err(input.error("unexpected tokens in `bind_span!`"));
143 }
144 Ok(BindSpanInfo {
145 parser,
146 span_ident: target.ident,
147 kind: target.kind,
148 ty: target.ty,
149 })
150 }
151}
152
153struct BindSliceInfo {
155 parser: Expr,
156 slice_ident: Ident,
157 kind: BindKind,
158 ty: Option<Type>,
159}
160
161impl Parse for BindSliceInfo {
162 fn parse(input: ParseStream) -> ParseResult<Self> {
163 let parser: Expr = input.parse()?;
164 let _: Token![,] = input.parse()?;
165 let target = parse_typed_target(input)?;
166 if !input.is_empty() {
167 return Err(input.error("unexpected tokens in `bind_slice!`"));
168 }
169 Ok(BindSliceInfo {
170 parser,
171 slice_ident: target.ident,
172 kind: target.kind,
173 ty: target.ty,
174 })
175 }
176}
177
178#[derive(Clone)]
179struct TypedBinding {
180 ident: Ident,
181 ty: Option<Type>,
182}
183
184#[derive(Default, Clone)]
186struct BindRegistry {
187 single_values: Vec<TypedBinding>,
188 single_spans: Vec<TypedBinding>,
189 multiple_values: Vec<TypedBinding>,
190 multiple_spans: Vec<TypedBinding>,
191 optional_values: Vec<TypedBinding>,
192 optional_spans: Vec<TypedBinding>,
193}
194
195impl BindRegistry {
196 fn types_compatible(a: &Option<Type>, b: &Option<Type>) -> bool {
197 match (a, b) {
198 (None, _) | (_, None) => true,
199 (Some(t1), Some(t2)) => quote!(#t1).to_string() == quote!(#t2).to_string(),
200 }
201 }
202
203 fn value_kind_if_present(&self, id: &Ident) -> Option<BindKind> {
204 if self.single_values.iter().any(|b| b.ident == *id) {
205 Some(BindKind::Single)
206 } else if self.multiple_values.iter().any(|b| b.ident == *id) {
207 Some(BindKind::Multiple)
208 } else if self.optional_values.iter().any(|b| b.ident == *id) {
209 Some(BindKind::Optional)
210 } else {
211 None
212 }
213 }
214
215 fn span_kind_if_present(&self, id: &Ident) -> Option<BindKind> {
216 if self.single_spans.iter().any(|b| b.ident == *id) {
217 Some(BindKind::Single)
218 } else if self.multiple_spans.iter().any(|b| b.ident == *id) {
219 Some(BindKind::Multiple)
220 } else if self.optional_spans.iter().any(|b| b.ident == *id) {
221 Some(BindKind::Optional)
222 } else {
223 None
224 }
225 }
226
227 fn ident_in_any_span_list(&self, id: &Ident) -> bool {
228 self.span_kind_if_present(id).is_some()
229 }
230
231 fn ident_in_any_value_list(&self, id: &Ident) -> bool {
232 self.value_kind_if_present(id).is_some()
233 }
234
235 fn values_mut(&mut self, kind: &BindKind) -> &mut Vec<TypedBinding> {
236 match kind {
237 BindKind::Single => &mut self.single_values,
238 BindKind::Multiple => &mut self.multiple_values,
239 BindKind::Optional => &mut self.optional_values,
240 }
241 }
242
243 fn spans_mut(&mut self, kind: &BindKind) -> &mut Vec<TypedBinding> {
244 match kind {
245 BindKind::Single => &mut self.single_spans,
246 BindKind::Multiple => &mut self.multiple_spans,
247 BindKind::Optional => &mut self.optional_spans,
248 }
249 }
250
251 fn merge_into(
252 list: &mut Vec<TypedBinding>,
253 ident: Ident,
254 ty: Option<Type>,
255 ) -> std::result::Result<(), syn::Error> {
256 if let Some(existing) = list.iter_mut().find(|e| e.ident == ident) {
257 if !Self::types_compatible(&existing.ty, &ty) {
258 return Err(syn::Error::new_spanned(
259 &ident,
260 format!(
261 "conflicting explicit `as` types for repeated binding `{}` in `capture!`",
262 ident
263 ),
264 ));
265 }
266 if existing.ty.is_none()
267 && let Some(t) = ty
268 {
269 existing.ty = Some(t);
270 }
271 Ok(())
272 } else {
273 list.push(TypedBinding { ident, ty });
274 Ok(())
275 }
276 }
277
278 fn register_value(
281 &mut self,
282 ident: Ident,
283 ty: Option<Type>,
284 kind: &BindKind,
285 ) -> std::result::Result<(), syn::Error> {
286 if self.ident_in_any_span_list(&ident) {
287 return Err(syn::Error::new_spanned(
288 &ident,
289 format!(
290 "binding `{}` is already used as a span binding; value and span captures cannot share an identifier in `capture!`",
291 ident
292 ),
293 ));
294 }
295 if let Some(existing) = self.value_kind_if_present(&ident)
296 && existing != *kind
297 {
298 return Err(syn::Error::new_spanned(
299 &ident,
300 format!(
301 "binding `{}` is used with incompatible sigils (for example `x` vs `*x` vs `?x`) in the same `capture!`",
302 ident
303 ),
304 ));
305 }
306 let list = self.values_mut(kind);
307 Self::merge_into(list, ident, ty)
308 }
309
310 fn register_span(
311 &mut self,
312 ident: Ident,
313 ty: Option<Type>,
314 kind: &BindKind,
315 ) -> std::result::Result<(), syn::Error> {
316 if self.ident_in_any_value_list(&ident) {
317 return Err(syn::Error::new_spanned(
318 &ident,
319 format!(
320 "binding `{}` is already used as a value binding; value and span captures cannot share an identifier in `capture!`",
321 ident
322 ),
323 ));
324 }
325 if let Some(existing) = self.span_kind_if_present(&ident)
326 && existing != *kind
327 {
328 return Err(syn::Error::new_spanned(
329 &ident,
330 format!(
331 "span binding `{}` is used with incompatible sigils in the same `capture!`",
332 ident
333 ),
334 ));
335 }
336 let list = self.spans_mut(kind);
337 Self::merge_into(list, ident, ty)
338 }
339}
340
341struct BindCollector {
343 reg: BindRegistry,
344 errors: Option<syn::Error>,
345}
346
347impl BindCollector {
348 fn bump_err(&mut self, e: syn::Error) {
349 self.errors = Some(match self.errors.take() {
350 None => e,
351 Some(mut prev) => {
352 prev.combine(e);
353 prev
354 }
355 });
356 }
357
358 fn collect(expr: &Expr) -> std::result::Result<BindRegistry, syn::Error> {
359 let mut c = Self {
360 reg: BindRegistry::default(),
361 errors: None,
362 };
363 c.visit_expr(expr);
364 if let Some(e) = c.errors {
365 Err(e)
366 } else {
367 Ok(c.reg)
368 }
369 }
370}
371
372impl<'ast> Visit<'ast> for BindCollector {
373 fn visit_expr(&mut self, expr: &'ast Expr) {
374 if let Expr::Macro(m) = expr {
375 if m.mac.path.is_ident("bind") {
376 let info = match m.mac.parse_body::<BindInfo>() {
377 Ok(i) => i,
378 Err(e) => {
379 self.bump_err(e);
380 visit::visit_expr(self, expr);
381 return;
382 }
383 };
384 if let Some(ref span_ident) = info.span_ident
385 && *span_ident == info.ident
386 {
387 self.bump_err(syn::Error::new_spanned(
388 span_ident,
389 "`bind!` value and span targets must use distinct identifiers",
390 ));
391 self.visit_expr(&info.parser);
392 return;
393 }
394 if let Err(e) =
395 self.reg
396 .register_value(info.ident.clone(), info.value_ty.clone(), &info.kind)
397 {
398 self.bump_err(e);
399 }
400 if let Some(span_ident) = &info.span_ident {
401 let span_kind = info.span_kind.as_ref().unwrap();
402 if let Err(e) =
403 self.reg
404 .register_span(span_ident.clone(), info.span_ty.clone(), span_kind)
405 {
406 self.bump_err(e);
407 }
408 }
409 self.visit_expr(&info.parser);
410 return;
411 }
412 if m.mac.path.is_ident("bind_span") {
413 let info = match m.mac.parse_body::<BindSpanInfo>() {
414 Ok(i) => i,
415 Err(e) => {
416 self.bump_err(e);
417 visit::visit_expr(self, expr);
418 return;
419 }
420 };
421 if let Err(e) =
422 self.reg
423 .register_span(info.span_ident.clone(), info.ty.clone(), &info.kind)
424 {
425 self.bump_err(e);
426 }
427 self.visit_expr(&info.parser);
428 return;
429 }
430 if m.mac.path.is_ident("bind_slice") {
431 let info = match m.mac.parse_body::<BindSliceInfo>() {
432 Ok(i) => i,
433 Err(e) => {
434 self.bump_err(e);
435 visit::visit_expr(self, expr);
436 return;
437 }
438 };
439 if let Err(e) =
440 self.reg
441 .register_value(info.slice_ident.clone(), info.ty.clone(), &info.kind)
442 {
443 self.bump_err(e);
444 }
445 self.visit_expr(&info.parser);
446 return;
447 }
448 }
449 visit::visit_expr(self, expr);
450 }
451}
452
453fn build_capture_mres_tuple(registry: &BindRegistry) -> proc_macro2::TokenStream {
455 let build_bucket = |values: &[TypedBinding], spans: &[TypedBinding], is_vec: bool| {
456 let wrap = |inner: proc_macro2::TokenStream| {
457 if is_vec {
458 quote! { ::std::vec::Vec<#inner> }
459 } else {
460 quote! { ::std::option::Option<#inner> }
461 }
462 };
463 let mut pieces = Vec::new();
464 for b in values.iter() {
465 let inner = if let Some(ty) = &b.ty {
466 quote! { #ty }
467 } else {
468 quote! { _ }
469 };
470 pieces.push(wrap(inner));
471 }
472 for b in spans.iter() {
473 let inner = if let Some(ty) = &b.ty {
474 quote! { #ty }
475 } else {
476 quote! { (_, _) }
477 };
478 pieces.push(wrap(inner));
479 }
480 if pieces.is_empty() {
481 quote! { () }
482 } else {
483 quote! { ( #(#pieces,)* ) }
484 }
485 };
486
487 let s_ty = build_bucket(®istry.single_values, ®istry.single_spans, false);
488 let m_ty = build_bucket(®istry.multiple_values, ®istry.multiple_spans, true);
489 let o_ty = build_bucket(®istry.optional_values, ®istry.optional_spans, false);
490 quote! { (#s_ty, #m_ty, #o_ty) }
491}
492
493fn build_factory_mres_tuple(registry: &BindRegistry) -> (proc_macro2::TokenStream, Vec<Ident>) {
522 let mut gen_names: Vec<Ident> = Vec::new();
523 let mut next_ty = |span: Span| -> proc_macro2::TokenStream {
524 let n = gen_names.len();
525 let id = Ident::new(&format!("__BindT{n}"), span);
526 gen_names.push(id.clone());
527 quote! { #id }
528 };
529
530 let mut build_bucket = |values: &[TypedBinding], spans: &[TypedBinding], is_vec: bool| {
531 let wrap = |inner: proc_macro2::TokenStream| {
532 if is_vec {
533 quote! { ::std::vec::Vec<#inner> }
534 } else {
535 quote! { ::std::option::Option<#inner> }
536 }
537 };
538 let mut pieces = Vec::new();
539 for b in values.iter() {
540 pieces.push(wrap(next_ty(b.ident.span())));
541 }
542 for b in spans.iter() {
543 let inner = if let Some(ty) = &b.ty {
544 quote! { #ty }
545 } else {
546 quote! { (usize, usize) }
547 };
548 pieces.push(wrap(inner));
549 }
550 if pieces.is_empty() {
551 quote! { () }
552 } else {
553 quote! { ( #(#pieces,)* ) }
554 }
555 };
556
557 let s_ty = build_bucket(®istry.single_values, ®istry.single_spans, false);
558 let m_ty = build_bucket(®istry.multiple_values, ®istry.multiple_spans, true);
559 let o_ty = build_bucket(®istry.optional_values, ®istry.optional_spans, false);
560 (quote! { (#s_ty, #m_ty, #o_ty) }, gen_names)
561}
562
563fn snapshot_bind_lets(
564 registry: &BindRegistry,
565) -> (
566 Vec<proc_macro2::TokenStream>,
567 Vec<proc_macro2::TokenStream>,
568 Vec<proc_macro2::TokenStream>,
569) {
570 let mut single_lets = Vec::new();
571 for (i, b) in registry
572 .single_values
573 .iter()
574 .chain(®istry.single_spans)
575 .enumerate()
576 {
577 let idx = Index::from(i);
578 let id = &b.ident;
579 single_lets.push(quote! {
580 #[allow(unused_variables)]
581 let #id = __single.#idx;
582 });
583 }
584 let mut multiple_lets = Vec::new();
585 for (i, b) in registry
586 .multiple_values
587 .iter()
588 .chain(®istry.multiple_spans)
589 .enumerate()
590 {
591 let idx = Index::from(i);
592 let id = &b.ident;
593 multiple_lets.push(quote! {
594 #[allow(unused_variables)]
595 let #id = &__multiple.#idx;
596 });
597 }
598 let mut optional_lets = Vec::new();
599 for (i, b) in registry
600 .optional_values
601 .iter()
602 .chain(®istry.optional_spans)
603 .enumerate()
604 {
605 let idx = Index::from(i);
606 let id = &b.ident;
607 optional_lets.push(quote! {
608 #[allow(unused_variables)]
609 let #id = __optional.#idx;
610 });
611 }
612 (single_lets, multiple_lets, optional_lets)
613}
614
615struct UseBindSite {
617 site: usize,
618 ctx_ident: Ident,
619 inner: proc_macro2::TokenStream,
620}
621
622fn emit_use_binds_sites(
624 sites: &[UseBindSite],
625 registry: &BindRegistry,
626 marser: &Path,
627 mres: &proc_macro2::TokenStream,
628 mres_generics: &[Ident],
629) -> proc_macro2::TokenStream {
630 if sites.is_empty() {
631 return quote! {};
632 }
633
634 let (single_lets, multiple_lets, optional_lets) = snapshot_bind_lets(registry);
635
636 let const_site_params = quote! { <const __SITE: usize> };
637 let build_inline_params = if mres_generics.is_empty() {
638 quote! { <const __SITE: usize> }
639 } else {
640 quote! { <const __SITE: usize, #(#mres_generics),*> }
641 };
642
643 let arms: Vec<_> = sites
644 .iter()
645 .map(|s| {
646 let lit = syn::LitInt::new(&format!("{}", s.site), Span::call_site());
647 let ctx = &s.ctx_ident;
648 let inner = &s.inner;
649 quote! {
650 #lit => {
651 let #ctx = __ctx;
652 #inner
653 }
654 }
655 })
656 .collect();
657
658 quote! {
659 struct __UseBindsSite<const __SITE: usize>;
660
661 impl #const_site_params ::core::clone::Clone for __UseBindsSite<__SITE> {
662 fn clone(&self) -> Self {
663 *self
664 }
665 }
666
667 impl #const_site_params ::core::marker::Copy for __UseBindsSite<__SITE> {}
668
669 impl #build_inline_params #marser::error::BuildInlineError<#mres> for __UseBindsSite<__SITE> {
670 fn build_inline_error<'__snap>(
671 &self,
672 __ctx: #marser::error::MatchDiagCtx,
673 __snap: <#mres as #marser::parser::capture::MatchResult>::Snapshot<'__snap>,
674 ) -> #marser::error::InlineError
675 where
676 #mres: '__snap,
677 {
678 let __single = &__snap.0;
679 let __multiple = &__snap.1;
680 let __optional = &__snap.2;
681 #(#single_lets)*
682 #(#multiple_lets)*
683 #(#optional_lets)*
684 match __SITE {
685 #(#arms)*
686 _ => ::core::unreachable!("use_binds site out of range"),
687 }
688 }
689 }
690 }
691}
692
693fn parse_use_binds_closure(
694 closure: ExprClosure,
695) -> std::result::Result<(Ident, proc_macro2::TokenStream), syn::Error> {
696 let ctx_ident = match closure.inputs.iter().next() {
697 Some(Pat::Type(pt)) => {
698 if let Pat::Ident(pi) = pt.pat.as_ref() {
699 pi.ident.clone()
700 } else {
701 Ident::new("ctx", Span::call_site())
702 }
703 }
704 Some(Pat::Ident(pi)) => pi.ident.clone(),
705 _ => Ident::new("ctx", Span::call_site()),
706 };
707
708 let inner = match closure.body.as_ref() {
709 Expr::Block(b) => {
710 let stmts = b.block.stmts.iter();
711 quote! { #(#stmts)* }
712 }
713 expr => quote! { #expr },
714 };
715 Ok((ctx_ident, inner))
716}
717
718struct UseBindsRewriter {
719 sites: RefCell<Vec<UseBindSite>>,
720 next_site: Cell<usize>,
721 errors: RefCell<Option<syn::Error>>,
722}
723
724impl UseBindsRewriter {
725 fn bump_err(&self, e: syn::Error) {
726 let mut slot = self.errors.borrow_mut();
727 *slot = Some(match slot.take() {
728 None => e,
729 Some(mut prev) => {
730 prev.combine(e);
731 prev
732 }
733 });
734 }
735}
736
737impl VisitMut for UseBindsRewriter {
738 fn visit_expr_mut(&mut self, expr: &mut Expr) {
739 if let Expr::Macro(m) = expr
740 && m.mac.path.is_ident("use_binds")
741 {
742 let closure = match m.mac.parse_body::<ExprClosure>() {
743 Ok(c) => c,
744 Err(e) => {
745 self.bump_err(e);
746 return;
747 }
748 };
749 let (ctx_ident, inner) = match parse_use_binds_closure(closure) {
750 Ok(x) => x,
751 Err(e) => {
752 self.bump_err(e);
753 return;
754 }
755 };
756 let site = self.next_site.get();
757 self.next_site.set(site + 1);
758 self.sites.borrow_mut().push(UseBindSite {
759 site,
760 ctx_ident,
761 inner,
762 });
763 let lit = syn::LitInt::new(&format!("{}", site), Span::call_site());
764 match syn::parse2::<Expr>(quote! { __UseBindsSite::<#lit> }) {
766 Ok(expanded) => *expr = expanded,
767 Err(e) => self.bump_err(e),
768 }
769 return;
770 }
771 visit_mut::visit_expr_mut(self, expr);
772 }
773}
774
775struct UseBindsInResultChecker {
777 error: Option<syn::Error>,
778}
779
780impl<'ast> Visit<'ast> for UseBindsInResultChecker {
781 fn visit_expr(&mut self, expr: &'ast Expr) {
782 if let Expr::Macro(m) = expr
783 && m.mac.path.is_ident("use_binds")
784 {
785 self.error = Some(syn::Error::new_spanned(
786 m.mac.path.get_ident().unwrap(),
787 "`use_binds!` is only allowed in the grammar of `capture!`, not in the `=>` result expression",
788 ));
789 return;
790 }
791 visit::visit_expr(self, expr);
792 }
793}
794
795struct BindMacroExpander {
801 marser_path: Path,
802 errors: Option<syn::Error>,
803}
804
805impl BindMacroExpander {
806 fn new(marser_path: Path) -> Self {
807 Self {
808 marser_path,
809 errors: None,
810 }
811 }
812
813 fn bump_err(&mut self, e: syn::Error) {
814 self.errors = Some(match self.errors.take() {
815 None => e,
816 Some(mut prev) => {
817 prev.combine(e);
818 prev
819 }
820 });
821 }
822
823 fn take_errors(self) -> Option<syn::Error> {
824 self.errors
825 }
826}
827
828impl VisitMut for BindMacroExpander {
829 fn visit_expr_mut(&mut self, i: &mut Expr) {
830 if let Expr::Macro(m) = i {
831 if m.mac.path.is_ident("bind") {
832 let info = match m.mac.parse_body::<BindInfo>() {
833 Ok(info) => info,
834 Err(e) => {
835 self.bump_err(e);
836 visit_mut::visit_expr_mut(self, i);
837 return;
838 }
839 };
840 let id = &info.ident;
841 let parser = &info.parser;
842 let bind_span = id.span();
843 let rewrite = if let Some(span_id) = &info.span_ident {
844 let marser = self.marser_path.clone();
845 quote_spanned! {bind_span=>
846 #marser::parser::capture::bind_span(
847 #marser::parser::capture::bind_result(#parser, #id),
848 #span_id
849 )
850 }
851 } else {
852 let marser = self.marser_path.clone();
853 quote_spanned! {bind_span=>
854 #marser::parser::capture::bind_result(#parser, #id)
855 }
856 };
857 match syn::parse2(rewrite) {
858 Ok(expr) => *i = expr,
859 Err(e) => self.bump_err(e),
860 }
861 return;
862 }
863
864 if m.mac.path.is_ident("bind_span") {
865 let info = match m.mac.parse_body::<BindSpanInfo>() {
866 Ok(i) => i,
867 Err(e) => {
868 self.bump_err(e);
869 visit_mut::visit_expr_mut(self, i);
870 return;
871 }
872 };
873 let span_id = &info.span_ident;
874 let parser = &info.parser;
875 let marser = self.marser_path.clone();
876 *i = parse_quote! { #marser::parser::capture::bind_span(#parser, #span_id) };
877 return;
878 }
879
880 if m.mac.path.is_ident("bind_slice") {
881 let info = match m.mac.parse_body::<BindSliceInfo>() {
882 Ok(i) => i,
883 Err(e) => {
884 self.bump_err(e);
885 visit_mut::visit_expr_mut(self, i);
886 return;
887 }
888 };
889 let slice_id = &info.slice_ident;
890 let parser = &info.parser;
891 let marser = self.marser_path.clone();
892 *i = parse_quote! { #marser::parser::capture::bind_slice(#parser, #slice_id) };
893 return;
894 }
895 }
896 visit_mut::visit_expr_mut(self, i);
897 }
898}
899
900#[proc_macro]
950pub fn capture(input: TokenStream) -> TokenStream {
951 let mut input: CaptureInput = syn::parse_macro_input!(input as CaptureInput);
952 let marser_path = marser_crate_path();
953 let registry = match BindCollector::collect(&input.grammar) {
954 Ok(r) => r,
955 Err(e) => return e.to_compile_error().into(),
956 };
957
958 let mut expander = BindMacroExpander::new(marser_path.clone());
959 expander.visit_expr_mut(&mut input.grammar);
960 if let Some(e) = expander.take_errors() {
961 return e.to_compile_error().into();
962 }
963
964 let pat_tuple = |values: &[TypedBinding], spans: &[TypedBinding]| {
965 let all: Vec<_> = values
966 .iter()
967 .chain(spans.iter())
968 .map(|x| &x.ident)
969 .collect();
970 if all.is_empty() {
971 quote! { () }
972 } else {
973 quote! { ( #(#all,)* ) }
974 }
975 };
976
977 let s_pat = pat_tuple(®istry.single_values, ®istry.single_spans);
978 let m_pat = pat_tuple(®istry.multiple_values, ®istry.multiple_spans);
979 let o_pat = pat_tuple(®istry.optional_values, ®istry.optional_spans);
980
981 let mres_capture = build_capture_mres_tuple(®istry);
982 let (mres_factory, mres_generics) = build_factory_mres_tuple(®istry);
984
985 let mut use_binds_rw = UseBindsRewriter {
986 sites: RefCell::new(Vec::new()),
987 next_site: Cell::new(0),
988 errors: RefCell::new(None),
989 };
990 use_binds_rw.visit_expr_mut(&mut input.grammar);
991 if let Some(e) = use_binds_rw.errors.into_inner() {
992 return e.to_compile_error().into();
993 }
994 let sites = use_binds_rw.sites.into_inner();
995
996 let mut result_checker = UseBindsInResultChecker { error: None };
997 result_checker.visit_expr(&input.result_expr);
998 if let Some(e) = result_checker.error {
999 return e.to_compile_error().into();
1000 }
1001
1002 let use_binds_block = emit_use_binds_sites(
1003 &sites,
1004 ®istry,
1005 &marser_path,
1006 &mres_factory,
1007 &mres_generics,
1008 );
1009
1010 let grammar = &input.grammar;
1011 let result_expr = &input.result_expr;
1012
1013 TokenStream::from(quote! {
1014 {
1015 #use_binds_block
1016 #[allow(unused_variables)]
1017 #marser_path::parser::as_parser(
1018 #marser_path::parser::capture::Capture::<#mres_capture, _, _>::new(
1019 |#s_pat, #m_pat, #o_pat| { #grammar },
1020 |#s_pat, #m_pat, #o_pat| { #result_expr },
1021 ),
1022 )
1023 }
1024 })
1025}
1026
1027fn marser_crate_path() -> Path {
1028 match crate_name("marser") {
1029 Ok(FoundCrate::Itself) => parse_quote!(::marser),
1030 Ok(FoundCrate::Name(name)) => {
1031 let ident = Ident::new(&name, Span::call_site());
1032 parse_quote!(::#ident)
1033 }
1034 Err(_) => parse_quote!(::marser),
1035 }
1036}