Skip to main content

ct_regex_internal/codegen/create_type/
parse.rs

1use proc_macro2::TokenStream;
2use regex_syntax::ast::parse::ParserBuilder;
3use regex_syntax::ast::{
4    Ast, ClassAscii, ClassAsciiKind, ClassBracketed, ClassPerl, ClassPerlKind, ClassSet,
5    ClassSetBinaryOp, ClassSetItem,
6};
7use regex_syntax::hir::translate::TranslatorBuilder;
8
9use crate::codegen::{CodegenItem, Group, HirExtension};
10
11pub fn parse_regex<I: CodegenItem>(pat: &str, config: &ConfigExt) -> (TokenStream, Vec<Group>) {
12    let mut ast = config.ast.build()
13        .parse(pat)
14        .expect("failed to parse regex");
15
16    if !config.complex_classes {
17        simplify_classes(&mut ast);
18    }
19
20    config.hir.build()
21        .translate(pat, &ast)
22        .expect("failed to parse regex")
23        .into_matcher::<I>()
24}
25
26pub fn simplify_classes(ast: &mut Ast) {
27    let replacement = match ast {
28        Ast::ClassPerl(class) =>      replace_perl_class(class),
29        Ast::ClassBracketed(class) => return replace_in_class(&mut class.kind),
30        Ast::Repetition(rep) =>       return simplify_classes(&mut rep.ast),
31        Ast::Group(group) =>          return simplify_classes(&mut group.ast),
32        Ast::Alternation(alt) =>      return alt.asts.iter_mut().for_each(simplify_classes),
33        Ast::Concat(cat) =>           return cat.asts.iter_mut().for_each(simplify_classes),
34        _ => return,
35    };
36    *ast = Ast::ClassBracketed(Box::new(ClassBracketed {
37        span: *ast.span(),
38        negated: false,
39        kind: ClassSet::Item(ClassSetItem::Ascii(replacement)),
40    }));
41}
42
43pub fn replace_in_class(class: &mut ClassSet) {
44    match class {
45        ClassSet::BinaryOp(ClassSetBinaryOp { lhs, rhs, .. }) => {
46            replace_in_class(lhs);
47            replace_in_class(rhs);
48        },
49        ClassSet::Item(item) => replace_in_class_set_item(item),
50    }
51}
52
53pub fn replace_in_class_set_item(item: &mut ClassSetItem) {
54    let replacement = match item {
55        ClassSetItem::Perl(class) =>      replace_perl_class(class),
56        ClassSetItem::Bracketed(class) => return replace_in_class(&mut class.kind),
57        ClassSetItem::Union(class) => {
58            return class.items.iter_mut().for_each(replace_in_class_set_item);
59        },
60        _ => return,
61    };
62    *item = ClassSetItem::Ascii(replacement);
63}
64
65pub fn replace_perl_class(class: &mut ClassPerl) -> ClassAscii {
66    ClassAscii {
67        span: class.span,
68        negated: class.negated,
69        kind: match class.kind {
70            ClassPerlKind::Digit => ClassAsciiKind::Digit,
71            ClassPerlKind::Space => ClassAsciiKind::Space,
72            ClassPerlKind::Word => ClassAsciiKind::Word,
73        },
74    }
75}
76
77#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ConfigExt {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "ConfigExt",
            "ast", &self.ast, "hir", &self.hir, "complex_classes",
            &&self.complex_classes)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for ConfigExt {
    #[inline]
    fn default() -> ConfigExt {
        ConfigExt {
            ast: ::core::default::Default::default(),
            hir: ::core::default::Default::default(),
            complex_classes: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::clone::Clone for ConfigExt {
    #[inline]
    fn clone(&self) -> ConfigExt {
        ConfigExt {
            ast: ::core::clone::Clone::clone(&self.ast),
            hir: ::core::clone::Clone::clone(&self.hir),
            complex_classes: ::core::clone::Clone::clone(&self.complex_classes),
        }
    }
}Clone)]
78pub struct ConfigExt {
79    pub ast: ParserBuilder,
80    pub hir: TranslatorBuilder,
81    pub complex_classes: bool,
82}
83
84macro_rules! impl_hir_methods {
85    ($name:ident) => {
86        pub fn $name(&mut self, flag: bool) -> &mut Self {
87            self.hir.$name(flag);
88            self
89        }
90    };
91    ($name:ident, $($others:ident),+) => {
92        impl_hir_methods! { $name }
93        impl_hir_methods! { $($others),+ }
94    };
95}
96
97impl ConfigExt {
98    self
bool
flag
&mut Self
self.hir.utf8(flag);
self;impl_hir_methods! {
99        case_insensitive,
100        multi_line,
101        dot_matches_new_line,
102        crlf,
103        swap_greed,
104        unicode,
105        utf8
106    }
107
108    pub fn ignore_whitespace(&mut self, flag: bool) -> &mut Self {
109        self.ast.ignore_whitespace(flag);
110        self
111    }
112
113    pub fn complex_classes(&mut self, flag: bool) -> &mut Self {
114        self.complex_classes = flag;
115        self
116    }
117}