1#![doc = include_str!("../README.md")]
2#![no_std]
3pub mod ctor;
4pub mod ctx;
5pub mod err;
6pub mod iter;
7pub mod map;
8pub mod neu;
9pub mod regex;
10pub mod span;
11
12pub(crate) mod log;
13pub(crate) mod r#macro;
14pub(crate) use log::*;
15
16#[cfg(feature = "alloc")]
17pub(crate) mod alloc {
18 extern crate alloc;
19
20 pub use alloc::borrow::Cow;
21 pub use alloc::boxed::Box;
22 pub use alloc::rc::Rc;
23 pub use alloc::string::String;
24 pub use alloc::sync::Arc;
25 pub use alloc::vec;
26 pub use alloc::vec::Vec;
27}
28
29#[cfg(feature = "std")]
30pub(crate) mod std {
31 extern crate std;
32
33 #[allow(unused)]
34 pub use std::collections::BTreeSet;
35 #[allow(unused)]
36 pub use std::collections::HashSet;
37 pub use std::sync::Mutex;
38}
39
40#[cfg(any(feature = "log", feature = "tracing"))]
41pub trait MayDebug: core::fmt::Debug {}
42
43#[cfg(any(feature = "log", feature = "tracing"))]
44impl<T> MayDebug for T where T: core::fmt::Debug {}
45
46#[cfg(not(any(feature = "log", feature = "tracing")))]
47pub trait MayDebug {}
48
49#[cfg(not(any(feature = "log", feature = "tracing")))]
50impl<T> MayDebug for T {}
51
52pub use charize::charize;
53
54pub mod prelude {
55 pub use crate::ctor;
56 pub use crate::ctor::CtorIntoHelper;
57 pub use crate::ctor::CtorOps;
58 pub use crate::ctor::CtorRefAsDynCtor;
59 pub use crate::ctx::Assert;
60 pub use crate::ctx::BytesCtx;
61 pub use crate::ctx::CharsCtx;
62 pub use crate::ctx::Context;
63 pub use crate::ctx::Match;
64 pub use crate::ctx::MatchExt;
65 pub use crate::ctx::MatchMulti;
66 pub use crate::ctx::RegexCtx;
67 pub use crate::map;
68 pub use crate::neu;
69 pub use crate::neu::Condition;
70 pub use crate::neu::Neu;
71 pub use crate::neu::NeuCond;
72 pub use crate::neu::NeuIntoRegexOps;
73 pub use crate::neu::NeuOp;
74 pub use crate::regex;
75 pub use crate::regex::Regex;
76 pub use crate::regex::RegexIntoHelper;
77 pub use crate::regex::RegexRefAsCtor;
78 pub use crate::regex::RegexRefAsDynRegex;
79 pub use crate::span::ArrayStorer;
80 pub use crate::span::Span;
81 #[cfg(feature = "alloc")]
82 pub use crate::span::VecStorer;
83}
84
85#[cfg(test)]
86mod test {
87
88 use crate::prelude::*;
89 use crate::regex;
90
91 #[test]
92 fn test_all() {
93 assert!(test_space().is_ok());
94 assert!(test_char().is_ok());
95 assert!(test_chars().is_ok());
96 assert!(test_chars_negative().is_ok());
97 assert!(test_range().is_ok());
98 #[cfg(feature = "alloc")]
99 assert!(test_range_negative().is_ok());
100 #[cfg(feature = "alloc")]
101 assert!(test_other().is_ok());
102 }
103
104 macro_rules! test_t {
105 ($ctx:ident, $str:literal, $id:literal, $parser:expr) => {
106 let parser = $parser;
107
108 $ctx.reset_with($str);
109 assert!($ctx.try_mat(&parser).is_err());
110 };
111 ($ctx:ident, $str:literal, $id:literal, $parser:expr, $span:expr) => {
112 let parser = $parser;
113
114 $ctx.reset_with($str);
115 assert_eq!($span, $ctx.try_mat(&parser)?);
116 };
117 }
118
119 #[cfg(feature = "alloc")]
120 macro_rules! test_st {
121 ($ctx:ident, $storer:ident, $str:literal, $id:literal, $parser:expr) => {
122 let parser = $parser;
123
124 $ctx.reset_with($str);
125 $storer.reset();
126 assert!($storer.try_cap($id, &mut $ctx, &parser).is_err());
127 };
128 ($ctx:ident, $storer:ident, $str:literal, $id:literal, $parser:expr, $($span:expr)*) => {
129 let parser = $parser;
130 let spans = [$($span)*];
131
132 $ctx.reset_with($str);
133 $storer.reset();
134 $storer.try_cap($id, &mut $ctx, &parser)?;
135 for (i, span) in $storer.spans_iter($id).unwrap().enumerate() {
136 assert_eq!(span, spans[i]);
137 }
138 };
139 }
140
141 #[cfg(feature = "alloc")]
142 fn test_other() -> Result<(), crate::err::Error> {
143 let mut ctx = RegexCtx::new("");
144 let mut storer = VecStorer::new(1);
145
146 test_st!(ctx, storer, "abedf", 0, regex!(.), Span { beg: 0, len: 1 });
147 test_st!(ctx, storer, "abedf", 0, regex!(.?), Span { beg: 0, len: 1 });
148 test_st!(
149 ctx,
150 storer,
151 "\nabedf",
152 0,
153 regex!(.?),
154 Span { beg: 0, len: 0 }
155 );
156 test_st!(ctx, storer, "abedf", 0, regex!(.*), Span { beg: 0, len: 5 });
157 test_st!(
158 ctx,
159 storer,
160 "\nabedf",
161 0,
162 regex!(.*),
163 Span { beg: 0, len: 0 }
164 );
165 test_st!(ctx, storer, "abedf", 0, regex!(.+), Span { beg: 0, len: 5 });
166 test_st!(ctx, storer, "\nabedf", 0, regex!(.+));
167 test_st!(
168 ctx,
169 storer,
170 "abedf",
171 0,
172 regex!(.{2}),
173 Span { beg: 0, len: 2 }
174 );
175 test_st!(ctx, storer, "ab\nedf", 0, regex!(.{3}));
176 test_st!(
177 ctx,
178 storer,
179 "abedf",
180 0,
181 regex!(.{2,}),
182 Span { beg: 0, len: 5 }
183 );
184 test_st!(
185 ctx,
186 storer,
187 "abedf",
188 0,
189 regex!(.{4,6}),
190 Span { beg: 0, len: 5 }
191 );
192 test_st!(ctx, storer, "abe\ndf", 0, regex!(.{4,6}));
193 test_st!(
194 ctx,
195 storer,
196 "c\nabedf",
197 0,
198 regex!(^),
199 Span { beg: 0, len: 1 }
200 );
201
202 Ok(())
203 }
204
205 #[cfg(feature = "alloc")]
206 fn test_range_negative() -> Result<(), crate::err::Error> {
207 let mut ctx = RegexCtx::new("");
208 let mut storer = VecStorer::new(1);
209
210 test_st!(
211 ctx,
212 storer,
213 "Raefc",
214 0,
215 regex!([^a - z]),
216 Span { beg: 0, len: 1 }
217 );
218 test_st!(
219 ctx,
220 storer,
221 "你aefc",
222 0,
223 regex!([^a - z A - Z]),
224 Span { beg: 0, len: 3 }
225 );
226 test_st!(
227 ctx,
228 storer,
229 "aefc",
230 0,
231 regex!([^a - z]?),
232 Span { beg: 0, len: 0 }
233 );
234 test_st!(
235 ctx,
236 storer,
237 "AEUF",
238 0,
239 regex!([^a - z]?),
240 Span { beg: 0, len: 1 }
241 );
242 test_st!(
243 ctx,
244 storer,
245 "&AEUF",
246 0,
247 regex!([^a - z A - Z]),
248 Span { beg: 0, len: 1 }
249 );
250 test_st!(
251 ctx,
252 storer,
253 "AEUF",
254 0,
255 regex!([^a-z]*),
256 Span { beg: 0, len: 4 }
257 );
258 test_st!(
259 ctx,
260 storer,
261 "aefc",
262 0,
263 regex!([^a-z]*),
264 Span { beg: 0, len: 0 }
265 );
266 test_st!(
267 ctx,
268 storer,
269 "@#$%",
270 0,
271 regex!([^a - z A - Z]*),
272 Span { beg: 0, len: 4 }
273 );
274 test_st!(
275 ctx,
276 storer,
277 "AEUF",
278 0,
279 regex!([^a-z]+),
280 Span { beg: 0, len: 4 }
281 );
282 test_st!(ctx, storer, "aefc", 0, regex!([^a-z]+));
283 test_st!(
284 ctx,
285 storer,
286 "AEUF",
287 0,
288 regex!([^a-z]{3}),
289 Span { beg: 0, len: 3 }
290 );
291 test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3}));
292 test_st!(
293 ctx,
294 storer,
295 "AEUF",
296 0,
297 regex!([^a-z]{3,6}),
298 Span { beg: 0, len: 4 }
299 );
300 test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3,6}));
301 test_st!(
302 ctx,
303 storer,
304 "AEUF",
305 0,
306 regex!([^a-z]{3,}),
307 Span { beg: 0, len: 4 }
308 );
309 test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3,}));
310
311 test_st!(
312 ctx,
313 storer,
314 "@#$%",
315 0,
316 regex!([^'a' - 'z' 'A' - 'Z']*),
317 Span { beg: 0, len: 4 }
318 );
319 test_st!(
320 ctx,
321 storer,
322 "AEUF",
323 0,
324 regex!([^'a'-'z']+),
325 Span { beg: 0, len: 4 }
326 );
327 test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']+));
328 test_st!(
329 ctx,
330 storer,
331 "AEUF",
332 0,
333 regex!([^'a'-'z']{3}),
334 Span { beg: 0, len: 3 }
335 );
336 test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3}));
337 test_st!(
338 ctx,
339 storer,
340 "AEUF",
341 0,
342 regex!([^'a'-'z']{3,6}),
343 Span { beg: 0, len: 4 }
344 );
345 test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3,6}));
346 test_st!(
347 ctx,
348 storer,
349 "AEUF",
350 0,
351 regex!([^'a'-'z']{3,}),
352 Span { beg: 0, len: 4 }
353 );
354 test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3,}));
355 Ok(())
356 }
357
358 fn test_range() -> Result<(), crate::err::Error> {
359 let mut ctx = RegexCtx::new("");
360
361 test_t!(ctx, "aefc", 0, regex!([a - z]), Span { beg: 0, len: 1 });
362 test_t!(
363 ctx,
364 "aefc",
365 0,
366 regex!([a - z A - Z]),
367 Span { beg: 0, len: 1 }
368 );
369 test_t!(ctx, "aefc", 0, regex!([a - z]?), Span { beg: 0, len: 1 });
370 test_t!(ctx, "AEUF", 0, regex!([a - z]?), Span { beg: 0, len: 0 });
371 test_t!(
372 ctx,
373 "AEUF",
374 0,
375 regex!([a - z A - Z]),
376 Span { beg: 0, len: 1 }
377 );
378 test_t!(ctx, "aefc", 0, regex!([a-z]*), Span { beg: 0, len: 4 });
379 test_t!(ctx, "AEUF", 0, regex!([a-z]*), Span { beg: 0, len: 0 });
380 test_t!(
381 ctx,
382 "AEUF",
383 0,
384 regex!([a - z A - Z]*),
385 Span { beg: 0, len: 4 }
386 );
387 test_t!(ctx, "aefc", 0, regex!([a-z]+), Span { beg: 0, len: 4 });
388 test_t!(ctx, "AEUF", 0, regex!([a-z]+));
389 test_t!(ctx, "aefc", 0, regex!([a-z]{3}), Span { beg: 0, len: 3 });
390 test_t!(ctx, "AEUF", 0, regex!([a-z]{3}));
391 test_t!(ctx, "aefc", 0, regex!([a-z]{3,6}), Span { beg: 0, len: 4 });
392 test_t!(ctx, "AEUF", 0, regex!([a-z]{3,6}));
393 test_t!(ctx, "aefc", 0, regex!([a-z]{3,}), Span { beg: 0, len: 4 });
394 test_t!(ctx, "AEUF", 0, regex!([a-z]{3,}));
395
396 test_t!(ctx, "aefc", 0, regex!(['a' - 'z']), Span { beg: 0, len: 1 });
397 test_t!(
398 ctx,
399 "aefc",
400 0,
401 regex!(['a' - 'z']?),
402 Span { beg: 0, len: 1 }
403 );
404 test_t!(
405 ctx,
406 "AEUF",
407 0,
408 regex!(['a' - 'z']?),
409 Span { beg: 0, len: 0 }
410 );
411 test_t!(ctx, "aefc", 0, regex!(['a'-'z']*), Span { beg: 0, len: 4 });
412 test_t!(ctx, "AEUF", 0, regex!(['a'-'z']*), Span { beg: 0, len: 0 });
413 test_t!(ctx, "aefc", 0, regex!(['a'-'z']+), Span { beg: 0, len: 4 });
414 test_t!(ctx, "AEUF", 0, regex!(['a'-'z']+));
415 test_t!(
416 ctx,
417 "AEUF",
418 0,
419 regex!(['a'-'z''A'-'Z']+),
420 Span { beg: 0, len: 4 }
421 );
422 test_t!(
423 ctx,
424 "aefc",
425 0,
426 regex!(['a'-'z']{3}),
427 Span { beg: 0, len: 3 }
428 );
429 test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3}));
430 test_t!(
431 ctx,
432 "aefc",
433 0,
434 regex!(['a'-'z']{3,6}),
435 Span { beg: 0, len: 4 }
436 );
437 test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3,6}));
438 test_t!(
439 ctx,
440 "aefc",
441 0,
442 regex!(['a'-'z']{3,}),
443 Span { beg: 0, len: 4 }
444 );
445 test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3,}));
446
447 Ok(())
448 }
449
450 fn test_chars_negative() -> Result<(), crate::err::Error> {
451 let mut ctx = RegexCtx::new("");
452
453 test_t!(ctx, "aefc", 0, regex!([^b c d]), Span { beg: 0, len: 1 });
454 test_t!(ctx, "aefc", 0, regex!([^b c d]?), Span { beg: 0, len: 1 });
455 test_t!(
456 ctx,
457 "aefc",
458 0,
459 regex!([^'b' 'c' 'd']),
460 Span { beg: 0, len: 1 }
461 );
462 test_t!(
463 ctx,
464 "aefc",
465 0,
466 regex!([^'b' 'c' 'd']?),
467 Span { beg: 0, len: 1 }
468 );
469 test_t!(ctx, "daefc", 0, regex!([^b c d]?), Span { beg: 0, len: 0 });
470 test_t!(ctx, "aefc", 0, regex!([^b c d]*), Span { beg: 0, len: 3 });
471 test_t!(ctx, "daefc", 0, regex!([^b c d]*), Span { beg: 0, len: 0 });
472 test_t!(ctx, "aefc", 0, regex!([^b c d]+), Span { beg: 0, len: 3 });
473 test_t!(
474 ctx,
475 "aefcddd",
476 0,
477 regex!([^b c d]+),
478 Span { beg: 0, len: 3 }
479 );
480 test_t!(ctx, "baefcddd", 0, regex!([^b c d]+));
481 test_t!(ctx, "aefh", 0, regex!([^b c d]{4}), Span { beg: 0, len: 4 });
482 test_t!(
483 ctx,
484 "aefhcc",
485 0,
486 regex!([^b c d]{4,}),
487 Span { beg: 0, len: 4 }
488 );
489 test_t!(
490 ctx,
491 "aefhccd",
492 0,
493 regex!([^b c d]{4,7}),
494 Span { beg: 0, len: 4 }
495 );
496 test_t!(ctx, "aecfhccd", 0, regex!([^b c d]{4,7}));
497 Ok(())
498 }
499
500 fn test_chars() -> Result<(), crate::err::Error> {
501 let mut ctx = RegexCtx::new("");
502
503 test_t!(ctx, "dabcd", 0, regex!([b c d]), Span { beg: 0, len: 1 });
504 test_t!(ctx, "dabcd", 0, regex!([b c d]?), Span { beg: 0, len: 1 });
505 test_t!(ctx, "edabcd", 0, regex!([b c d]?), Span { beg: 0, len: 0 });
506 test_t!(ctx, "dbcd", 0, regex!([b c d]*), Span { beg: 0, len: 4 });
507 test_t!(ctx, "aeuyf", 0, regex!([b c d]*), Span { beg: 0, len: 0 });
508 test_t!(ctx, "dabcd", 0, regex!([b c d]+), Span { beg: 0, len: 1 });
509 test_t!(ctx, "dbcdfff", 0, regex!([b c d]+), Span { beg: 0, len: 4 });
510 test_t!(ctx, "abcd", 0, regex!([b c d]+));
511 test_t!(ctx, "dbcd", 0, regex!([b c d]{4}), Span { beg: 0, len: 4 });
512 test_t!(
513 ctx,
514 "dbcdccc",
515 0,
516 regex!([b c d]{4,}),
517 Span { beg: 0, len: 7 }
518 );
519 test_t!(
520 ctx,
521 "dbcdbb",
522 0,
523 regex!([b c d]{4,7}),
524 Span { beg: 0, len: 6 }
525 );
526
527 test_t!(
528 ctx,
529 "dabcd",
530 0,
531 regex!(['b' 'c' 'd']),
532 Span { beg: 0, len: 1 }
533 );
534 test_t!(
535 ctx,
536 "dabcd",
537 0,
538 regex!(['b' 'c' 'd']?),
539 Span { beg: 0, len: 1 }
540 );
541 test_t!(
542 ctx,
543 "edabcd",
544 0,
545 regex!(['b' 'c' 'd']?),
546 Span { beg: 0, len: 0 }
547 );
548 test_t!(
549 ctx,
550 "dbcd",
551 0,
552 regex!(['b' 'c' 'd']*),
553 Span { beg: 0, len: 4 }
554 );
555 test_t!(
556 ctx,
557 "aeuyf",
558 0,
559 regex!(['b' 'c' 'd']*),
560 Span { beg: 0, len: 0 }
561 );
562 test_t!(
563 ctx,
564 "dabcd",
565 0,
566 regex!(['b' 'c' 'd']+),
567 Span { beg: 0, len: 1 }
568 );
569 test_t!(
570 ctx,
571 "dbcdfff",
572 0,
573 regex!(['b' 'c' 'd']+),
574 Span { beg: 0, len: 4 }
575 );
576 test_t!(ctx, "abcd", 0, regex!(['b' 'c' 'd']+));
577 test_t!(
578 ctx,
579 "dbcd",
580 0,
581 regex!(['b' 'c' 'd']{4}),
582 Span { beg: 0, len: 4 }
583 );
584 test_t!(
585 ctx,
586 "dbcdccc",
587 0,
588 regex!(['b' 'c' 'd']{4,}),
589 Span { beg: 0, len: 7 }
590 );
591 test_t!(
592 ctx,
593 "dbcdbb",
594 0,
595 regex!(['b' 'c' 'd']{4,7}),
596 Span { beg: 0, len: 6 }
597 );
598 Ok(())
599 }
600
601 fn test_char() -> Result<(), crate::err::Error> {
602 let mut ctx = RegexCtx::new("");
603
604 test_t!(ctx, "a", 0, regex!(a), Span { beg: 0, len: 1 });
605 test_t!(ctx, "a", 0, regex!('a'), Span { beg: 0, len: 1 });
606 test_t!(ctx, "a", 0, regex!(a?), Span { beg: 0, len: 1 });
607 test_t!(ctx, "a", 0, regex!('a'?), Span { beg: 0, len: 1 });
608 test_t!(ctx, "你", 0, regex!(你), Span { beg: 0, len: 3 });
609 test_t!(ctx, "你you", 0, regex!('你'), Span { beg: 0, len: 3 });
610 test_t!(ctx, "@", 0, regex!('@'), Span { beg: 0, len: 1 });
611 test_t!(ctx, "der", 0, regex!(a?), Span { beg: 0, len: 0 });
612 test_t!(ctx, "", 0, regex!('a'?), Span { beg: 0, len: 0 });
613 test_t!(ctx, "a", 0, regex!(a*), Span { beg: 0, len: 1 });
614 test_t!(ctx, "aaaaaee", 0, regex!('a'*), Span { beg: 0, len: 5 });
615 test_t!(ctx, "cde", 0, regex!(a*), Span { beg: 0, len: 0 });
616 test_t!(ctx, "aaaaee", 0, regex!('a'+), Span { beg: 0, len: 4 });
617 test_t!(ctx, "你你你", 0, regex!(你+), Span { beg: 0, len: 9 });
618 test_t!(ctx, "我你你你", 0, regex!(你+));
619 test_t!(ctx, "aaaaee", 0, regex!('a'{2}), Span { beg: 0, len: 2 });
620 test_t!(ctx, "你你你", 0, regex!(你{2}), Span { beg: 0, len: 6 });
621 test_t!(ctx, "你", 0, regex!(你{2}));
622 test_t!(ctx, "aaaaee", 0, regex!('a'{2,}), Span { beg: 0, len: 4 });
623 test_t!(ctx, "你你你", 0, regex!(你{2,}), Span { beg: 0, len: 9 });
624 test_t!(ctx, "你", 0, regex!(你{2,}));
625 test_t!(ctx, "aaaaee", 0, regex!('a'{2,3}), Span { beg: 0, len: 3 });
626 test_t!(
627 ctx,
628 "你你你你你啊",
629 0,
630 regex!(你{2,4}),
631 Span { beg: 0, len: 12 }
632 );
633 test_t!(ctx, "你啊", 0, regex!(你{2,4}));
634
635 Ok(())
636 }
637
638 fn test_space() -> Result<(), crate::err::Error> {
639 let mut ctx = RegexCtx::new("");
640
641 test_t!(ctx, "\tcd", 0, regex!(), Span { beg: 0, len: 1 });
642 test_t!(ctx, "\tdwq", 0, regex!(?), Span { beg: 0, len: 1 });
643 test_t!(ctx, "dwq", 0, regex!(?), Span { beg: 0, len: 0 });
644 test_t!(ctx, "\t\n\rdda", 0, regex!(*), Span { beg: 0, len: 3 });
645 test_t!(ctx, "dda", 0, regex!(*), Span { beg: 0, len: 0 });
646 test_t!(ctx, "\t\n\rdda", 0, regex!(+), Span { beg: 0, len: 3 });
647 test_t!(ctx, "\tdda", 0, regex!(+), Span { beg: 0, len: 1 });
648 test_t!(ctx, "dda", 0, regex!(+));
649 test_t!(ctx, " \u{A0}dda", 0, regex!({ 2 }), Span { beg: 0, len: 3 });
650 test_t!(ctx, "\u{A0}dda", 0, regex!({ 2 }));
651 test_t!(ctx, "\t\rdda", 0, regex!({2,}), Span { beg: 0, len: 2 });
652 test_t!(
653 ctx,
654 "\t\r\u{A0}dda",
655 0,
656 regex!({2,}),
657 Span { beg: 0, len: 4 }
658 );
659 test_t!(ctx, "dda", 0, regex!());
660 test_t!(ctx, "\t\ndda", 0, regex!({2,3}), Span { beg: 0, len: 2 });
661 test_t!(
662 ctx,
663 "\t\r\u{A0}dda",
664 0,
665 regex!({2,3}),
666 Span { beg: 0, len: 4 }
667 );
668 test_t!(
669 ctx,
670 "\t\r \u{A0}dda",
671 0,
672 regex!({2,3}),
673 Span { beg: 0, len: 3 }
674 );
675 test_t!(ctx, " dda", 0, regex!({2,3}));
676
677 Ok(())
678 }
679}