1/*!
2Defines an abstract syntax for regular expressions.
3*/
4
5use core::cmp::Ordering;
6
7use alloc::{boxed::Box, string::String, vec, vec::Vec};
8
9pub use crate::ast::visitor::{visit, Visitor};
10
11pub mod parse;
12pub mod print;
13mod visitor;
14
15/// An error that occurred while parsing a regular expression into an abstract
16/// syntax tree.
17///
18/// Note that not all ASTs represents a valid regular expression. For example,
19/// an AST is constructed without error for `\p{Quux}`, but `Quux` is not a
20/// valid Unicode property name. That particular error is reported when
21/// translating an AST to the high-level intermediate representation (`HIR`).
22#[derive(Clone, Debug, Eq, PartialEq)]
23#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24pub struct Error {
25 /// The kind of error.
26 kind: ErrorKind,
27 /// The original pattern that the parser generated the error from. Every
28 /// span in an error is a valid range into this string.
29 pattern: String,
30 /// The span of this error.
31 span: Span,
32}
33
34impl Error {
35 /// Return the type of this error.
36 pub fn kind(&self) -> &ErrorKind {
37 &self.kind
38 }
39
40 /// The original pattern string in which this error occurred.
41 ///
42 /// Every span reported by this error is reported in terms of this string.
43 pub fn pattern(&self) -> &str {
44 &self.pattern
45 }
46
47 /// Return the span at which this error occurred.
48 pub fn span(&self) -> &Span {
49 &self.span
50 }
51
52 /// Return an auxiliary span. This span exists only for some errors that
53 /// benefit from being able to point to two locations in the original
54 /// regular expression. For example, "duplicate" errors will have the
55 /// main error position set to the duplicate occurrence while its
56 /// auxiliary span will be set to the initial occurrence.
57 pub fn auxiliary_span(&self) -> Option<&Span> {
58 use self::ErrorKind::*;
59 match self.kind {
60 FlagDuplicate { ref original } => Some(original),
61 FlagRepeatedNegation { ref original, .. } => Some(original),
62 GroupNameDuplicate { ref original, .. } => Some(original),
63 _ => None,
64 }
65 }
66}
67
68/// The type of an error that occurred while building an AST.
69///
70/// This error type is marked as `non_exhaustive`. This means that adding a
71/// new variant is not considered a breaking change.
72#[non_exhaustive]
73#[derive(Clone, Debug, Eq, PartialEq)]
74#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
75pub enum ErrorKind {
76 /// The capturing group limit was exceeded.
77 ///
78 /// Note that this represents a limit on the total number of capturing
79 /// groups in a regex and not necessarily the number of nested capturing
80 /// groups. That is, the nest limit can be low and it is still possible for
81 /// this error to occur.
82 CaptureLimitExceeded,
83 /// An invalid escape sequence was found in a character class set.
84 ClassEscapeInvalid,
85 /// An invalid character class range was found. An invalid range is any
86 /// range where the start is greater than the end.
87 ClassRangeInvalid,
88 /// An invalid range boundary was found in a character class. Range
89 /// boundaries must be a single literal codepoint, but this error indicates
90 /// that something else was found, such as a nested class.
91 ClassRangeLiteral,
92 /// An opening `[` was found with no corresponding closing `]`.
93 ClassUnclosed,
94 /// Note that this error variant is no longer used. Namely, a decimal
95 /// number can only appear as a repetition quantifier. When the number
96 /// in a repetition quantifier is empty, then it gets its own specialized
97 /// error, `RepetitionCountDecimalEmpty`.
98 DecimalEmpty,
99 /// An invalid decimal number was given where one was expected.
100 DecimalInvalid,
101 /// A bracketed hex literal was empty.
102 EscapeHexEmpty,
103 /// A bracketed hex literal did not correspond to a Unicode scalar value.
104 EscapeHexInvalid,
105 /// An invalid hexadecimal digit was found.
106 EscapeHexInvalidDigit,
107 /// EOF was found before an escape sequence was completed.
108 EscapeUnexpectedEof,
109 /// An unrecognized escape sequence.
110 EscapeUnrecognized,
111 /// A dangling negation was used when setting flags, e.g., `i-`.
112 FlagDanglingNegation,
113 /// A flag was used twice, e.g., `i-i`.
114 FlagDuplicate {
115 /// The position of the original flag. The error position
116 /// points to the duplicate flag.
117 original: Span,
118 },
119 /// The negation operator was used twice, e.g., `-i-s`.
120 FlagRepeatedNegation {
121 /// The position of the original negation operator. The error position
122 /// points to the duplicate negation operator.
123 original: Span,
124 },
125 /// Expected a flag but got EOF, e.g., `(?`.
126 FlagUnexpectedEof,
127 /// Unrecognized flag, e.g., `a`.
128 FlagUnrecognized,
129 /// A duplicate capture name was found.
130 GroupNameDuplicate {
131 /// The position of the initial occurrence of the capture name. The
132 /// error position itself points to the duplicate occurrence.
133 original: Span,
134 },
135 /// A capture group name is empty, e.g., `(?P<>abc)`.
136 GroupNameEmpty,
137 /// An invalid character was seen for a capture group name. This includes
138 /// errors where the first character is a digit (even though subsequent
139 /// characters are allowed to be digits).
140 GroupNameInvalid,
141 /// A closing `>` could not be found for a capture group name.
142 GroupNameUnexpectedEof,
143 /// An unclosed group, e.g., `(ab`.
144 ///
145 /// The span of this error corresponds to the unclosed parenthesis.
146 GroupUnclosed,
147 /// An unopened group, e.g., `ab)`.
148 GroupUnopened,
149 /// The nest limit was exceeded. The limit stored here is the limit
150 /// configured in the parser.
151 NestLimitExceeded(u32),
152 /// The range provided in a counted repetition operator is invalid. The
153 /// range is invalid if the start is greater than the end.
154 RepetitionCountInvalid,
155 /// An opening `{` was not followed by a valid decimal value.
156 /// For example, `x{}` or `x{]}` would fail.
157 RepetitionCountDecimalEmpty,
158 /// An opening `{` was found with no corresponding closing `}`.
159 RepetitionCountUnclosed,
160 /// A repetition operator was applied to a missing sub-expression. This
161 /// occurs, for example, in the regex consisting of just a `*` or even
162 /// `(?i)*`. It is, however, possible to create a repetition operating on
163 /// an empty sub-expression. For example, `()*` is still considered valid.
164 RepetitionMissing,
165 /// The special word boundary syntax, `\b{something}`, was used, but
166 /// either EOF without `}` was seen, or an invalid character in the
167 /// braces was seen.
168 SpecialWordBoundaryUnclosed,
169 /// The special word boundary syntax, `\b{something}`, was used, but
170 /// `something` was not recognized as a valid word boundary kind.
171 SpecialWordBoundaryUnrecognized,
172 /// The syntax `\b{` was observed, but afterwards the end of the pattern
173 /// was observed without being able to tell whether it was meant to be a
174 /// bounded repetition on the `\b` or the beginning of a special word
175 /// boundary assertion.
176 SpecialWordOrRepetitionUnexpectedEof,
177 /// The Unicode class is not valid. This typically occurs when a `\p` is
178 /// followed by something other than a `{`.
179 UnicodeClassInvalid,
180 /// When octal support is disabled, this error is produced when an octal
181 /// escape is used. The octal escape is assumed to be an invocation of
182 /// a backreference, which is the common case.
183 UnsupportedBackreference,
184 /// When syntax similar to PCRE's look-around is used, this error is
185 /// returned. Some example syntaxes that are rejected include, but are
186 /// not necessarily limited to, `(?=re)`, `(?!re)`, `(?<=re)` and
187 /// `(?<!re)`. Note that all of these syntaxes are otherwise invalid; this
188 /// error is used to improve the user experience.
189 UnsupportedLookAround,
190}
191
192#[cfg(feature = "std")]
193impl std::error::Error for Error {}
194
195impl core::fmt::Display for Error {
196 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
197 crate::error::Formatter::from(self).fmt(f)
198 }
199}
200
201impl core::fmt::Display for ErrorKind {
202 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 use self::ErrorKind::*;
204 match *self {
205 CaptureLimitExceeded => write!(
206 f,
207 "exceeded the maximum number of \
208 capturing groups ({})",
209 u32::MAX
210 ),
211 ClassEscapeInvalid => {
212 write!(f, "invalid escape sequence found in character class")
213 }
214 ClassRangeInvalid => write!(
215 f,
216 "invalid character class range, \
217 the start must be <= the end"
218 ),
219 ClassRangeLiteral => {
220 write!(f, "invalid range boundary, must be a literal")
221 }
222 ClassUnclosed => write!(f, "unclosed character class"),
223 DecimalEmpty => write!(f, "decimal literal empty"),
224 DecimalInvalid => write!(f, "decimal literal invalid"),
225 EscapeHexEmpty => write!(f, "hexadecimal literal empty"),
226 EscapeHexInvalid => {
227 write!(f, "hexadecimal literal is not a Unicode scalar value")
228 }
229 EscapeHexInvalidDigit => write!(f, "invalid hexadecimal digit"),
230 EscapeUnexpectedEof => write!(
231 f,
232 "incomplete escape sequence, \
233 reached end of pattern prematurely"
234 ),
235 EscapeUnrecognized => write!(f, "unrecognized escape sequence"),
236 FlagDanglingNegation => {
237 write!(f, "dangling flag negation operator")
238 }
239 FlagDuplicate { .. } => write!(f, "duplicate flag"),
240 FlagRepeatedNegation { .. } => {
241 write!(f, "flag negation operator repeated")
242 }
243 FlagUnexpectedEof => {
244 write!(f, "expected flag but got end of regex")
245 }
246 FlagUnrecognized => write!(f, "unrecognized flag"),
247 GroupNameDuplicate { .. } => {
248 write!(f, "duplicate capture group name")
249 }
250 GroupNameEmpty => write!(f, "empty capture group name"),
251 GroupNameInvalid => write!(f, "invalid capture group character"),
252 GroupNameUnexpectedEof => write!(f, "unclosed capture group name"),
253 GroupUnclosed => write!(f, "unclosed group"),
254 GroupUnopened => write!(f, "unopened group"),
255 NestLimitExceeded(limit) => write!(
256 f,
257 "exceed the maximum number of \
258 nested parentheses/brackets ({})",
259 limit
260 ),
261 RepetitionCountInvalid => write!(
262 f,
263 "invalid repetition count range, \
264 the start must be <= the end"
265 ),
266 RepetitionCountDecimalEmpty => {
267 write!(f, "repetition quantifier expects a valid decimal")
268 }
269 RepetitionCountUnclosed => {
270 write!(f, "unclosed counted repetition")
271 }
272 RepetitionMissing => {
273 write!(f, "repetition operator missing expression")
274 }
275 SpecialWordBoundaryUnclosed => {
276 write!(
277 f,
278 "special word boundary assertion is either \
279 unclosed or contains an invalid character",
280 )
281 }
282 SpecialWordBoundaryUnrecognized => {
283 write!(
284 f,
285 "unrecognized special word boundary assertion, \
286 valid choices are: start, end, start-half \
287 or end-half",
288 )
289 }
290 SpecialWordOrRepetitionUnexpectedEof => {
291 write!(
292 f,
293 "found either the beginning of a special word \
294 boundary or a bounded repetition on a \\b with \
295 an opening brace, but no closing brace",
296 )
297 }
298 UnicodeClassInvalid => {
299 write!(f, "invalid Unicode character class")
300 }
301 UnsupportedBackreference => {
302 write!(f, "backreferences are not supported")
303 }
304 UnsupportedLookAround => write!(
305 f,
306 "look-around, including look-ahead and look-behind, \
307 is not supported"
308 ),
309 }
310 }
311}
312
313/// Span represents the position information of a single AST item.
314///
315/// All span positions are absolute byte offsets that can be used on the
316/// original regular expression that was parsed.
317#[derive(Clone, Copy, Eq, PartialEq)]
318#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
319pub struct Span {
320 /// The start byte offset.
321 pub start: Position,
322 /// The end byte offset.
323 pub end: Position,
324}
325
326impl core::fmt::Debug for Span {
327 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
328 write!(f, "Span({:?}, {:?})", self.start, self.end)
329 }
330}
331
332impl Ord for Span {
333 fn cmp(&self, other: &Span) -> Ordering {
334 (&self.start, &self.end).cmp(&(&other.start, &other.end))
335 }
336}
337
338impl PartialOrd for Span {
339 fn partial_cmp(&self, other: &Span) -> Option<Ordering> {
340 Some(self.cmp(other))
341 }
342}
343
344/// A single position in a regular expression.
345///
346/// A position encodes one half of a span, and include the byte offset, line
347/// number and column number.
348#[derive(Clone, Copy, Eq, PartialEq)]
349#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
350pub struct Position {
351 /// The absolute offset of this position, starting at `0` from the
352 /// beginning of the regular expression pattern string.
353 pub offset: usize,
354 /// The line number, starting at `1`.
355 pub line: usize,
356 /// The approximate column number, starting at `1`.
357 pub column: usize,
358}
359
360impl core::fmt::Debug for Position {
361 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362 write!(
363 f,
364 "Position(o: {:?}, l: {:?}, c: {:?})",
365 self.offset, self.line, self.column
366 )
367 }
368}
369
370impl Ord for Position {
371 fn cmp(&self, other: &Position) -> Ordering {
372 self.offset.cmp(&other.offset)
373 }
374}
375
376impl PartialOrd for Position {
377 fn partial_cmp(&self, other: &Position) -> Option<Ordering> {
378 Some(self.cmp(other))
379 }
380}
381
382impl Span {
383 /// Create a new span with the given positions.
384 pub fn new(start: Position, end: Position) -> Span {
385 Span { start, end }
386 }
387
388 /// Create a new span using the given position as the start and end.
389 pub fn splat(pos: Position) -> Span {
390 Span::new(pos, pos)
391 }
392
393 /// Create a new span by replacing the starting the position with the one
394 /// given.
395 pub fn with_start(self, pos: Position) -> Span {
396 Span { start: pos, ..self }
397 }
398
399 /// Create a new span by replacing the ending the position with the one
400 /// given.
401 pub fn with_end(self, pos: Position) -> Span {
402 Span { end: pos, ..self }
403 }
404
405 /// Returns true if and only if this span occurs on a single line.
406 pub fn is_one_line(&self) -> bool {
407 self.start.line == self.end.line
408 }
409
410 /// Returns true if and only if this span is empty. That is, it points to
411 /// a single position in the concrete syntax of a regular expression.
412 pub fn is_empty(&self) -> bool {
413 self.start.offset == self.end.offset
414 }
415}
416
417impl Position {
418 /// Create a new position with the given information.
419 ///
420 /// `offset` is the absolute offset of the position, starting at `0` from
421 /// the beginning of the regular expression pattern string.
422 ///
423 /// `line` is the line number, starting at `1`.
424 ///
425 /// `column` is the approximate column number, starting at `1`.
426 pub fn new(offset: usize, line: usize, column: usize) -> Position {
427 Position { offset, line, column }
428 }
429}
430
431/// An abstract syntax tree for a singular expression along with comments
432/// found.
433///
434/// Comments are not stored in the tree itself to avoid complexity. Each
435/// comment contains a span of precisely where it occurred in the original
436/// regular expression.
437#[derive(Clone, Debug, Eq, PartialEq)]
438#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
439pub struct WithComments {
440 /// The actual ast.
441 pub ast: Ast,
442 /// All comments found in the original regular expression.
443 pub comments: Vec<Comment>,
444}
445
446/// A comment from a regular expression with an associated span.
447///
448/// A regular expression can only contain comments when the `x` flag is
449/// enabled.
450#[derive(Clone, Debug, Eq, PartialEq)]
451#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
452pub struct Comment {
453 /// The span of this comment, including the beginning `#` and ending `\n`.
454 pub span: Span,
455 /// The comment text, starting with the first character following the `#`
456 /// and ending with the last character preceding the `\n`.
457 pub comment: String,
458}
459
460/// An abstract syntax tree for a single regular expression.
461///
462/// An `Ast`'s `fmt::Display` implementation uses constant stack space and heap
463/// space proportional to the size of the `Ast`.
464///
465/// This type defines its own destructor that uses constant stack space and
466/// heap space proportional to the size of the `Ast`.
467#[derive(Clone, Debug, Eq, PartialEq)]
468#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
469pub enum Ast {
470 /// An empty regex that matches everything.
471 Empty(Box<Span>),
472 /// A set of flags, e.g., `(?is)`.
473 Flags(Box<SetFlags>),
474 /// A single character literal, which includes escape sequences.
475 Literal(Box<Literal>),
476 /// The "any character" class.
477 Dot(Box<Span>),
478 /// A single zero-width assertion.
479 Assertion(Box<Assertion>),
480 /// A single Unicode character class, e.g., `\pL` or `\p{Greek}`.
481 ClassUnicode(Box<ClassUnicode>),
482 /// A single perl character class, e.g., `\d` or `\W`.
483 ClassPerl(Box<ClassPerl>),
484 /// A single bracketed character class set, which may contain zero or more
485 /// character ranges and/or zero or more nested classes. e.g.,
486 /// `[a-zA-Z\pL]`.
487 ClassBracketed(Box<ClassBracketed>),
488 /// A repetition operator applied to an arbitrary regular expression.
489 Repetition(Box<Repetition>),
490 /// A grouped regular expression.
491 Group(Box<Group>),
492 /// An alternation of regular expressions.
493 Alternation(Box<Alternation>),
494 /// A concatenation of regular expressions.
495 Concat(Box<Concat>),
496}
497
498impl Ast {
499 /// Create an "empty" AST item.
500 pub fn empty(span: Span) -> Ast {
501 Ast::Empty(Box::new(span))
502 }
503
504 /// Create a "flags" AST item.
505 pub fn flags(e: SetFlags) -> Ast {
506 Ast::Flags(Box::new(e))
507 }
508
509 /// Create a "literal" AST item.
510 pub fn literal(e: Literal) -> Ast {
511 Ast::Literal(Box::new(e))
512 }
513
514 /// Create a "dot" AST item.
515 pub fn dot(span: Span) -> Ast {
516 Ast::Dot(Box::new(span))
517 }
518
519 /// Create a "assertion" AST item.
520 pub fn assertion(e: Assertion) -> Ast {
521 Ast::Assertion(Box::new(e))
522 }
523
524 /// Create a "Unicode class" AST item.
525 pub fn class_unicode(e: ClassUnicode) -> Ast {
526 Ast::ClassUnicode(Box::new(e))
527 }
528
529 /// Create a "Perl class" AST item.
530 pub fn class_perl(e: ClassPerl) -> Ast {
531 Ast::ClassPerl(Box::new(e))
532 }
533
534 /// Create a "bracketed class" AST item.
535 pub fn class_bracketed(e: ClassBracketed) -> Ast {
536 Ast::ClassBracketed(Box::new(e))
537 }
538
539 /// Create a "repetition" AST item.
540 pub fn repetition(e: Repetition) -> Ast {
541 Ast::Repetition(Box::new(e))
542 }
543
544 /// Create a "group" AST item.
545 pub fn group(e: Group) -> Ast {
546 Ast::Group(Box::new(e))
547 }
548
549 /// Create a "alternation" AST item.
550 pub fn alternation(e: Alternation) -> Ast {
551 Ast::Alternation(Box::new(e))
552 }
553
554 /// Create a "concat" AST item.
555 pub fn concat(e: Concat) -> Ast {
556 Ast::Concat(Box::new(e))
557 }
558
559 /// Return the span of this abstract syntax tree.
560 pub fn span(&self) -> &Span {
561 match *self {
562 Ast::Empty(ref span) => span,
563 Ast::Flags(ref x) => &x.span,
564 Ast::Literal(ref x) => &x.span,
565 Ast::Dot(ref span) => span,
566 Ast::Assertion(ref x) => &x.span,
567 Ast::ClassUnicode(ref x) => &x.span,
568 Ast::ClassPerl(ref x) => &x.span,
569 Ast::ClassBracketed(ref x) => &x.span,
570 Ast::Repetition(ref x) => &x.span,
571 Ast::Group(ref x) => &x.span,
572 Ast::Alternation(ref x) => &x.span,
573 Ast::Concat(ref x) => &x.span,
574 }
575 }
576
577 /// Return true if and only if this Ast is empty.
578 pub fn is_empty(&self) -> bool {
579 match *self {
580 Ast::Empty(_) => true,
581 _ => false,
582 }
583 }
584
585 /// Returns true if and only if this AST has any (including possibly empty)
586 /// subexpressions.
587 fn has_subexprs(&self) -> bool {
588 match *self {
589 Ast::Empty(_)
590 | Ast::Flags(_)
591 | Ast::Literal(_)
592 | Ast::Dot(_)
593 | Ast::Assertion(_)
594 | Ast::ClassUnicode(_)
595 | Ast::ClassPerl(_) => false,
596 Ast::ClassBracketed(_)
597 | Ast::Repetition(_)
598 | Ast::Group(_)
599 | Ast::Alternation(_)
600 | Ast::Concat(_) => true,
601 }
602 }
603}
604
605/// Print a display representation of this Ast.
606///
607/// This does not preserve any of the original whitespace formatting that may
608/// have originally been present in the concrete syntax from which this Ast
609/// was generated.
610///
611/// This implementation uses constant stack space and heap space proportional
612/// to the size of the `Ast`.
613impl core::fmt::Display for Ast {
614 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
615 use crate::ast::print::Printer;
616 Printer::new().print(self, f)
617 }
618}
619
620/// An alternation of regular expressions.
621#[derive(Clone, Debug, Eq, PartialEq)]
622#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
623pub struct Alternation {
624 /// The span of this alternation.
625 pub span: Span,
626 /// The alternate regular expressions.
627 pub asts: Vec<Ast>,
628}
629
630impl Alternation {
631 /// Return this alternation as an AST.
632 ///
633 /// If this alternation contains zero ASTs, then `Ast::empty` is returned.
634 /// If this alternation contains exactly 1 AST, then the corresponding AST
635 /// is returned. Otherwise, `Ast::alternation` is returned.
636 pub fn into_ast(mut self) -> Ast {
637 match self.asts.len() {
638 0 => Ast::empty(self.span),
639 1 => self.asts.pop().unwrap(),
640 _ => Ast::alternation(self),
641 }
642 }
643}
644
645/// A concatenation of regular expressions.
646#[derive(Clone, Debug, Eq, PartialEq)]
647#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
648pub struct Concat {
649 /// The span of this concatenation.
650 pub span: Span,
651 /// The concatenation regular expressions.
652 pub asts: Vec<Ast>,
653}
654
655impl Concat {
656 /// Return this concatenation as an AST.
657 ///
658 /// If this alternation contains zero ASTs, then `Ast::empty` is returned.
659 /// If this alternation contains exactly 1 AST, then the corresponding AST
660 /// is returned. Otherwise, `Ast::concat` is returned.
661 pub fn into_ast(mut self) -> Ast {
662 match self.asts.len() {
663 0 => Ast::empty(self.span),
664 1 => self.asts.pop().unwrap(),
665 _ => Ast::concat(self),
666 }
667 }
668}
669
670/// A single literal expression.
671///
672/// A literal corresponds to a single Unicode scalar value. Literals may be
673/// represented in their literal form, e.g., `a` or in their escaped form,
674/// e.g., `\x61`.
675#[derive(Clone, Debug, Eq, PartialEq)]
676#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
677pub struct Literal {
678 /// The span of this literal.
679 pub span: Span,
680 /// The kind of this literal.
681 pub kind: LiteralKind,
682 /// The Unicode scalar value corresponding to this literal.
683 pub c: char,
684}
685
686impl Literal {
687 /// If this literal was written as a `\x` hex escape, then this returns
688 /// the corresponding byte value. Otherwise, this returns `None`.
689 pub fn byte(&self) -> Option<u8> {
690 match self.kind {
691 LiteralKind::HexFixed(HexLiteralKind::X) => {
692 u8::try_from(self.c).ok()
693 }
694 _ => None,
695 }
696 }
697}
698
699/// The kind of a single literal expression.
700#[derive(Clone, Debug, Eq, PartialEq)]
701#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
702pub enum LiteralKind {
703 /// The literal is written verbatim, e.g., `a` or `☃`.
704 Verbatim,
705 /// The literal is written as an escape because it is otherwise a special
706 /// regex meta character, e.g., `\*` or `\[`.
707 Meta,
708 /// The literal is written as an escape despite the fact that the escape is
709 /// unnecessary, e.g., `\%` or `\/`.
710 Superfluous,
711 /// The literal is written as an octal escape, e.g., `\141`.
712 Octal,
713 /// The literal is written as a hex code with a fixed number of digits
714 /// depending on the type of the escape, e.g., `\x61` or or `\u0061` or
715 /// `\U00000061`.
716 HexFixed(HexLiteralKind),
717 /// The literal is written as a hex code with a bracketed number of
718 /// digits. The only restriction is that the bracketed hex code must refer
719 /// to a valid Unicode scalar value.
720 HexBrace(HexLiteralKind),
721 /// The literal is written as a specially recognized escape, e.g., `\f`
722 /// or `\n`.
723 Special(SpecialLiteralKind),
724}
725
726/// The type of a special literal.
727///
728/// A special literal is a special escape sequence recognized by the regex
729/// parser, e.g., `\f` or `\n`.
730#[derive(Clone, Debug, Eq, PartialEq)]
731#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
732pub enum SpecialLiteralKind {
733 /// Bell, spelled `\a` (`\x07`).
734 Bell,
735 /// Form feed, spelled `\f` (`\x0C`).
736 FormFeed,
737 /// Tab, spelled `\t` (`\x09`).
738 Tab,
739 /// Line feed, spelled `\n` (`\x0A`).
740 LineFeed,
741 /// Carriage return, spelled `\r` (`\x0D`).
742 CarriageReturn,
743 /// Vertical tab, spelled `\v` (`\x0B`).
744 VerticalTab,
745 /// Space, spelled `\ ` (`\x20`). Note that this can only appear when
746 /// parsing in verbose mode.
747 Space,
748}
749
750/// The type of a Unicode hex literal.
751///
752/// Note that all variants behave the same when used with brackets. They only
753/// differ when used without brackets in the number of hex digits that must
754/// follow.
755#[derive(Clone, Debug, Eq, PartialEq)]
756#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
757pub enum HexLiteralKind {
758 /// A `\x` prefix. When used without brackets, this form is limited to
759 /// two digits.
760 X,
761 /// A `\u` prefix. When used without brackets, this form is limited to
762 /// four digits.
763 UnicodeShort,
764 /// A `\U` prefix. When used without brackets, this form is limited to
765 /// eight digits.
766 UnicodeLong,
767}
768
769impl HexLiteralKind {
770 /// The number of digits that must be used with this literal form when
771 /// used without brackets. When used with brackets, there is no
772 /// restriction on the number of digits.
773 pub fn digits(&self) -> u32 {
774 match *self {
775 HexLiteralKind::X => 2,
776 HexLiteralKind::UnicodeShort => 4,
777 HexLiteralKind::UnicodeLong => 8,
778 }
779 }
780}
781
782/// A Perl character class.
783#[derive(Clone, Debug, Eq, PartialEq)]
784#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
785pub struct ClassPerl {
786 /// The span of this class.
787 pub span: Span,
788 /// The kind of Perl class.
789 pub kind: ClassPerlKind,
790 /// Whether the class is negated or not. e.g., `\d` is not negated but
791 /// `\D` is.
792 pub negated: bool,
793}
794
795/// The available Perl character classes.
796#[derive(Clone, Debug, Eq, PartialEq)]
797#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
798pub enum ClassPerlKind {
799 /// Decimal numbers.
800 Digit,
801 /// Whitespace.
802 Space,
803 /// Word characters.
804 Word,
805}
806
807/// An ASCII character class.
808#[derive(Clone, Debug, Eq, PartialEq)]
809#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
810pub struct ClassAscii {
811 /// The span of this class.
812 pub span: Span,
813 /// The kind of ASCII class.
814 pub kind: ClassAsciiKind,
815 /// Whether the class is negated or not. e.g., `[[:alpha:]]` is not negated
816 /// but `[[:^alpha:]]` is.
817 pub negated: bool,
818}
819
820/// The available ASCII character classes.
821#[derive(Clone, Debug, Eq, PartialEq)]
822#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
823pub enum ClassAsciiKind {
824 /// `[0-9A-Za-z]`
825 Alnum,
826 /// `[A-Za-z]`
827 Alpha,
828 /// `[\x00-\x7F]`
829 Ascii,
830 /// `[ \t]`
831 Blank,
832 /// `[\x00-\x1F\x7F]`
833 Cntrl,
834 /// `[0-9]`
835 Digit,
836 /// `[!-~]`
837 Graph,
838 /// `[a-z]`
839 Lower,
840 /// `[ -~]`
841 Print,
842 /// `[!-/:-@\[-`{-~]`
843 Punct,
844 /// `[\t\n\v\f\r ]`
845 Space,
846 /// `[A-Z]`
847 Upper,
848 /// `[0-9A-Za-z_]`
849 Word,
850 /// `[0-9A-Fa-f]`
851 Xdigit,
852}
853
854impl ClassAsciiKind {
855 /// Return the corresponding ClassAsciiKind variant for the given name.
856 ///
857 /// The name given should correspond to the lowercase version of the
858 /// variant name. e.g., `cntrl` is the name for `ClassAsciiKind::Cntrl`.
859 ///
860 /// If no variant with the corresponding name exists, then `None` is
861 /// returned.
862 pub fn from_name(name: &str) -> Option<ClassAsciiKind> {
863 use self::ClassAsciiKind::*;
864 match name {
865 "alnum" => Some(Alnum),
866 "alpha" => Some(Alpha),
867 "ascii" => Some(Ascii),
868 "blank" => Some(Blank),
869 "cntrl" => Some(Cntrl),
870 "digit" => Some(Digit),
871 "graph" => Some(Graph),
872 "lower" => Some(Lower),
873 "print" => Some(Print),
874 "punct" => Some(Punct),
875 "space" => Some(Space),
876 "upper" => Some(Upper),
877 "word" => Some(Word),
878 "xdigit" => Some(Xdigit),
879 _ => None,
880 }
881 }
882}
883
884/// A Unicode character class.
885#[derive(Clone, Debug, Eq, PartialEq)]
886#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
887pub struct ClassUnicode {
888 /// The span of this class.
889 pub span: Span,
890 /// Whether this class is negated or not.
891 ///
892 /// Note: be careful when using this attribute. This specifically refers
893 /// to whether the class is written as `\p` or `\P`, where the latter
894 /// is `negated = true`. However, it also possible to write something like
895 /// `\P{scx!=Katakana}` which is actually equivalent to
896 /// `\p{scx=Katakana}` and is therefore not actually negated even though
897 /// `negated = true` here. To test whether this class is truly negated
898 /// or not, use the `is_negated` method.
899 pub negated: bool,
900 /// The kind of Unicode class.
901 pub kind: ClassUnicodeKind,
902}
903
904impl ClassUnicode {
905 /// Returns true if this class has been negated.
906 ///
907 /// Note that this takes the Unicode op into account, if it's present.
908 /// e.g., `is_negated` for `\P{scx!=Katakana}` will return `false`.
909 pub fn is_negated(&self) -> bool {
910 match self.kind {
911 ClassUnicodeKind::NamedValue {
912 op: ClassUnicodeOpKind::NotEqual,
913 ..
914 } => !self.negated,
915 _ => self.negated,
916 }
917 }
918}
919
920/// The available forms of Unicode character classes.
921#[derive(Clone, Debug, Eq, PartialEq)]
922pub enum ClassUnicodeKind {
923 /// A one letter abbreviated class, e.g., `\pN`.
924 OneLetter(char),
925 /// A binary property, general category or script. The string may be
926 /// empty.
927 Named(String),
928 /// A property name and an associated value.
929 NamedValue {
930 /// The type of Unicode op used to associate `name` with `value`.
931 op: ClassUnicodeOpKind,
932 /// The property name (which may be empty).
933 name: String,
934 /// The property value (which may be empty).
935 value: String,
936 },
937}
938
939#[cfg(feature = "arbitrary")]
940impl arbitrary::Arbitrary<'_> for ClassUnicodeKind {
941 fn arbitrary(
942 u: &mut arbitrary::Unstructured,
943 ) -> arbitrary::Result<ClassUnicodeKind> {
944 #[cfg(any(
945 feature = "unicode-age",
946 feature = "unicode-bool",
947 feature = "unicode-gencat",
948 feature = "unicode-perl",
949 feature = "unicode-script",
950 feature = "unicode-segment",
951 ))]
952 {
953 use alloc::string::ToString;
954
955 use super::unicode_tables::{
956 property_names::PROPERTY_NAMES,
957 property_values::PROPERTY_VALUES,
958 };
959
960 match u.choose_index(3)? {
961 0 => {
962 let all = PROPERTY_VALUES
963 .iter()
964 .flat_map(|e| e.1.iter())
965 .filter(|(name, _)| name.len() == 1)
966 .count();
967 let idx = u.choose_index(all)?;
968 let value = PROPERTY_VALUES
969 .iter()
970 .flat_map(|e| e.1.iter())
971 .take(idx + 1)
972 .last()
973 .unwrap()
974 .0
975 .chars()
976 .next()
977 .unwrap();
978 Ok(ClassUnicodeKind::OneLetter(value))
979 }
980 1 => {
981 let all = PROPERTY_VALUES
982 .iter()
983 .map(|e| e.1.len())
984 .sum::<usize>()
985 + PROPERTY_NAMES.len();
986 let idx = u.choose_index(all)?;
987 let name = PROPERTY_VALUES
988 .iter()
989 .flat_map(|e| e.1.iter())
990 .chain(PROPERTY_NAMES)
991 .map(|(_, e)| e)
992 .take(idx + 1)
993 .last()
994 .unwrap();
995 Ok(ClassUnicodeKind::Named(name.to_string()))
996 }
997 2 => {
998 let all = PROPERTY_VALUES
999 .iter()
1000 .map(|e| e.1.len())
1001 .sum::<usize>();
1002 let idx = u.choose_index(all)?;
1003 let (prop, value) = PROPERTY_VALUES
1004 .iter()
1005 .flat_map(|e| {
1006 e.1.iter().map(|(_, value)| (e.0, value))
1007 })
1008 .take(idx + 1)
1009 .last()
1010 .unwrap();
1011 Ok(ClassUnicodeKind::NamedValue {
1012 op: u.arbitrary()?,
1013 name: prop.to_string(),
1014 value: value.to_string(),
1015 })
1016 }
1017 _ => unreachable!("index chosen is impossible"),
1018 }
1019 }
1020 #[cfg(not(any(
1021 feature = "unicode-age",
1022 feature = "unicode-bool",
1023 feature = "unicode-gencat",
1024 feature = "unicode-perl",
1025 feature = "unicode-script",
1026 feature = "unicode-segment",
1027 )))]
1028 {
1029 match u.choose_index(3)? {
1030 0 => Ok(ClassUnicodeKind::OneLetter(u.arbitrary()?)),
1031 1 => Ok(ClassUnicodeKind::Named(u.arbitrary()?)),
1032 2 => Ok(ClassUnicodeKind::NamedValue {
1033 op: u.arbitrary()?,
1034 name: u.arbitrary()?,
1035 value: u.arbitrary()?,
1036 }),
1037 _ => unreachable!("index chosen is impossible"),
1038 }
1039 }
1040 }
1041
1042 fn size_hint(depth: usize) -> (usize, Option<usize>) {
1043 #[cfg(any(
1044 feature = "unicode-age",
1045 feature = "unicode-bool",
1046 feature = "unicode-gencat",
1047 feature = "unicode-perl",
1048 feature = "unicode-script",
1049 feature = "unicode-segment",
1050 ))]
1051 {
1052 arbitrary::size_hint::and_all(&[
1053 usize::size_hint(depth),
1054 usize::size_hint(depth),
1055 arbitrary::size_hint::or(
1056 (0, Some(0)),
1057 ClassUnicodeOpKind::size_hint(depth),
1058 ),
1059 ])
1060 }
1061 #[cfg(not(any(
1062 feature = "unicode-age",
1063 feature = "unicode-bool",
1064 feature = "unicode-gencat",
1065 feature = "unicode-perl",
1066 feature = "unicode-script",
1067 feature = "unicode-segment",
1068 )))]
1069 {
1070 arbitrary::size_hint::and(
1071 usize::size_hint(depth),
1072 arbitrary::size_hint::or_all(&[
1073 char::size_hint(depth),
1074 String::size_hint(depth),
1075 arbitrary::size_hint::and_all(&[
1076 String::size_hint(depth),
1077 String::size_hint(depth),
1078 ClassUnicodeOpKind::size_hint(depth),
1079 ]),
1080 ]),
1081 )
1082 }
1083 }
1084}
1085
1086/// The type of op used in a Unicode character class.
1087#[derive(Clone, Debug, Eq, PartialEq)]
1088#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1089pub enum ClassUnicodeOpKind {
1090 /// A property set to a specific value, e.g., `\p{scx=Katakana}`.
1091 Equal,
1092 /// A property set to a specific value using a colon, e.g.,
1093 /// `\p{scx:Katakana}`.
1094 Colon,
1095 /// A property that isn't a particular value, e.g., `\p{scx!=Katakana}`.
1096 NotEqual,
1097}
1098
1099impl ClassUnicodeOpKind {
1100 /// Whether the op is an equality op or not.
1101 pub fn is_equal(&self) -> bool {
1102 match *self {
1103 ClassUnicodeOpKind::Equal | ClassUnicodeOpKind::Colon => true,
1104 _ => false,
1105 }
1106 }
1107}
1108
1109/// A bracketed character class, e.g., `[a-z0-9]`.
1110#[derive(Clone, Debug, Eq, PartialEq)]
1111#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1112pub struct ClassBracketed {
1113 /// The span of this class.
1114 pub span: Span,
1115 /// Whether this class is negated or not. e.g., `[a]` is not negated but
1116 /// `[^a]` is.
1117 pub negated: bool,
1118 /// The type of this set. A set is either a normal union of things, e.g.,
1119 /// `[abc]` or a result of applying set operations, e.g., `[\pL--c]`.
1120 pub kind: ClassSet,
1121}
1122
1123/// A character class set.
1124///
1125/// This type corresponds to the internal structure of a bracketed character
1126/// class. That is, every bracketed character is one of two types: a union of
1127/// items (literals, ranges, other bracketed classes) or a tree of binary set
1128/// operations.
1129#[derive(Clone, Debug, Eq, PartialEq)]
1130#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1131pub enum ClassSet {
1132 /// An item, which can be a single literal, range, nested character class
1133 /// or a union of items.
1134 Item(ClassSetItem),
1135 /// A single binary operation (i.e., &&, -- or ~~).
1136 BinaryOp(ClassSetBinaryOp),
1137}
1138
1139impl ClassSet {
1140 /// Build a set from a union.
1141 pub fn union(ast: ClassSetUnion) -> ClassSet {
1142 ClassSet::Item(ClassSetItem::Union(ast))
1143 }
1144
1145 /// Return the span of this character class set.
1146 pub fn span(&self) -> &Span {
1147 match *self {
1148 ClassSet::Item(ref x) => x.span(),
1149 ClassSet::BinaryOp(ref x) => &x.span,
1150 }
1151 }
1152
1153 /// Return true if and only if this class set is empty.
1154 fn is_empty(&self) -> bool {
1155 match *self {
1156 ClassSet::Item(ClassSetItem::Empty(_)) => true,
1157 _ => false,
1158 }
1159 }
1160}
1161
1162/// A single component of a character class set.
1163#[derive(Clone, Debug, Eq, PartialEq)]
1164#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1165pub enum ClassSetItem {
1166 /// An empty item.
1167 ///
1168 /// Note that a bracketed character class cannot contain a single empty
1169 /// item. Empty items can appear when using one of the binary operators.
1170 /// For example, `[&&]` is the intersection of two empty classes.
1171 Empty(Span),
1172 /// A single literal.
1173 Literal(Literal),
1174 /// A range between two literals.
1175 Range(ClassSetRange),
1176 /// An ASCII character class, e.g., `[:alnum:]` or `[:punct:]`.
1177 Ascii(ClassAscii),
1178 /// A Unicode character class, e.g., `\pL` or `\p{Greek}`.
1179 Unicode(ClassUnicode),
1180 /// A perl character class, e.g., `\d` or `\W`.
1181 Perl(ClassPerl),
1182 /// A bracketed character class set, which may contain zero or more
1183 /// character ranges and/or zero or more nested classes. e.g.,
1184 /// `[a-zA-Z\pL]`.
1185 Bracketed(Box<ClassBracketed>),
1186 /// A union of items.
1187 Union(ClassSetUnion),
1188}
1189
1190impl ClassSetItem {
1191 /// Return the span of this character class set item.
1192 pub fn span(&self) -> &Span {
1193 match *self {
1194 ClassSetItem::Empty(ref span) => span,
1195 ClassSetItem::Literal(ref x) => &x.span,
1196 ClassSetItem::Range(ref x) => &x.span,
1197 ClassSetItem::Ascii(ref x) => &x.span,
1198 ClassSetItem::Perl(ref x) => &x.span,
1199 ClassSetItem::Unicode(ref x) => &x.span,
1200 ClassSetItem::Bracketed(ref x) => &x.span,
1201 ClassSetItem::Union(ref x) => &x.span,
1202 }
1203 }
1204}
1205
1206/// A single character class range in a set.
1207#[derive(Clone, Debug, Eq, PartialEq)]
1208#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1209pub struct ClassSetRange {
1210 /// The span of this range.
1211 pub span: Span,
1212 /// The start of this range.
1213 pub start: Literal,
1214 /// The end of this range.
1215 pub end: Literal,
1216}
1217
1218impl ClassSetRange {
1219 /// Returns true if and only if this character class range is valid.
1220 ///
1221 /// The only case where a range is invalid is if its start is greater than
1222 /// its end.
1223 pub fn is_valid(&self) -> bool {
1224 self.start.c <= self.end.c
1225 }
1226}
1227
1228/// A union of items inside a character class set.
1229#[derive(Clone, Debug, Eq, PartialEq)]
1230#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1231pub struct ClassSetUnion {
1232 /// The span of the items in this operation. e.g., the `a-z0-9` in
1233 /// `[^a-z0-9]`
1234 pub span: Span,
1235 /// The sequence of items that make up this union.
1236 pub items: Vec<ClassSetItem>,
1237}
1238
1239impl ClassSetUnion {
1240 /// Push a new item in this union.
1241 ///
1242 /// The ending position of this union's span is updated to the ending
1243 /// position of the span of the item given. If the union is empty, then
1244 /// the starting position of this union is set to the starting position
1245 /// of this item.
1246 ///
1247 /// In other words, if you only use this method to add items to a union
1248 /// and you set the spans on each item correctly, then you should never
1249 /// need to adjust the span of the union directly.
1250 pub fn push(&mut self, item: ClassSetItem) {
1251 if self.items.is_empty() {
1252 self.span.start = item.span().start;
1253 }
1254 self.span.end = item.span().end;
1255 self.items.push(item);
1256 }
1257
1258 /// Return this union as a character class set item.
1259 ///
1260 /// If this union contains zero items, then an empty union is
1261 /// returned. If this concatenation contains exactly 1 item, then the
1262 /// corresponding item is returned. Otherwise, ClassSetItem::Union is
1263 /// returned.
1264 pub fn into_item(mut self) -> ClassSetItem {
1265 match self.items.len() {
1266 0 => ClassSetItem::Empty(self.span),
1267 1 => self.items.pop().unwrap(),
1268 _ => ClassSetItem::Union(self),
1269 }
1270 }
1271}
1272
1273/// A Unicode character class set operation.
1274#[derive(Clone, Debug, Eq, PartialEq)]
1275#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1276pub struct ClassSetBinaryOp {
1277 /// The span of this operation. e.g., the `a-z--[h-p]` in `[a-z--h-p]`.
1278 pub span: Span,
1279 /// The type of this set operation.
1280 pub kind: ClassSetBinaryOpKind,
1281 /// The left hand side of the operation.
1282 pub lhs: Box<ClassSet>,
1283 /// The right hand side of the operation.
1284 pub rhs: Box<ClassSet>,
1285}
1286
1287/// The type of a Unicode character class set operation.
1288///
1289/// Note that this doesn't explicitly represent union since there is no
1290/// explicit union operator. Concatenation inside a character class corresponds
1291/// to the union operation.
1292#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1293#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1294pub enum ClassSetBinaryOpKind {
1295 /// The intersection of two sets, e.g., `\pN&&[a-z]`.
1296 Intersection,
1297 /// The difference of two sets, e.g., `\pN--[0-9]`.
1298 Difference,
1299 /// The symmetric difference of two sets. The symmetric difference is the
1300 /// set of elements belonging to one but not both sets.
1301 /// e.g., `[\pL~~[:ascii:]]`.
1302 SymmetricDifference,
1303}
1304
1305/// A single zero-width assertion.
1306#[derive(Clone, Debug, Eq, PartialEq)]
1307#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1308pub struct Assertion {
1309 /// The span of this assertion.
1310 pub span: Span,
1311 /// The assertion kind, e.g., `\b` or `^`.
1312 pub kind: AssertionKind,
1313}
1314
1315/// An assertion kind.
1316#[derive(Clone, Debug, Eq, PartialEq)]
1317#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1318pub enum AssertionKind {
1319 /// `^`
1320 StartLine,
1321 /// `$`
1322 EndLine,
1323 /// `\A`
1324 StartText,
1325 /// `\z`
1326 EndText,
1327 /// `\b`
1328 WordBoundary,
1329 /// `\B`
1330 NotWordBoundary,
1331 /// `\b{start}`
1332 WordBoundaryStart,
1333 /// `\b{end}`
1334 WordBoundaryEnd,
1335 /// `\<` (alias for `\b{start}`)
1336 WordBoundaryStartAngle,
1337 /// `\>` (alias for `\b{end}`)
1338 WordBoundaryEndAngle,
1339 /// `\b{start-half}`
1340 WordBoundaryStartHalf,
1341 /// `\b{end-half}`
1342 WordBoundaryEndHalf,
1343}
1344
1345/// A repetition operation applied to a regular expression.
1346#[derive(Clone, Debug, Eq, PartialEq)]
1347#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1348pub struct Repetition {
1349 /// The span of this operation.
1350 pub span: Span,
1351 /// The actual operation.
1352 pub op: RepetitionOp,
1353 /// Whether this operation was applied greedily or not.
1354 pub greedy: bool,
1355 /// The regular expression under repetition.
1356 pub ast: Box<Ast>,
1357}
1358
1359/// The repetition operator itself.
1360#[derive(Clone, Debug, Eq, PartialEq)]
1361#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1362pub struct RepetitionOp {
1363 /// The span of this operator. This includes things like `+`, `*?` and
1364 /// `{m,n}`.
1365 pub span: Span,
1366 /// The type of operation.
1367 pub kind: RepetitionKind,
1368}
1369
1370/// The kind of a repetition operator.
1371#[derive(Clone, Debug, Eq, PartialEq)]
1372#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1373pub enum RepetitionKind {
1374 /// `?`
1375 ZeroOrOne,
1376 /// `*`
1377 ZeroOrMore,
1378 /// `+`
1379 OneOrMore,
1380 /// `{m,n}`
1381 Range(RepetitionRange),
1382}
1383
1384/// A range repetition operator.
1385#[derive(Clone, Debug, Eq, PartialEq)]
1386#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1387pub enum RepetitionRange {
1388 /// `{m}`
1389 Exactly(u32),
1390 /// `{m,}`
1391 AtLeast(u32),
1392 /// `{m,n}`
1393 Bounded(u32, u32),
1394}
1395
1396impl RepetitionRange {
1397 /// Returns true if and only if this repetition range is valid.
1398 ///
1399 /// The only case where a repetition range is invalid is if it is bounded
1400 /// and its start is greater than its end.
1401 pub fn is_valid(&self) -> bool {
1402 match *self {
1403 RepetitionRange::Bounded(s, e) if s > e => false,
1404 _ => true,
1405 }
1406 }
1407}
1408
1409/// A grouped regular expression.
1410///
1411/// This includes both capturing and non-capturing groups. This does **not**
1412/// include flag-only groups like `(?is)`, but does contain any group that
1413/// contains a sub-expression, e.g., `(a)`, `(?P<name>a)`, `(?:a)` and
1414/// `(?is:a)`.
1415#[derive(Clone, Debug, Eq, PartialEq)]
1416#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1417pub struct Group {
1418 /// The span of this group.
1419 pub span: Span,
1420 /// The kind of this group.
1421 pub kind: GroupKind,
1422 /// The regular expression in this group.
1423 pub ast: Box<Ast>,
1424}
1425
1426impl Group {
1427 /// If this group is non-capturing, then this returns the (possibly empty)
1428 /// set of flags. Otherwise, `None` is returned.
1429 pub fn flags(&self) -> Option<&Flags> {
1430 match self.kind {
1431 GroupKind::NonCapturing(ref flags) => Some(flags),
1432 _ => None,
1433 }
1434 }
1435
1436 /// Returns true if and only if this group is capturing.
1437 pub fn is_capturing(&self) -> bool {
1438 match self.kind {
1439 GroupKind::CaptureIndex(_) | GroupKind::CaptureName { .. } => true,
1440 GroupKind::NonCapturing(_) => false,
1441 }
1442 }
1443
1444 /// Returns the capture index of this group, if this is a capturing group.
1445 ///
1446 /// This returns a capture index precisely when `is_capturing` is `true`.
1447 pub fn capture_index(&self) -> Option<u32> {
1448 match self.kind {
1449 GroupKind::CaptureIndex(i) => Some(i),
1450 GroupKind::CaptureName { ref name, .. } => Some(name.index),
1451 GroupKind::NonCapturing(_) => None,
1452 }
1453 }
1454}
1455
1456/// The kind of a group.
1457#[derive(Clone, Debug, Eq, PartialEq)]
1458#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1459pub enum GroupKind {
1460 /// `(a)`
1461 CaptureIndex(u32),
1462 /// `(?<name>a)` or `(?P<name>a)`
1463 CaptureName {
1464 /// True if the `?P<` syntax is used and false if the `?<` syntax is used.
1465 starts_with_p: bool,
1466 /// The capture name.
1467 name: CaptureName,
1468 },
1469 /// `(?:a)` and `(?i:a)`
1470 NonCapturing(Flags),
1471}
1472
1473/// A capture name.
1474///
1475/// This corresponds to the name itself between the angle brackets in, e.g.,
1476/// `(?P<foo>expr)`.
1477#[derive(Clone, Debug, Eq, PartialEq)]
1478pub struct CaptureName {
1479 /// The span of this capture name.
1480 pub span: Span,
1481 /// The capture name.
1482 pub name: String,
1483 /// The capture index.
1484 pub index: u32,
1485}
1486
1487#[cfg(feature = "arbitrary")]
1488impl arbitrary::Arbitrary<'_> for CaptureName {
1489 fn arbitrary(
1490 u: &mut arbitrary::Unstructured,
1491 ) -> arbitrary::Result<CaptureName> {
1492 let len = u.arbitrary_len::<char>()?;
1493 if len == 0 {
1494 return Err(arbitrary::Error::NotEnoughData);
1495 }
1496 let mut name: String = String::new();
1497 for _ in 0..len {
1498 let ch: char = u.arbitrary()?;
1499 let cp = u32::from(ch);
1500 let ascii_letter_offset = u8::try_from(cp % 26).unwrap();
1501 let ascii_letter = b'a' + ascii_letter_offset;
1502 name.push(char::from(ascii_letter));
1503 }
1504 Ok(CaptureName { span: u.arbitrary()?, name, index: u.arbitrary()? })
1505 }
1506
1507 fn size_hint(depth: usize) -> (usize, Option<usize>) {
1508 arbitrary::size_hint::and_all(&[
1509 Span::size_hint(depth),
1510 usize::size_hint(depth),
1511 u32::size_hint(depth),
1512 ])
1513 }
1514}
1515
1516/// A group of flags that is not applied to a particular regular expression.
1517#[derive(Clone, Debug, Eq, PartialEq)]
1518#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1519pub struct SetFlags {
1520 /// The span of these flags, including the grouping parentheses.
1521 pub span: Span,
1522 /// The actual sequence of flags.
1523 pub flags: Flags,
1524}
1525
1526/// A group of flags.
1527///
1528/// This corresponds only to the sequence of flags themselves, e.g., `is-u`.
1529#[derive(Clone, Debug, Eq, PartialEq)]
1530#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1531pub struct Flags {
1532 /// The span of this group of flags.
1533 pub span: Span,
1534 /// A sequence of flag items. Each item is either a flag or a negation
1535 /// operator.
1536 pub items: Vec<FlagsItem>,
1537}
1538
1539impl Flags {
1540 /// Add the given item to this sequence of flags.
1541 ///
1542 /// If the item was added successfully, then `None` is returned. If the
1543 /// given item is a duplicate, then `Some(i)` is returned, where
1544 /// `items[i].kind == item.kind`.
1545 pub fn add_item(&mut self, item: FlagsItem) -> Option<usize> {
1546 for (i, x) in self.items.iter().enumerate() {
1547 if x.kind == item.kind {
1548 return Some(i);
1549 }
1550 }
1551 self.items.push(item);
1552 None
1553 }
1554
1555 /// Returns the state of the given flag in this set.
1556 ///
1557 /// If the given flag is in the set but is negated, then `Some(false)` is
1558 /// returned.
1559 ///
1560 /// If the given flag is in the set and is not negated, then `Some(true)`
1561 /// is returned.
1562 ///
1563 /// Otherwise, `None` is returned.
1564 pub fn flag_state(&self, flag: Flag) -> Option<bool> {
1565 let mut negated = false;
1566 for x in &self.items {
1567 match x.kind {
1568 FlagsItemKind::Negation => {
1569 negated = true;
1570 }
1571 FlagsItemKind::Flag(ref xflag) if xflag == &flag => {
1572 return Some(!negated);
1573 }
1574 _ => {}
1575 }
1576 }
1577 None
1578 }
1579}
1580
1581/// A single item in a group of flags.
1582#[derive(Clone, Debug, Eq, PartialEq)]
1583#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1584pub struct FlagsItem {
1585 /// The span of this item.
1586 pub span: Span,
1587 /// The kind of this item.
1588 pub kind: FlagsItemKind,
1589}
1590
1591/// The kind of an item in a group of flags.
1592#[derive(Clone, Debug, Eq, PartialEq)]
1593#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1594pub enum FlagsItemKind {
1595 /// A negation operator applied to all subsequent flags in the enclosing
1596 /// group.
1597 Negation,
1598 /// A single flag in a group.
1599 Flag(Flag),
1600}
1601
1602impl FlagsItemKind {
1603 /// Returns true if and only if this item is a negation operator.
1604 pub fn is_negation(&self) -> bool {
1605 match *self {
1606 FlagsItemKind::Negation => true,
1607 _ => false,
1608 }
1609 }
1610}
1611
1612/// A single flag.
1613#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1614#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1615pub enum Flag {
1616 /// `i`
1617 CaseInsensitive,
1618 /// `m`
1619 MultiLine,
1620 /// `s`
1621 DotMatchesNewLine,
1622 /// `U`
1623 SwapGreed,
1624 /// `u`
1625 Unicode,
1626 /// `R`
1627 CRLF,
1628 /// `x`
1629 IgnoreWhitespace,
1630}
1631
1632/// A custom `Drop` impl is used for `Ast` such that it uses constant stack
1633/// space but heap space proportional to the depth of the `Ast`.
1634impl Drop for Ast {
1635 fn drop(&mut self) {
1636 use core::mem;
1637
1638 match *self {
1639 Ast::Empty(_)
1640 | Ast::Flags(_)
1641 | Ast::Literal(_)
1642 | Ast::Dot(_)
1643 | Ast::Assertion(_)
1644 | Ast::ClassUnicode(_)
1645 | Ast::ClassPerl(_)
1646 // Bracketed classes are recursive, they get their own Drop impl.
1647 | Ast::ClassBracketed(_) => return,
1648 Ast::Repetition(ref x) if !x.ast.has_subexprs() => return,
1649 Ast::Group(ref x) if !x.ast.has_subexprs() => return,
1650 Ast::Alternation(ref x) if x.asts.is_empty() => return,
1651 Ast::Concat(ref x) if x.asts.is_empty() => return,
1652 _ => {}
1653 }
1654
1655 let empty_span = || Span::splat(Position::new(0, 0, 0));
1656 let empty_ast = || Ast::empty(empty_span());
1657 let mut stack = vec![mem::replace(self, empty_ast())];
1658 while let Some(mut ast) = stack.pop() {
1659 match ast {
1660 Ast::Empty(_)
1661 | Ast::Flags(_)
1662 | Ast::Literal(_)
1663 | Ast::Dot(_)
1664 | Ast::Assertion(_)
1665 | Ast::ClassUnicode(_)
1666 | Ast::ClassPerl(_)
1667 // Bracketed classes are recursive, so they get their own Drop
1668 // impl.
1669 | Ast::ClassBracketed(_) => {}
1670 Ast::Repetition(ref mut x) => {
1671 stack.push(mem::replace(&mut x.ast, empty_ast()));
1672 }
1673 Ast::Group(ref mut x) => {
1674 stack.push(mem::replace(&mut x.ast, empty_ast()));
1675 }
1676 Ast::Alternation(ref mut x) => {
1677 stack.extend(x.asts.drain(..));
1678 }
1679 Ast::Concat(ref mut x) => {
1680 stack.extend(x.asts.drain(..));
1681 }
1682 }
1683 }
1684 }
1685}
1686
1687/// A custom `Drop` impl is used for `ClassSet` such that it uses constant
1688/// stack space but heap space proportional to the depth of the `ClassSet`.
1689impl Drop for ClassSet {
1690 fn drop(&mut self) {
1691 use core::mem;
1692
1693 match *self {
1694 ClassSet::Item(ref item) => match *item {
1695 ClassSetItem::Empty(_)
1696 | ClassSetItem::Literal(_)
1697 | ClassSetItem::Range(_)
1698 | ClassSetItem::Ascii(_)
1699 | ClassSetItem::Unicode(_)
1700 | ClassSetItem::Perl(_) => return,
1701 ClassSetItem::Bracketed(ref x) => {
1702 if x.kind.is_empty() {
1703 return;
1704 }
1705 }
1706 ClassSetItem::Union(ref x) => {
1707 if x.items.is_empty() {
1708 return;
1709 }
1710 }
1711 },
1712 ClassSet::BinaryOp(ref op) => {
1713 if op.lhs.is_empty() && op.rhs.is_empty() {
1714 return;
1715 }
1716 }
1717 }
1718
1719 let empty_span = || Span::splat(Position::new(0, 0, 0));
1720 let empty_set = || ClassSet::Item(ClassSetItem::Empty(empty_span()));
1721 let mut stack = vec![mem::replace(self, empty_set())];
1722 while let Some(mut set) = stack.pop() {
1723 match set {
1724 ClassSet::Item(ref mut item) => match *item {
1725 ClassSetItem::Empty(_)
1726 | ClassSetItem::Literal(_)
1727 | ClassSetItem::Range(_)
1728 | ClassSetItem::Ascii(_)
1729 | ClassSetItem::Unicode(_)
1730 | ClassSetItem::Perl(_) => {}
1731 ClassSetItem::Bracketed(ref mut x) => {
1732 stack.push(mem::replace(&mut x.kind, empty_set()));
1733 }
1734 ClassSetItem::Union(ref mut x) => {
1735 stack.extend(x.items.drain(..).map(ClassSet::Item));
1736 }
1737 },
1738 ClassSet::BinaryOp(ref mut op) => {
1739 stack.push(mem::replace(&mut op.lhs, empty_set()));
1740 stack.push(mem::replace(&mut op.rhs, empty_set()));
1741 }
1742 }
1743 }
1744 }
1745}
1746
1747#[cfg(test)]
1748mod tests {
1749 use super::*;
1750
1751 // We use a thread with an explicit stack size to test that our destructor
1752 // for Ast can handle arbitrarily sized expressions in constant stack
1753 // space. In case we run on a platform without threads (WASM?), we limit
1754 // this test to Windows/Unix.
1755 #[test]
1756 #[cfg(any(unix, windows))]
1757 fn no_stack_overflow_on_drop() {
1758 use std::thread;
1759
1760 let run = || {
1761 let span = || Span::splat(Position::new(0, 0, 0));
1762 let mut ast = Ast::empty(span());
1763 for i in 0..200 {
1764 ast = Ast::group(Group {
1765 span: span(),
1766 kind: GroupKind::CaptureIndex(i),
1767 ast: Box::new(ast),
1768 });
1769 }
1770 assert!(!ast.is_empty());
1771 };
1772
1773 // We run our test on a thread with a small stack size so we can
1774 // force the issue more easily.
1775 //
1776 // NOTE(2023-03-21): It turns out that some platforms (like FreeBSD)
1777 // will just barf with very small stack sizes. So we bump this up a bit
1778 // to give more room to breath. When I did this, I confirmed that if
1779 // I remove the custom `Drop` impl for `Ast`, then this test does
1780 // indeed still fail with a stack overflow. (At the time of writing, I
1781 // had to bump it all the way up to 32K before the test would pass even
1782 // without the custom `Drop` impl. So 16K seems like a safe number
1783 // here.)
1784 //
1785 // See: https://github.com/rust-lang/regex/issues/967
1786 thread::Builder::new()
1787 .stack_size(16 << 10)
1788 .spawn(run)
1789 .unwrap()
1790 .join()
1791 .unwrap();
1792 }
1793
1794 // This tests that our `Ast` has a reasonable size. This isn't a hard rule
1795 // and it can be increased if given a good enough reason. But this test
1796 // exists because the size of `Ast` was at one point over 200 bytes on a
1797 // 64-bit target. Wow.
1798 #[test]
1799 fn ast_size() {
1800 let max = 2 * core::mem::size_of::<usize>();
1801 let size = core::mem::size_of::<Ast>();
1802 assert!(
1803 size <= max,
1804 "Ast size of {} bytes is bigger than suggested max {}",
1805 size,
1806 max
1807 );
1808 }
1809}
1810