Skip to main content

ct_regex_internal/codegen/convert_hir/
into_matcher.rs

1#![allow(non_snake_case)]
2
3use std::any;
4
5use proc_macro2::{Ident, TokenStream};
6use quote::{format_ident, quote};
7use regex_syntax::hir::{Capture, Class, Hir, HirKind, Literal, Look, Repetition};
8
9use crate::codegen::{ClassIter, ClassRange, CodegenItem, ExprMetadata};
10use crate::matcher::{Always as A, ClassEntry, Or, Then};
11
12pub(crate) fn type_name<T>() -> &'static str {
13    any::type_name::<T>()
14        .split('<').next().unwrap()
15        .rsplit("::").next().unwrap()
16}
17
18pub(crate) fn type_ident<T>() -> Ident {
19    match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}", type_name::<T>())
20}
21
22pub(crate) trait IntoMatcherExpr {
23    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream;
24}
25
26impl IntoMatcherExpr for Hir {
27    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
28        match self.into_kind() {
29            HirKind::Empty              => Empty.into_matcher_expr(meta),
30            HirKind::Literal(lit)       => lit.into_matcher_expr(meta),
31            HirKind::Class(class)       => class.into_matcher_expr(meta),
32            HirKind::Look(look)         => look.into_matcher_expr(meta),
33            HirKind::Repetition(rep)    => rep.into_matcher_expr(meta),
34            HirKind::Capture(cap)       => cap.into_matcher_expr(meta),
35            HirKind::Concat(hirs)       => Concat(hirs).into_matcher_expr(meta),
36            HirKind::Alternation(hirs)  => Alternation(hirs).into_matcher_expr(meta),
37        }
38    }
39}
40
41#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Empty {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Empty")
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Empty {
    #[inline]
    fn clone(&self) -> Empty { Empty }
}Clone)]
42struct Empty;
43
44#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Concat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Concat",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Concat {
    #[inline]
    fn clone(&self) -> Concat { Concat(::core::clone::Clone::clone(&self.0)) }
}Clone)]
45struct Concat(pub Vec<Hir>);
46
47#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Alternation {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Alternation",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Alternation {
    #[inline]
    fn clone(&self) -> Alternation {
        Alternation(::core::clone::Clone::clone(&self.0))
    }
}Clone)]
48struct Alternation(pub Vec<Hir>);
49
50impl IntoMatcherExpr for Empty {
51    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata<I>) -> TokenStream {
52        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Always");
    _s
}quote!(::ct_regex::internal::matcher::Always)
53    }
54}
55
56impl IntoMatcherExpr for Literal {
57    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
58        let LiteralTy = meta.insert_literal(self.0);
59        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "LiteralMatcher");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&LiteralTy, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::LiteralMatcher<#LiteralTy>)
60    }
61}
62
63impl IntoMatcherExpr for Class {
64    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
65        let normalized = I::normalize_class(self);
66
67        let class = normalized.ranges().flat_map(|range| {
68            let mut range_entries = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [ClassEntry { value: range.start(), is_upper_bound: false }]))vec![
69                ClassEntry {
70                    value: range.start(),
71                    is_upper_bound: false,
72                }
73            ];
74            if range.start() != range.end() {
75                range_entries.push(
76                    ClassEntry {
77                        value: range.end(),
78                        is_upper_bound: true,
79                    }
80                )
81            }
82            range_entries
83        }).collect::<Box<[_]>>();
84
85        let ClassTy = meta.insert_class(class);
86        let ItemTy = type_ident::<I>();
87        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ClassMatcher");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&ClassTy, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::ClassMatcher<#ItemTy, #ClassTy>)
88    }
89}
90
91impl IntoMatcherExpr for Look {
92    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata<I>) -> TokenStream {
93        match self {
94            Look::Start => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Start");
    _s
}quote!(::ct_regex::internal::matcher::Start),
95            Look::End => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "End");
    _s
}quote!(::ct_regex::internal::matcher::End),
96            Look::StartLF => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "LineStart");
    _s
}quote!(::ct_regex::internal::matcher::LineStart),
97            Look::EndLF => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "LineEnd");
    _s
}quote!(::ct_regex::internal::matcher::LineEnd),
98            Look::StartCRLF => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "CRLFStart");
    _s
}quote!(::ct_regex::internal::matcher::CRLFStart),
99            Look::EndCRLF => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "CRLFEnd");
    _s
}quote!(::ct_regex::internal::matcher::CRLFEnd),
100            _ => {
    ::core::panicking::panic_fmt(format_args!("not implemented: {0}",
            format_args!("complex look arounds")));
}unimplemented!("complex look arounds"),
101        }
102    }
103}
104
105impl IntoMatcherExpr for Repetition {
106    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
107        let Repetition { min, max, greedy, sub } = self;
108
109        let required = meta.required;
110        if min == 0 {
111            meta.required = false;
112        }
113
114        let ItemTy = type_ident::<I>();
115        let sub_matcher = sub.into_matcher_expr(meta);
116        // I need to document this somewhere, might as well be here: usize is used for all generic
117        // parameters, even though Hir types use u32, because it is used for array indexing during
118        // the conversion process.
119        let (min, max) = (min as usize, max.map(|m| m as usize));
120
121        if min == 0 {
122            meta.required = required;
123        }
124
125        let tokens = match max {
126            None => {
127                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierNOrMore");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierNOrMore<#ItemTy, #sub_matcher, #min>)
128            },
129            Some(max) if min == max => {
130                return {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierN");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierN<#ItemTy, #sub_matcher, #min>);
131            },
132            Some(max) => {
133                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierNToM");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&max, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierNToM<#ItemTy, #sub_matcher, #min, #max>)
134            },
135        };
136
137        if greedy {
138            tokens
139        } else {
140            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Lazy");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&tokens, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::Lazy<#ItemTy, #tokens>)
141        }
142    }
143}
144
145impl IntoMatcherExpr for Capture {
146    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
147        meta.insert_group(self.index, self.name);
148        let ItemTy = type_ident::<I>();
149        let sub_matcher = self.sub.into_matcher_expr(meta);
150        let index = self.index as usize;
151
152        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "CaptureGroup");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&index, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::CaptureGroup<#ItemTy, #sub_matcher, #index>)
153    }
154}
155
156impl IntoMatcherExpr for Alternation {
157    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut ExprMetadata<I>) -> TokenStream {
158        let required = caps.required;
159        caps.required = false;
160        let tokens = write_chunked::<Or<u8, A, A>, I, _>(caps, self.0);
161        caps.required = required;
162        tokens
163    }
164}
165
166impl IntoMatcherExpr for Concat {
167    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata<I>) -> TokenStream {
168        write_chunked::<Then<u8, A, A>, I, _>(meta, self.0)
169    }
170}
171
172fn write_chunked<T, I: CodegenItem, W: IntoMatcherExpr>(
173    meta: &mut ExprMetadata<I>,
174    mut items: Vec<W>,
175) -> TokenStream {
176    let n = items.len();
177    let base = match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}", type_name::<T>());
178    let ItemTy = type_ident::<I>();
179
180    match n {
181        0 => { ::core::panicking::panic_fmt(format_args!("literal contains no items")); }panic!("literal contains no items"),
182        1 => items.pop().unwrap().into_matcher_expr(meta),
183        2 => {
184            let mut iter = items.into_iter();
185            let first = iter.next().unwrap().into_matcher_expr(meta);
186            let second = iter.next().unwrap().into_matcher_expr(meta);
187
188            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&first, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&second, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#ItemTy, #first, #second>)
189        },
190        3 => {
191            let mut iter = items.into_iter();
192            let first = iter.next().unwrap().into_matcher_expr(meta);
193            let chunked = write_chunked::<T, I, W>(meta, iter.collect());
194
195            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&first, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&chunked, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#ItemTy, #first, #chunked>)
196        },
197        4 | 8 | 16 => write_n_items::<T, I, W>(meta, items, n),
198        _ => {
199            // Take largest chunk that fits, combine with remainder
200            let chunk_size = if n > 16 {
201                16
202            } else if n > 8 {
203                8
204            } else {
205                4
206            };
207            let remainder = items.split_off(chunk_size);
208            let n_matcher = write_n_items::<T, I, W>(meta, items, chunk_size);
209            let chunked = write_chunked::<T, I, W>(meta, remainder);
210
211            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&n_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&chunked, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#ItemTy, #n_matcher, #chunked>)
212        },
213    }
214}
215
216fn write_n_items<T, I: CodegenItem, W: IntoMatcherExpr>(
217    meta: &mut ExprMetadata<I>,
218    items: Vec<W>,
219    n: usize,
220) -> TokenStream {
221    let name = match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        match ::quote::__private::IdentFragmentAdapter(&n) {
            arg =>
                ::quote::__private::mk_ident(&::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("{0}{1}", arg, arg))
                            }),
                    ::quote::__private::Option::None.or(arg.span()).or(arg.span())),
        },
}format_ident!("{}{}", type_name::<T>(), n);
222    let ItemTy = type_ident::<I>();
223
224    let mut tokens = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ItemTy, &mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#name<#ItemTy);
225
226    for item in items {
227        tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_comma(&mut _s);
    _s
}quote!(,));
228        tokens.extend(item.into_matcher_expr(meta));
229    }
230
231    tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(>));
232    tokens
233}