1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#[macro_export]
macro_rules! re {
    (@q * $($res:tt)*) => {
        $crate::re::zero_more($($res)*)
    };
    (@q ? $($res:tt)*) => {
        $crate::re::zero_one($($res)*)
    };
    (@q + $($res:tt)*) => {
        $crate::re::one_more($($res)*)
    };
    (@q {$st:literal} $($res:tt)*) => {
        $crate::re::count::<$st, $st, _, _>($($res)*)
    };
    (@q {$st:literal,} $($res:tt)*) => {
        $crate::re::count::<$st, {usize::MAX}, _, _>($($res)*)
    };
    (@q {$st:literal, $ed:literal} $($res:tt)*) => {
        $crate::re::count::<$st, $ed, _, _>($($res)*)
    };
    (@q $($res:tt)*) => {
        $crate::re::one($($res)*)
    };

    (@r ^ $($res:tt)*) => { // \S
        re!(@q $($res)* $crate::neu!(^))
    };
    (@r . $($res:tt)*) => { // .
        re!(@q $($res)* $crate::neu!(.))
    };
    (@r [ $($range:tt)+ ] $($res:tt)*) => {
        re!(@q $($res)* $crate::neu!([$($range)+]))
    };
    (@r $ch:ident $($res:tt)*) => {
        re!(@q $($res)* $crate::neu::equal($crate::charize!($ch)))
    };
    (@r $ch:literal $($res:tt)*) => {
        re!(@q $($res)* $crate::neu::equal($ch))
    };
    (@r ($($regex:expr),+) $($res:tt)*) => {
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($regex);
            )+
            re!(@q $($res)* re)
        }
    };
    (@r $($res:tt)*) => {
        re!(@q $($res)* $crate::neu::whitespace())
    };
    ($($res:tt)*) => {
        re!(@r $($res)*)
    };
}

#[macro_export]
macro_rules! neu {
    (^) => { // \S
        $crate::neu::whitespace().not()
    };
    (.) => { // .
        $crate::neu::wild()
    };
    ([^$l:literal - $r:literal] ) => {
        $crate::neu::range($l..=$r).not()
    };
    ([^$l:ident - $r:ident] ) => {
        $crate::neu::range($crate::charize!($l)..(char::from_u32($crate::charize!($r) as u32 + 1).unwrap())).not()
    };
    ([$l:literal - $r:literal] ) => {
        $crate::neu::range($l..=$r)
    };
    ([$l:ident - $r:ident] ) => {
        $crate::neu::range($crate::charize!($l)..(char::from_u32($crate::charize!($r) as u32 + 1).unwrap()))
    };

    ([^$($l:literal - $r:literal)+] ) => {// [ ^ 'a'-'z' 'A'-'Z' ]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::range($l..=$r));
            )+
            re.not()
        }
    };
    ([^$($l:ident - $r:ident)+] ) => { // [ ^ a-z A-Z ]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::range($crate::charize!($l)..=$crate::charize!($r)));
            )+
            re.not()
        }
    };
    ([$($l:literal - $r:literal)+] ) => { // [ 'a'-'Z' 'A'-'Z' ]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::range($l..=$r));
            )+
            re
        }
    };
    ([$($l:ident - $r:ident)+] ) => { // [ a-Z A-Z ]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::range($crate::charize!($l)..=$crate::charize!($r)));
            )+
            re
        }
    };


    ([ ^ $($ch:literal)+ ] ) => { // [ ^ 'a' 'b' 'c']
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::equal($ch));
            )+
            re.not()
        }
    };
    ([ ^ $($ch:ident)+ ] ) => { // [^ a b c]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::equal($crate::charize!($ch)));
            )+
            re.not()
        }
    };
    ([ $($ch:literal)+ ] ) => { // ['a' 'b' 'c']
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::equal($ch));
            )+
            re
        }
    };
    ([ $($ch:ident)+ ] ) => { // [a b c]
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($crate::neu::equal($crate::charize!($ch)));
            )+
            re
        }
    };
    (($($regex:expr),+)) => {
        {
            let re = $crate::neu::none();
            $(
                let re = re.or($regex);
            )+
            re
        }
    };

    ($ch:ident ) => {
        $crate::neu::equal($crate::charize!($ch))
    };
    ($ch:literal ) => {
        $crate::neu::equal($ch)
    };
    () => {
        $crate::neu::space()
    };
}

#[macro_export]
macro_rules! escape {
    ($re:expr, $escape:expr, $or:expr) => {{
        let cond = $crate::neu::re_cond($crate::re::not($escape));
        $re.set_cond(cond).or($or)
    }};
}