Skip to main content

ct_regex_internal/codegen/
args.rs

1use std::collections::HashSet;
2use std::fmt::{self, Display};
3
4use syn::parse::{discouraged::Speculative, Parse, ParseStream};
5use syn::{Ident, LitStr, Token, Visibility};
6
7use crate::codegen::ConfigExt;
8
9pub enum RegexArgType {
10    Regex(RegexArgs),
11    Anon(AnonRegexArgs),
12}
13
14impl Parse for RegexArgType {
15    fn parse(input: ParseStream) -> syn::Result<Self> {
16        let fork = input.fork();
17        if let Ok(parsed) = fork.parse() {
18            input.advance_to(&fork);
19            Ok(RegexArgType::Regex(parsed))
20        } else {
21            Ok(RegexArgType::Anon(input.parse()?))
22        }
23    }
24}
25
26pub struct RegexArgs {
27    pub vis: Visibility,
28    pub name: Ident,
29    pub pat: LitStr,
30    pub flags: Flags,
31}
32
33impl Parse for RegexArgs {
34    fn parse(input: ParseStream) -> syn::Result<Self> {
35        let vis = input.parse()?;
36        let name = input.parse()?;
37        input.parse::<::syn::token::EqToken![=]>()?;
38        let pat = input.parse()?;
39        let flags = input.parse()?;
40        Ok(RegexArgs {
41            vis,
42            name,
43            pat,
44            flags,
45        })
46    }
47}
48
49pub struct AnonRegexArgs {
50    pub pat: LitStr,
51    pub flags: Flags,
52}
53
54impl Parse for AnonRegexArgs {
55    fn parse(input: ParseStream) -> syn::Result<Self> {
56        Ok(AnonRegexArgs {
57            pat: input.parse()?,
58            flags: input.parse()?,
59        })
60    }
61}
62
63#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Flags {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Flags",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Flags {
    #[inline]
    fn clone(&self) -> Flags { Flags(::core::clone::Clone::clone(&self.0)) }
}Clone)]
64pub struct Flags(pub HashSet<char>);
65
66impl Parse for Flags {
67    fn parse(input: ParseStream) -> syn::Result<Self> {
68        let sep = input.parse::<::syn::token::SlashToken![/]>();
69
70        let lit: syn::Result<LitStr> = input.parse();
71
72        let set = lit
73            .and_then(|l| sep.map(|_| l))
74            .map(|l| l.value())
75            .unwrap_or_default()
76            .chars()
77            .collect();
78
79        Ok(Flags(set))
80    }
81}
82
83impl Flags {
84    pub(crate) fn create_config(self) -> ConfigExt {
85        let mut config = ConfigExt::default();
86
87        for c in self.0 {
88            // TODO: Add flag that allows groups to be Vec<&str>s appending captures rather than
89            // replacing them.
90            match c {
91                'i' => config.case_insensitive(true),
92                'm' => config.multi_line(true),
93                's' => config.dot_matches_new_line(true),
94                'R' => config.crlf(true),
95                'U' => config.swap_greed(true),
96                'x' => config.ignore_whitespace(true),
97                'c' => config.complex_classes(true),
98                'g' => {
    ::core::panicking::panic_fmt(format_args!("the global flag is unsupported by this implementation, please read the docs on the methods available on the Regex trait"));
}panic!(
99                    "the global flag is unsupported by this implementation, please read the docs \
100                    on the methods available on the Regex trait"
101                ),
102                o => {
    ::core::panicking::panic_fmt(format_args!("unknown flag provided for regex: {0:?}",
            o));
}panic!("unknown flag provided for regex: {o:?}"),
103            };
104        }
105
106        config
107    }
108}
109
110impl Display for Flags {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        let mut vec: Vec<_> = self.0.iter().collect();
113        vec.sort();
114        f.write_fmt(format_args!("{0:?}", &vec[..]))write!(f, "{:?}", &vec[..])
115    }
116}