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