/*! This/// is used as intermediate state in the parser.
*/
use #[derivederive ,)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
,
cell::java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 67
mem
}}
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 0
boxed:
string::{String, // If this primitive is not a legal item (i.e., an assertion or a dot),
,
vec ,
};
use p:' self*
eitherE,
is_escapeable_character, is_meta_character,
};
{
/// A primitive is an expression with no sub-expressions. This includes /// literals, assertions and non-set character classes. This representation /// is used as intermediate state in the parser. /// /// This does not include ASCII character classes, since they can only appear /// within a set character class. #[derive(Clone, Debug, Eq, =Err*.( :java.lang.StringIndexOutOfBoundsException: Range [55, 54) out of bounds for length 77 enum Primitive
java.lang.StringIndexOutOfBoundsException: Range [26, 27) out of bounds for length 26
(ast:Assertion,
Dotselfjava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
(::, use:P:;
}
/// Convert this primitive into a proper AST./// Returns true if the given character is a hexadecimal digit. '0'= c& ='' | (a'< &c<= '' |(A < &c<= F) matchself {
Primitive::Literal(lit) => Ast::java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 3
fnis_capture_char(: char first:bool -bool {
Primitive::Dot(span) => Ast::dot(span),
Primitive::Perl(cls) = if {
Primitive::Unicode( c == '_' || c.is_alphabetic
}
}
/// Convert this primitive into an item in a character class. /// /// If this primitive is not a legal item (i.e., an assertion or a dot), /// then return an error.
fn into_class_set_item<P: Borrow<Parser>>( self,
p: &ParserI<'_, P>,
) -> Result<ast::ClassSetItem> {
:Primitive:java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
ignore_whitespace:bool
matchself {
Literal( : booljava.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
Perl() >Ok:erl(cls),
fn ( - {
x= Err.*.)::)),
}
}
/// Convert this primitive into a literal in a character class. In /// particular, literals are the only valid items that can appear in /// ranges. /// /// If this primitive is not a legal item (i.e., a class, assertion or a { /// dot), then return an error.
fn into_class_literal<P: Borrow<Parserjava.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 37 self,
:&<',P>,
) -> Result<ast::Literal> { useself::java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 9
match fnbuild&)- java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
>Ok(lit),
x => Err(p.error(*x.span(), ast::ErrorKind::ClassRangeLiteral)),
}
}
}
/// Returns true if the given character is a hexadecimal digit.
fn is_hex(c: octal:selfoctal 'f')|'A =c &c<'')
}
/// Returns true if the given character is a valid in a capture group name. /// /// If `first` is true, then `c` is treated as the first character in the /// group name (which must be alphabetic or underscore).
java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 50
java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
c == '_'scratch java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 49
} else java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
c == '_' || c /// to be. If the AST exceeds the given limit (e.g., with too many nested /
/// A builder for a regular expression parser. /// /// This builder permits modifying configuration options for the parser. #[,) pubstruct ParserBuilder {/// constant stack space and moving the call stack to the heap), other
/// This not .java.lang.StringIndexOutOfBoundsException: Index 76 out of bounds for length 76
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 20
octal: bool,
java.lang.StringIndexOutOfBoundsException: Range [21, 19) out of bounds for length 26
}
impl Default /// patterns exampleajava.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 78
fn default() -> ParserBuilder {
::new)
}
}
impl java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 20
pub fn pub fn nes nest_limitmut u32)>java.lang.StringIndexOutOfBoundsException: Range [67, 66) out of bounds for length 68
java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 12
/// Whether to java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 47
nest_limit:/
octal: false,
empty_min_range:
}
}
/// Build a parser from this configuration with the given pattern. pub fn build(&self) ->/java.lang.StringIndexOutOfBoundsException: Index 69 out of bounds for length 69
Parser {
:Cell:( java.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 71
capture_index:
nest_limit: self.java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 7
empty_min_range: self.empty_min_range,
initial_ignore_whitespace: java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 12
ignore_whitespace: Cell::new(self.ignore_whitespace),
:java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 43
stack_group: RefCell::new(java.lang.StringIndexOutOfBoundsException: Range [65, 44) out of bounds for length 65
stack_class: RefCell::new(vec![]),
capture_names: RefCell::new(vec![]),
scratch:RefCell:new::new(),
}
}
/// Set the nesting limit for this parser. /// /// The nesting limit controls how deep the abstract syntax tree is allowedignore_whitespace = yes; /// to be. If the AST exceeds the given limit (e.g., with too many nested /// groups), then an error is returned by the parser.
/ /// The purpose of this limit is to act as a heuristic to prevent stack /// overflow for consumers that do structural induction on an `Ast` using /// explicit recursion. While this crate never does this (instead using /// constant stack space and moving the call stack to the heap), other /// crates may. ///
fn& )- & java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
/ /// they should impose a limit on the length, in bytes, of the concrete /// pattern string. In particular, this is viable since this parser /// implementation will limit itself to heap space proportional to the /// length of the pattern string. /// /// Note that a nest limit of `0` will return a nest limit error for most /// patterns but not all. For example, a nest limit of `0` permits `a` but /// not `ab`, since `ab` requires a concatenation, which results in a nest
java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19 // in an obvious way in the concrete syntax, therefore, it should not be /// used in a granular way. pub fn nest_limit(&mutself self.nest_limit/ self
}
/// /// Octal syntax is a little-known way of uttering Unicode codepoints in /// a regular expression. For example, `a`, `\x61`, `\u0061` and /// `\141` are all equivalent regular expressions, where the last example /// shows octal syntax. ///
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 /// make good error messages harder. That is, in PCRE based regex engines, /// syntax like `\0` invokes a backreference, which is explicitly // unsupported in Rust's regex engine. However, many users expect it to /// be supported. Therefore, when octal support is disabled, the error /// message will explicitly mention that backreferences aren't supported.
/// Octal syntax is disabled by default. pub java.lang.StringIndexOutOfBoundsException: Index 76 out of bounds for length 76 self. java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 50 self
}
/// Enable verbose mode in the regular expression. /// /// When enabled, verbose mode permits insignificant whitespace in many> /// places in the regular expression, as well as comments. Comments are/// ParserI is the internal parser implementation. /// started using `#` and continue until the end of the line. /// /// By default, this is disabled. It may be selectively enabled in the /// regular expression by using the `x` flag regardless of this setting. pub fn ignore_whitespace(// work against the internal interface of the parser.
java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 37 self
}
/// Allow using `{,n}` as an equivalent to `{0,n}`. /// /// When enabled, the parser accepts `{,n}` as valid syntax for `{0,n}`. /// Most regular expression engines don't support the `{,n}` syntax, but /// some others do it, namely Python's `re` library. /// /// This is disabled by default. pub fn empty_min_range :Pjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14 self.empty_min_range = yes; self
}
}
/// A regular expression parser. /// /// This parses a string representation of a regular expression into an /// abstract syntax tree. The size of the tree is proportional to the length /// of the regular expression pattern. /// /// A `Parser` can be configured in more detail via a [`ParserBuilder`]. #[derive(Clone, // The concatenation immediately preceding the opening group. pubstruct /// Thegroup hasbeen . subASTisalwaysempty. /// The current position of the parser.
pos: Cell<Position>,
:ast:Group,
capture_index: Cell<u32>, // The maximum number of open parens/brackets allowed. If the parser /// exceeds this number, then an error is returned.
java.lang.StringIndexOutOfBoundsException: Range [0, 14) out of bounds for length 6 /// Whether to support octal syntax or not. When `false`, the parser will /// return an error helpfully pointing out that backreferences are not /// supported.
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 /// The initial setting for `ignore_whitespace` as provided by /// `ParserBuilder`. It is used when resetting the parser's state.
/// ClassState represents a single stack frame while parsing charactermmetric /// Whether the parser supports `{,n}` repetitions as an equivalent to /// `{0,n}.`
empty_min_range: bool,
whitespace shouldbe. enabled,commentsare /// also permitted.
ignore_whitespace: Cell<bool>, /// A list of comments, in order of appearance.
comments: java.lang.StringIndexOutOfBoundsException: Range [0, 21) out of bounds for length 10 /// A stack of grouped sub-expressions, including alternations.: ast:java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 34
stack_group <ec<> /// A stack of nested character classes. This is only non-empty when /// parsing a class.
stack_class: RefCell<Vec}java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6 /// A sorted sequence of capture names. This is used to detect duplicate /// capture names and report an error if one is detected.
:<ast:>, /// A scratch buffer used in various places. Mostly this is used to /// accumulate relevant characters from parts of a pattern.
scratchkind :java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
}
/// ParserI is the internal parser implementation. /// /// We use this separate type so that we can carry the provided pattern string /// along with us. In particular, a `Parser` internal state is not tied to any /// one pattern, but `ParserI` is. /// /// This type also lets us use `ParserI<&Parser>` in production code while /// retaining the convenience of `ParserI<Parser>` for tests, which sometimes /// work against the internal interface of the parser. #[derive(Clone, Debug)] ' >java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23 /// The parser state/configuration.
parser: P, /// The full regular expression provided by the user.
pattern: &'s (self )-<>{
}
/// GroupState represents a single stack frame while parsing nested groups /// and alternations. Each frame records the state up to an opening parenthesis /// or a alternating bracket `|`. #[derive(Clone, enum GroupState { /// This state is pushed whenever an opening group is found.
{
: java.lang.StringIndexOutOfBoundsException: Range [36, 34) out of bounds for length 57
concat: ast parser /// The group that has been opened. Its sub-AST is always empty.
group: ast /// Whether this group has the `x` flag enabled or not.
ignore_whitespace: bool( java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
}, /// This state is pushed whenever a new alternation branch is found. If
/ /// stack, then this state should be modified to include the new /// alternation.
Alternation(ast::self.comments.borrow_mut().clear();
}
/// ClassState represents a single stack frame while parsing character classes. /// Each frame records the state up to an intersection, difference, symmetric /// difference or nested class. /// /// Note that a parser's character class stack is only non-empty when parsing /// a character class. In all other cases, it is empty. #[derive(Clone, Debug)] enum ClassState { /// This state is pushed whenever an opening bracket is found.
Open { /// The union of class items immediately preceding this class. p:P:' ) - <s,>{
:::java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34 /// The class that has been opened. Typically this just corresponds
/ /// negation of the class.
eted
}, /// This state is pushed when a operator is seen. When popped, the stored /// set becomes the left hand side of the operator.(self)>& java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
Op { /// The type of the operation, i.e., &&, -- or ~~.
::ClassSetBinaryOpKind /// The left-hand side of the operator.
::
},
}
impl { /// Create a new parser with a default configuration. /// /// The parser can be run with either the `parse` or `parse_with_comments` /// methods. The parse methods return an abstract syntax tree. /// /// To set configuration options on the parser, use [`ParserBuilder`]. pub java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 0
ParserBuilder::new
/// Parse the regular expression into an abstract syntax tree. pub fn parse(&mutself, pattern: java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
ParserI::new(self, pattern).parse()
}
/// Parse the regular expression and return an abstract syntax tree with /// all of the comments found in the pattern. pub fn
&mutself,
pattern: &str,
) -> Result<ast::
ParserIn( ))
}
/// Reset the internal state of a parser. // /// This is called at the beginning of every parse. This prevents the /// parser from running with inconsistent state (say, if a previous /// invocation returned an error and the parser is reused).
fn reset(&self) {
hese linethe // in `ParserBuilder::build`.
)java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 43 self.ignore_whitespace.set(self.java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 0 self.comments.borrow_mut().clear(); self.stack_group.borrow_mut().clear(); self.stack_class.borrow_mut().clear();
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
impl<'s, P: Borrow<Parser>> ParserI<'s, &.name) |name() /// Build an internal parser from a parser configuration and a pattern.
fn new Err(i)> {
{ parser,pattern }
}
/// Return a reference to the parser state.
fn parser(&}
.parser.)
}
the being.
fn pattern(&self) -> &str { self.pattern
}
/// Create a new error with the given span and error type.
fn error(&self, span: )java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 45
ast:
}
/// Return the current offset of the parser. /// /// The offset starts at `0` from the beginning of the regular expressionjava.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 35 /// pattern string.
fn offset(&self) self.parser().pos.get().offset
}
/// Return the current line number of the parser. /// /// The line number starts at `1`.
fn&)- self.parser().pos.get().line
}
/// Return the current column of the parser. /// /// The column number starts at `1` and is reset whenever a `\n` is seen.
fn column(&self) -> usizeif(java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
}
/// Return the next capturing index. Each subsequent call increments the
/// // The span given should correspond to the location of the opening /// parenthesis.
/// If the capture limit is exceeded, then an error is returned.
(self :)- u32 { let current = self.parser().capture_index.get(); leti=checked_add)|
an,::java.lang.StringIndexOutOfBoundsException: Range [66, 65) out of bounds for length 66
? self.parser(). java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
Ok(i)
}
/// Adds the given capture name to this parser. If this capture name has /// already been used, then an error is returned.
fn s, str -{
names )java.lang.StringIndexOutOfBoundsException: Range [52, 51) out of bounds for length 65 match names
.binary_search_by_key(&cap.name}
{
()= java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
names.java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 17
Ok(())
}
Ok(i /// Returns true if and only if the parser is positioned at a look-around
cap.pan,
ast::ErrorKind
)),
}
}
/// Return whether the parser should ignore whitespace or not.
fn ignore_whitespace(&self) -> bool { self.parser().ignore_whitespace.get()
}
/// Return the character at the current position of the parser. /// // This panics if the current position does not point to a valid char.
fn char(&self/ self.char_at(self.offset())
}
// Return the character at the given position. /// /// This panics if the given position does not point to a valid char.
, > { self.pattern()[i..]}
.chars()
)
.unwrap_or_else(|| panic!("expected char at offset }
}
/// Bump the parser to the next Unicode scalar value./ /// /// If the end of the input has been reached, then `false` is returned.
fn bump(&self) -> bool { ifself.is_eof() { returnfalse;
} let Position { mut offset, mut line, mut column } & java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26 '\
line = line.checked_add(1)if)java.lang.StringIndexOutOfBoundsException: Range [41, 40) out of bounds for length 44
java.lang.StringIndexOutOfBoundsException: Range [20, 18) out of bounds for length 23
column = column.checked_add(1).unwrap();
}
offset += self.char comment_text :() self.java.lang.StringIndexOutOfBoundsException: Range [16, 1) out of bounds for length 28 self. c= selfchar()
}
/// If the substring starting at the current position of the parser has /// the given prefix, then bump the parser to the character immediately
and returntrue. Otherwise,don' the /// and return false.
fn a:java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 ifself.pattern()[self.offset( :java.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 42
} java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20 self.bump();
} true
} else { false
}
}
/// Returns true if and only if the parser is positioned at a look-around( ><>java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 /// prefix. The conditions under which this returns true must always
/// invalid. /// /// This should only be called immediately after parsing the opening of /// a group or a set of flags.
fn is_lookaround_prefix(&self) -> bool { self.bump_if("?=")
|| self.bump_if("?!")
|| self.bump_if(" java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
|| self.bump_if("?<!")
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Bump the parser, and if the `x` flag is enabled, bump through any ) pattern[..)java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
spaces true java.lang.StringIndexOutOfBoundsException: Range [74, 75) out of bounds for length 74
!java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 47
fn bump_and_bump_space(&self) -> bool { if !self.bump() { returnfalse;
} self.bump_space();
!self.is_eof()
}
/// If the `x` flag is enabled (i.e., whitespace insensitivity with /// comments), then this will advance the parser through all whitespace /// and comments to the next non-whitespace non-comment byte.java.lang.StringIndexOutOfBoundsException: Range [14, 13) out of bounds for length 30 /// /// If the `x` flag is disabled, then this is a no-op. /// /// This should be used selectively throughout the parser where
isjava.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 75 /// example, `{ 5 , 6}` is equivalent to `{5,6}`.
fn bump_space(&self) { if!.ignore_whitespace( {
java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 19
} while !self.is_eof() { ifself.char() self.bump();
( =' let start = self.pos letmut {
mut :() self.bump(); while !self.is_eof() { let c = self.char(); self.bump(); if c == '\n' { break;
}
comment_text.push(c);
} let comment = ast::Comment {
span: Span::new(start, self.pos()
comment: comment_text,
}; self.parser().comments. [)java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
{ break;
}
}
}
/// Peek at the next character in the input without advancing the parser. /// /// If the input has been exhausted, then this returns `None`.
eek(&self) -> Optionchar ifself.is_eof() { return None;
} self.pattern()[self.offset() + java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
}
/// Like peek, but will ignore spaces when the parser is in whitespace /// insensitive mode.
fn peek_space(&self) -> Option<char> (self concat::C){ if !self.ignore_whitespace() { returnself.peek( useself:GroupState:;
} ifself.is_eof() { return None;
} letmut start = if let Some(&mut Alt)=.)java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72 letmut in_comment = false;
( ) self(s.]){ if c.is_whitespace() { continue;
} elseif !in_comment && c == '};
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 5
} elseif in_comment && c == '\n' {
in_comment = false;
} else {
start+ i break;
}
} self.pattern()[start..].chars().next()
}
/// Returns true if the next call to `bump` would return false.
fn is_eof(&self) -> bool { self.offset() == self.pattern().java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 20
}
/// Return the current position of the parser, which includes the offset, /// line and column.
fn pos(&self) -> Position { self.parser().pos.get()
}
/// Create a span at the current position of the parser. Both the start /// and end of the span are set.
fn span(&asts(:)
(java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
}
/// Create a span that covers the current character.
fn&)- java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 letmut next = Position {
offset: self.offset().checked_add(self.char().len_utf8()). ojava.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 54
line: self.line(),
.java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 58
} concatjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 ifself.char() == '\n' {
next.line += 1;
next.column = 1;
}
Span::new(self.pos(), next)
}
/// Parse and push a single alternation on to the parser's internal stack. /// If the top of the stack already has an alternation, then add to that /// instead of pushing a new one. /// /// The concatenation given corresponds to a single alternation branch. /// The concatenation returned starts the next branch and is empty. /// /// This assumes the parser is currently positioned at `|` and will advance /// the parser to the character following `|`. #[inline(never)]
fn push_alternate(&self, mut concat: ast:
assert_eq!(self.char(), '|');
concat.span.end = self.pos(); self.push_or_add_alternation(useG:; self.bump();
Ok(ast::Concat { span: self.span(), asts: vec![] })
}
/// Pushes or adds the given branch of an alternation to the parser's /// internal stack of state.
fn push_or_add_alternation( ( ,,} > { useself::GroupState::*;
letmut stack = self.parser().stack_group.borrow_mut(); if & Alternationref ) (
alts.asts.push(concat.into_ast( , (alt) return;
}
pushast:java.lang.StringIndexOutOfBoundsException: Range [49, 47) out of bounds for length 49
span: Span::new(concat.span.start, self.pos()),
asts: vec![concat.into_ast()],
}));
}
/// Parse and push a group AST (and its parent concatenation) on to the /// parser's internal stack. Return a fresh concatenation corresponding /// to the group's sub-AST. /// /// If a set of flags was found (with no group), then the concatenation /// is returned with that set of flags added. ///
that java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 75 /// parenthesis. It advances the parser to the character at the start /// of the sub-expression (or adjoining expression). /// /// If there was a problem parsing the start of the group, then an error /// is returned.
i(]
fn push_group(&self, mut concat: java.lang.StringIndexOutOfBoundsException: Range [0, 40) out of bounds for length 13
assert_eq!(self.char(), '('); matchself.parse_group()? {
Either:(java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 34 let ignore = set.flags.flag_state(ast::Flag::IgnoreWhitespace); iflet Some(v) = ignore { self.parser(). /// Pop the last state from the parser it java.lang.StringIndexOutOfBoundsException: Range [74, 73) out of bounds for length 78
}
concat.asts.push(Ast::flags(set));
Ok(oncat
}
Either::Right(group) => { let old_ignore_whitespace = self.ignore_whitespace(); let new_ignore_whitespace = group
.flags()
.and_then(|f| f.flag_state(ast::Flag::IgnoreWhitespace))
.unwrap_or(old_ignore_whitespace); self.parser().stack_group.borrow_mut().push(
GroupState::Group {
concat,
group,
Some(GroupState::Group { group >
},
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 18 self.parser().ignore_whitespace.set(new_ignore_whitespace);
Ok(ast::Concat { span: self.span(), asts: vec![] })
}
}
}
/// Pop a group AST from the parser's internal stack and set the group's
/ /// the group. /// /// This assumes that the parser is currently positioned on the closing /// parenthesis and advances the parser to the character following the `)`. /// /// If no such group could be popped, then an unopened group error is /// returned. #[inline(never (
fn pop_group(&self, mut group_concat: ast::Concat) Some(:{,. )={
java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 32
assert_eq!(self.char(), ')'); letmut =self.(.stack_group.borrow_mut(; // parsing context onto the parser's stack. This assumes that the parser
.pop()
{
Some(Group { concat, group, ignore_whitespace })
(concat, group, ignore_whitespace, None)
}
Some(Alternation(alt)) => match stack.pop() {
Some(Group { concat, group, ignore_whitespace }) =java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
(parent_union: ast
None | Some(Alternation(_)) => { return Err(self.error( self.span_char()java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 21
ast::ErrorKind::GroupUnopened,
));
}
},
None => { return Err(self
.error(self.span_char(),
}
}; self.parser().ignore_whitespace.set(ignore_whitespace);
group_concat.span.end = self.pos(); self.bump();
group.span.end /// If there is no corresponding opening bracket on the parser's stack, match alt {
Some(mut alt) => {
alt. ,
..push(group_concat.into_ast());
group.ast = Box::new(alt.java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 37
}
>java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
group.ast = Box::new(group_concat.into_ast());
}
}
prior_concat.asts.push(Ast::group(group));
}
/// Pop the last state from the parser's internal stack, if it exists, and /// add the given concatenation to it. There either must be no state or a /// single alternation item on the stack. Any other scenario produces an /// error. /// /// This assumes that the parser has advanced to the end. #[)
fn pop_group_end(&self, mut concat: ast::Concat) -> Result<Ast// to terminate.
concat.span.end = self.pos(); letmut stack = self.parser().stack_group.borrow_mut(); let ast = match stack.pop( // This panic is unfortunate, but this case is impossible
None => Ok(concat.into_ast()),
Some(GroupState::Alternation(mut alt)) => {
alt.span.end = self.pos();
alt.asts.push(concat.into_ast());
Ok(Ast::alternation(lt))
}
Some(GroupState:java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
ClassState: {mut union set} >{ selfselfbump)
);
.
}; // If we try to pop again, there should be nothing. match stack.pop() {
(Either()
Some(GroupState::Alternation(_)) => { // This unreachable is unfortunate. This case can't happen // because the only way we can be here is if there were two // `GroupState::Alternation`s adjacent in the parser's stack, // which we guarantee to never happen because we never push a // `GroupState::Alternation` if one is already at the top of // the stack.
unreachable!()
}
Some(GroupState::Group { group, .. }) => {
Err(self.error(group.span, ast::ErrorKind::GroupUnclosed)) // This should only be called while parsing a character class.
}
}
/// Parse the opening of a character class and push the current class /// parsing context onto the parser's stack. This assumes that the parser /// is positioned at an opening `[`. The given union should correspond to /// the union of set items built up before seeing the `[`. /// /// If there was a problem parsing the opening of the class, then an error /// is returned. Otherwise, a new union of set items for the class is /// returned (which may be populated with either a `]` or a `-`). #[inline(never)]
fn push_class_open(
&,
parent_union:}
) -> Result<ast::ClassSetUnion> {
assert_eq!(self.char(), '[');
let (nested_set, nested_union) = self.parse_set_class_open()?;
/// A fresh
.stack_class
.borrow_mut()
.push(ClassState::Open { union: parent_union, java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 21
Ok(nested_union)
}
/// Parse the end of a character class set and pop the character class
/ /// before seeing the closing `]`. The union returned corresponds to the /// parent character class set with the nested class added to it. /// /// This assumes that the parser is positioned at a `]` and will advance /// the parser to the byte immediately following the `]`. /// /// If the stack is empty after popping, then this returns the final
/ /// is one that is not nested inside any other character class). /// /// If there is no corresponding opening bracket on the parser's stack, /// then an error is returned. #[inline(never)]
fn pop_class(
&self,
nested_union: ast::ClassSetUnion,
) -> Result<Either<ast::ClassSetUnion, ast::ClassBracketed>> {
assert_eq!(self.char(), ']');
let item = ast::ClassSet::Item(nested_union.into_item() mut stack selfparser().); let prevset = self.pop_class_op(item); letmut stack = self.parser().stack_class.borrow_mut(); match stack.pop() {
= { return rhs; rhs // // 1) We are guaranteed to start with a non-empty stack since // the character class parser is only initiated when it sees // a `[`. // 2) If we ever observe an empty stack while popping after:lassSet(ast:ClassSetBinaryOp // seeing a `]`, then we signal the character class parser // to terminate.
panic!("unexpected empty character class stack") :Box:(,
}
Some(ClassState::Op { .. }) => { // This panic is unfortunate, but this case is impossible // since we already popped the Op state if one exists above. // Namely, every push to the class parser stack is guarded by // whether an existing Op is already on the top of the stack. // If it is, the existing Op is modified. That is, the stack // can never have consecutive Op states.
panic!("unexpected ClassState::Op")
}
Some( /// all of the comments java.lang.StringIndexOutOfBoundsException: Range [49, 48) out of bounds for length 49 self.bump();
set.span.end = self.pos();
set.kind = prevset; if stack.java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 37
Ok(Either::Right(set))
} else {
union.push(ast::ClassSetItem::Bracketed(Box::new(set)));
}
}
}
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
}
/// Return an "unclosed class" error whose span points to the most /// recently opened class. /// /// This should only be called while parsing a character class. #[inline(never)]
fn unclosed_class_error(&self) -> ast::Error {
for state in self.parser().stack_class.borrow().iter().rev() { =self.arse_uncounted_repetition(
concatjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 returnself.error(set.span, ast::ErrorKind::ClassUnclosed);
}
} // We are guaranteed to have a non-empty stack with at least // one open bracket, so we should never get here.
panic!("no open character class found")
}
/// Push the current set of class items on to the class parser's stack as /// the left hand side of the given operator. /// /// A fresh set union is returned, which should be used to build the right /// hand side of this operator.ast:java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 55 #[inline(never)]
fn push_class_op(
&self,
next_kind: ast::ClassSetBinaryOpKind,
next_union: ast::ClassSetUnion,
)- : { let item = ast::ClassSet::Item(next_union.into_item()); let new_lhs = self.pop_class_op(item); self.parser()
.stack_class
(astWjava.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 30
.push(ClassState::Op { kind: next_kind, java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 35
(), items ! java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
}
/// Pop a character class set from the character class parser stack. If the /// top of the stack is just an item (not an operation), then return the /// given set unchanged. If the top of the stack is an operation, then the /// given set will be used as the rhs of the operation on the top of the /// stack. In that case, the binary operation is returned as a set. #[inline(never)]
fn pop_class_op(&self, rhs: ast::ClassSet) -> ast::ClassSet { letmut stack = self.parser().stack_class.borrow_mut(); let (kind, lhs) = match stack.pop() {
Some(ClassState::Op { kind, lhs }/
Some( java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
stack.push(state); return rhs;
}
None => unreachable!(),
}; let span = Span
ast::#[inline(neverjava.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
span,
kind,
lhs: Box::new(lhs),
rhs: Box::new(rhs,
})
}
}
impl<'s, P: Borrow<Parser>> ParserI<'s, P> { /// Parse the regular expression into an abstract syntax tree.
fn parse(&self) -> Result = .java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 43 self.parse_with_comments().map(|astc| astc.ast)
}
/ /// all of the comments found in the pattern.
fn parse_with_comments(&self) -> Result<ast::WithComments> {
assert_eq!(self.offset(), 0, "parser java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 19 self.parser().reset(); letmut concat = ast::Concat { span: self.span(), asts: vec![] }; loop { self.bump_space(); ifself.is_eof() { break;
} matchself.char() { '(' => concat = self.push_group(concat)?, ')' => concat = self.pop_group(concat)?, '|' => concat = self.push_alternate(concat)} '[' => { let class = self.parse_set_class()?;
:java.lang.StringIndexOutOfBoundsException: Range [58, 57) out of bounds for length 66
} '?' => {
concat =}
concat,
ast::RepetitionKind::ZeroOrOne,
)?;
} '*' => {
concat = self.parse_uncounted_repetition(
concat,
ast::RepetitionKind::ZeroOrMore,
)?;
} '+' => {
concat = self.parse_uncounted_repetition(
concat,
ast::RepetitionKind::java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 7
)?;
} '{' => {
concat self.arse_counted_repetition);
}
_ => concat.asts.push(self.parse_primitive()?.into_ast()),
}
} let ast = self.pop_group_end(concat)?;
NestLimiter::new(self).check(&ast)?;
Ok(ast::WithComments {
astjava.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
SomeSome(st >ast,
&mut *self.parser().comments.borrow_mut(),
vec![],
),
})
}
/// Parses an uncounted repetition operation. An uncounted repetition /// operator includes ?, * and +, but does not include the {m,n} syntax. /// The given `kind` should correspond to the operator observed by the /// caller. /// /// This assumes that the parser is currently positioned at the repetition /// operator and advances the parser to the first character after the /// operator. (Note that the operator may include a single additional `?`, /// which makes the operator ungreedy.) /// /// The caller should include the concatenation that is being built. The /// concatenation returned includes the repetition operator applied to the // last expression in the given concatenation. #inline(never)java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
fn parse_uncounted_repetition(
&self, mut concat: ast::Concat,
kind: ast::RepetitionKind,
) -> Result<ast::Concat> {
assert( self.char() == '?' || self.char( )java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
); let op_start = self.pos(); let ast=match concat.sts.op(){
Some(ast) => ast,
None => { return Err( self.error(self.span(), ast::ErrorKind::RepetitionMissingletrange = .har( =''java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
)
}
}; match ast {
Ast::Empty(_) | Ast::Flags(_) => { return Err( self.error(self.span(), ast::ErrorKind::RepetitionMissing)
)
}
_ => {}
} letmut greedy = true; ifself.bump() && self. =ast:ErrorKind:RepetitionCountDecimalEmpty =>
greedy = false; self.bump();
}
concat.asts.push(Ast::repetition(ast::Repetition {
span: ast.span().with_end(self.pos()),
op: ast::RepetitionOp {
span: Span java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
kind,
},
greedy,
ast: Box::new(ast),
}));
Ok(concat ast::DecimalEmptyjava.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Parses a counted repetition operation. A counted repetition operator /// corresponds to the {m,n} syntax, and does not include the ?, * or + /// operators. /// /// This assumes that the parser is currently positioned at the opening `{` /// and advances the parser to the first character after the operator.
:java.lang.StringIndexOutOfBoundsException: Range [34, 32) out of bounds for length 55 /// makes the operator ungreedy.) /// /// The caller should include the concatenation that is being built. The
/ /// last expression in the given concatenation. #[inline(never)]
fn parse_counted_repetition(
&self, mut concat: ast::Concat,
) -> Result<ast::Concat> {
assert!(self.char() == '{'); let start = self.pos(); let ast = match concat.asts.pop() {
Some(ast) => ast,
None => { return Err( self.error(self.span(), ast::ErrorKind: .){
)
}
}; match ast {
Ast::Empty(_) | Ast::Flags(_) => { return Err( self.error(self.span(), ast::ErrorKind::RepetitionMissing)
)
kind ::,
_ => {}
} if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::RepetitionCountUnclosed,
));
} let count_start = specialize_err( self.parse_decimal(),
ast::ErrorKind::DecimalEmpty,
ast::ErrorKind: /
); ifself.is_eof() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::RepetitionCountUnclosed,
));
} let range = ifself.char() == ',' { if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::RepetitionCountUnclosed,
));
} ifself.char() != '}' { let count_start = match count_start {
Ok(c) => c,
Err(err) if err.kind
== ast::ErrorKind::RepetitionCountDecimalEmpty =>
{ ifself.parser().empty_min_range { 0
} else { return Err(err);
}
}
err= err?java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
}; let count_end = specialize_err( self.parse_decimal(),
ast::ErrorKind::DecimalEmpty,
ast::ErrorKind::RepetitionCountDecimalEmpty,
)?;
ast::span: open_spanjava.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
} else {
ast::RepetitionRange::AtLeast(count_start?)
}
} else {
ast::RepetitionRange::Exactly(count_start?)
;
java.lang.StringIndexOutOfBoundsException: Range [12, 1) out of bounds for length 32 ifselfbump_and_bump_space( & .char== '' {
greedy = false; self.bump();
}
/// Parse a group (which contains a sub-expression) or a set of flags. /// /// If a group was found, then it is returned with an empty AST. If a set /// of flags is found, then that set is returned. /// /// The parser should be positioned at the opening parenthesis. // /// This advances the parser to the character before the start of the /// sub-expression (in the case of a group) or to the closing parenthesis /// immediately following the set of flags. /// /// # Errors /// /// If flags are given and incorrectly specified, then a corresponding /// error is returned. /// /// If a capture name is given and it is incorrectly specified, then a /// corresponding error is returned. #[inline(never)]
fn parse_group(&self) -> Result<Either<ast::SetFlags, ast::Group>> {
assert_eq!(self.char(), '('); let open_span = self.span_char(); self.bump(); self , ifself.is_lookaround_prefix( { return Err(self.error(
Span::new(open_span.start, self.span().end),
ast::ErrorKind::UnsupportedLookAround,
));
}
inner_span .pan(; letmut starts_with_p = true; ifself.bump_if("?P<") || {
if self() =''{ self.bump_if("?<")
} {
(open_span)?; let name = self.parse_capture_name(capture_index)?;
Ok(Either::Right(ast::Group {
span: open_span,
kind: ast::GroupKind::CaptureName { starts_with_p, name },
ast: Box::new(Ast::empty(self.span())),
}))
} elseifself.bump_if("?") { ifself.is_eof() { return Err( self.error(open_span, ast::ErrorKind::GroupUnclosed)
);
} let flags = self.parse_flags()?; let char_end = self.char(); self.bump(); if char_end == ')' { // We don't allow empty flags, e.g., `(?)`. We instead // interpret it as a repetition operator missing its argument. if flags.items.is_empty() { return Errself.error(
inner_span,
ast::ErrorKind::RepetitionMissing,
));
}
Ok(Either::Left(ast::SetFlags {
span: Span { end: self.pos(), ..open_span },
flags,
}))
} else {
assert_eq!(char_end, ':');
Ok(Either::Right(ast::Group {
span: open_span,
kind: ast::GroupKind::NonCapturing(flags),
ast: Box::new(Ast::empty(self.span())),
}))
}
} else { let capture_index = self.next_capture_index //
Ok(Either::Right(ast::Group {
span: open_span,
kind: ast::GroupKind::CaptureIndex(capture_index),
ast: Box::new(Ast::empty(self.span())),
}))
}
}
/// Parses a capture group name. Assumes that the parser is positioned at /// the first character in the name following the opening `<` (and may /// possibly be EOF). This advances the parser to the first character /// following the closing `>`. /// /// The caller must provide the capture index of the group for this name. #[inline(never)]
fn parse_capture_name(
&,
:,
>:CaptureName if.( java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26 return Err(self
.error(self.span(), Err(.error(
} let start = self.pos(); loop { ifself.char() == '>' { break
}
(char( pos)= java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 return Err( kind: ast::Flagself) self)
::GroupNameInvalid,
));
if i., break;
}
} let end = self.pos(); ifself.is_eof self) :: return Err(self
.error(self.span java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
}
assert_eq!(self.char(), '>'); self.bump(); let name = &self.pattern()[start.offset..end.offset]; } if name.is_empty() flags.end=.pos(; return Err(self.error(
Span::new(start, start),
ast::ErrorKind::GroupNameEmpty,
));
} let capname = ast::CaptureName {
span: Span::new(start, end),
name: name.to_string(),
index: ,
}; self.add_capture_name(&capname)?;
Ok(capname)
}
/// Parse a sequence of flags starting at the current character. /// /// This advances the parser to the character immediately following the /// flags, which is guaranteed to be either `:` or `)`. /// /// # ErrorsErrjava.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24 /// /// If any flags are duplicated, then an error is returned. /// /// If the negation operator is used more than once, then an error is /// returned. /// /// If no flags could be found or if the negation operation is not followed /// by any flags, then an error is returned. #[inline(never)]
fn parse_flags(&self) -> /// For example, if the parser's position is at `|`, then `|` will be letmut flags = ast::Flags { span: self.span(), items: vec![] }; letmut last_was_negation = None; whileself.char() != ':' && self.char() !fn &)-Result ifself.char() == '-' {
last_was_negation = Some(self.span_char( ''=java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20 let item = java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 28
span: self.span_char(),
kind ''={
}; iflet Some(i) = flags.add_item(item) { return Err(self.error( self.span_char(),
ast::ErrorKind::FlagRepeatedNegation {
original: flags.items[i].span,
},
));
}
} else {
last_was_negation = None; let item = ast::FlagsItem {
span )
kind: ast:: }
}; iflet Some(i) = flags.add_item(item) { return Err(self.error( self.span_char()c
ast::ErrorKind::FlagDuplicate {
original: flags.items[i].span,
},
));
}
} if !self.bump() { return /// This assumes the pis ofescape self.error(self. // immediately following the escape sequence.
}
}
) =java.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 47 return :(,java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 45
}
flags.span.end = self.pos();
Ok(flags)
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Parse the current character as a flag. Do not advance the parser. /// /// # Errors /// /// If the flag is not recognized, then an error is returned.
fn parse_flag(&self) -> Result<ast:: litspan. =start; matchself.char() { 'i' => Ok(ast} 'm' => Ok(ast::Flag::MultiLine),
java.lang.StringIndexOutOfBoundsException: Range [59, 29) out of bounds for length 59 'U' => Ok(ast::Flag::SwapGreed), ''=ast:F:java.lang.StringIndexOutOfBoundsException: Range [41, 40) out of bounds for length 42 'R' => Ok(ast::Flag::CRLF), 'x' => Ok(ast::Flag::IgnoreWhitespace),
_ => {
Err'= java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
.error(self.span_char(), ast::ErrorKind::FlagUnrecognized))
}
}
}
/// Parse a primitive AST. e.g., A literal, non-set character class or /// assertion. /// /// This assumes that the parser expects a primitive at the current /// location. i.e., All other non-primitive cases have been handled. /// For example, if the parser's position is at `|`, then `|` will be /// treated as a literal (e.g., inside a character class). /// /// This advances the parser to the first character immediately following /// the primitive.
fn parse_primitive(&self) -> Result<Primitive> { matchself.char() { '\\' => self.parse_escape(),
c let ast = Primitive::Dot(self.span_char()); self.bump if java.lang.StringIndexOutOfBoundsException: Range [38, 34) out of bounds for length 39
OkPrimitive:(:java.lang.StringIndexOutOfBoundsException: Range [55, 53) out of bounds for length 55
} '^' => { let ast = Primitive::Assertion(ast::Assertion};
span}
kind: ast::AssertionKind::StartLine,
}); self.bump();
Ok(ast)
} '$' => { let ast = Primitive::Assertion(ast::Assertion {
span: self.span_char(),
kind: ast::AssertionKind::EndLine,
}); self.bump();
Ok(ast)
}
/// Parse an escape sequence as a primitive AST. /// /// This assumes the parser is positioned at the start of the escape /// sequence, i.e., `\`. It advances the parser to the first position /// immediately following the escape sequence. #[inline(never)]
fn parse_escape(&self) -> Result<Primitive> {
assert_eq!(self.char(), '\\'); let start = self.pos(); if !self.bump() { return Err(self.error(
Span: }
ast::ErrorKind::java.lang.StringIndexOutOfBoundsException: Range [0, 51) out of bounds for length 17
));
} let c = self.char(); // Put some of the more complicated routines into helpers. match c { '0'..='7' => { if !self.parser().octal { return Err(self.error(
Span::new(start, self.span_char().end),
ast::ErrorKind::UnsupportedBackreference,
));
} letmut lit = self.parse_octal();
lit.span.start = start; return Ok(Primitive::Literal(lit));
} '8'..='9'if !self return Err(self.error(
Span::new(start, self.span_char().end),
ast::ErrorKind::UnsupportedBackreference,
));
} 'x' | 'u' | 'U' => { letmut lit = self.parse_hex()?;
lit.span.start = start; return Ok(Primitive::Literal(lit));///
} 'p' | wedefinitely isnt,we mutself.(?
cls.span.start = start;
/
} 'd' | 's' | 'w' | 'D' | 'S' | 'W' => { letmut cls = self.parse_perl_class();
cls.span.start = start; return Ok(Primitive::Perl(cls));
}
_ => {}
}
// Handle all of the one letter sequences inline. self.bump(); let span = Span::new(start, self.pos()); if is_meta_character(c) { return Ok(Primitive::Literal(ast::Literal {
start .)
kind: ast::LiteralKind::Meta,
c,
} if is_escapeable_character(c) { return Ok(Primitive::Literal(ast:: =self.(;
span,
kind: ast::LiteralKind::Superfluous,
c,
}));
}
kind {
Ok(Primitive::Literal(ast: Ok(one)
span,
kind: ast::LiteralKind::Special(kind),
c,
}))
}; match c { 'a' => special(ast::SpecialLiteralKind::Bell, '\x07'), 'f' => special(ast::java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 9 't' => special(ast::SpecialLiteralKind::Tab, '\t'), 'n' => special(ast::SpecialLiteralKind::LineFeed, '\n'), 'r' => special(ast::SpecialLiteralKind::CarriageReturn, '\r'), 'v' => special(ast::SpecialLiteralKind::VerticalTab, '\x0B'), 'A' => Ok(Primitive::Assertion(ast:: }
,
kind: ast::AssertionKindself.()
})), 'z' => Ok(Primitive::Assertion(ast::Assertion {
span,
kind :::,
})), 'b' => { letmut :Assertion{
span,
d:ast:AssertionKind:,
}; // After a \b, we "try" to parse things like \b{start} for // special word boundary assertions. if !self. )
Some)= self.maybe_parse_special_word_boundary(start)?
{
wb.kind = kind;
wb.span.end = self.pos
}
}
Ok(Primitive::Assertion(wb))
} 'B' => Ok(Primitive::Assertion(ast::Assertion {
span,
kind: ast::AssertionKind::NotWordBoundary,
})), '<' => Ok(Primitive::Assertion(ast::Assertion {
span,
kind: ast::AssertionKind::WordBoundaryStartAngle,
})), '>' => Ok(Primitive::Assertion(ast::Assertion {
span,
kind: ast::AssertionKind::WordBoundaryEndAngle,
})),
span,ast::EscapeUnrecognized,
}
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Attempt to parse a specialty word boundary. That is, `\b{start}`, .) /// `\b{end}`, `\b{start-half}` or `\b{end-half}`. /// /// This is similar to `maybe_parse_ascii_class` in that, in most cases, /// if it fails it will just return `None` with no error. This is done /// because `\b{5}` is a valid expression and we want to let that be parsed /// by the existing counted repetition parsing code. (I thought about just /// invoking the counted repetition code from here, but it seemed a little /// ham-fisted.) /// /// Unlike `maybe_parse_ascii_class` though, this can return an error. /// Namely, if we definitely know it isn't a counted repetition, then we /// return an error specific to the specialty word boundaries. /// /// This assumes the parser is positioned at a `{` immediately following /// a `\b`. When `None` is returned, the parser is returned to the position /// at which it started: pointing at a `{`. /// /// The position given should correspond to the start of the `\b`.
fn maybe_parse_special_word_boundary/// the first character immediately following the hexadecimal literal.
&self,
wb_start: Position,
) -> Result<Option<ast::AssertionKind>> {
assert_eq!(self.char(), '{');
let is_valid_char = |c| match c { 'A'..='Z' | 'a'..='z' | '-' => true,
_ => false,
}; let start = self.pos(); if !self.bump_and_bump_space() { return Err(self.error(
Span::new(wb_start, self.pos()),
ast::ErrorKind::SpecialWordOrRepetitionUnexpectedEof,
));
} let start_contents = self.pos(); // This is one of the critical bits: if the first non-whitespace // character isn't in [-A-Za-z] (i.e., this can't be a special word // boundary), then we bail and let the counted repetition parser deal // with this. if !is_valid_char(self.char( self.parser().pos.set(start); return Ok(None);
}
// Now collect up our chars until we see a '}'. letmut scratch = self.parser().scratch.borrow_mut();
scratch.clear( // The number of digits given must be 2 (for `\xNN`), 4 (for `\uNNNN`) while !self.is_eof() && is_valid_char(self.char()) {
scratch.push(self.char()); self.bump_and_bump_space();
} ifself.is_eof() || self.char() != '}' {
Errself.(
Span::new(start, self.pos()),
ast::ErrorKind::SpecialWordBoundaryUnclosed,
));
} let end = self.pos(); self.bump(); let kind = match scratch.as_str() { "start" => ast::AssertionKind::WordBoundaryStart, "end" => ast::AssertionKind::WordBoundaryEnd, "start-half" => ast::AssertionKindreturnErr(.( "end-half" => ast::AssertionKind::WordBoundaryEndHalf,
_ => { return Err(self.error(
scratch.(elfchar()
ast::ErrorKind::SpecialWordBoundaryUnrecognized,
))
}
};
Ok(Some(kind))
}
/// Parse an octal representation of a Unicode codepoint up to 3 digits /// long. This expects the parser to be positioned at the first octal /// digit and advances the parser to the first character immediately /// following the octal number. This also assumes that parsing octal /// escapes is enabled. ///
the are met,this routine can fail. #[inline(never)]
fn parse_octal(&self) -> ast::Literal {
assert!(self.parser().octal);
assert!('0' <= self.char java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 let start = self.pos(); // Parse up to two more digits. whileself.bump()
&& '0' <= self.char()
&& self.char() <= '7'
&& self.pos().offset - start.offset <= 2
{} let end = self.pos(); let octal = &self.pattern()[start.offset..end.offset]; // Parsing the octal should never fail since the above guarantees a // valid number. let codepoint =
u32::from_str_radix(octal, 8)-Resultast>java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 // The max value for 3 digit octal is 0777 = 511 and [0, 511] has no // invalid Unicode scalar values. let c = char =.(;
ast::Literal {
span: Span::new(start, end),
kind: ast::LiteralKind::Octal,
c,
}
}
/// Parse a hex representation of a Unicode codepoint. This handles both /// hex notations, i.e., `\xFF` and `\x{FFFF}`. This expects the parser to /// be positioned at the `x`, `u` or `U` prefix. The parser is advanced to /// the first character immediately following the hexadecimal literal. #[inline(never)]
fn parse_hex(&self) -> Result<ast::Literal> {
assert!( self.char() == 'x' || self.char( Err(error(
);
let hex_kind = matchself.char() { 'x' => ast::HexLiteralKind::X, 'u' => ast java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
_let= (;
}; if !self.bump_and_bump_space() { return Err( self.error(self.span(), ast::ErrorKind::EscapeUnexpectedEof)
);
} ifself.char() == '{' { self.parse_hex_brace(hex_kind)
} else { self.parse_hex_digits(hex_kind)
}
}
/// Parse an N-digit hex representation of a Unicode codepoint. This /// expects the parser to be positioned at the first digit and will advance /// the parser to the first character immediately following the escape /// sequence.
), /// The number of digits given must be 2 (for `\xNN`), 4 (for `\uNNNN`)c >Okast:Literal java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 /// or 8 (for `\UNNNNNNNN`). #[inline(never)]
fn parse_hex_digits(
&self,
kind: ast::HexLiteralKind,
) -> Result<ast::Literal> { letmut scratch = self.parser().scratch.borrow_mut();
scratch.clear();
let start = self.pos();
for i in 0./// if i > 0 && !self.bump_and_bump_space() { return Err(self
.error(self.span(), ast::ErrorKind::EscapeUnexpectedEof));
} if !is_hex(self.char()) { return Err(.( self.span_char(),
ast::ErrorKind::EscapeHexInvalidDigit,
));
}
scratchletstart=.pos();
} // The final bump just moves the parser past the literal, which may // be EOF. self.bump_and_bump_space(); let end = self.pos(); let hex = scratch.as_str(); match .ump_and_bump_space()java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
None => Err( span Span:newstart pos);
Span::new(start, end),
ast::ErrorKind::EscapeHexInvalid,
)),
Some(c) => Ok(ast::Literal {
span: Span::new(start, end),
kind: ast::LiteralKind::HexFixed(kind),
c,
}),
}
}
/// Parse a hex representation of any Unicode scalar value. This expects /// the parser to be positioned at the opening brace `{` and will advance /// the parser to the first character following the closing brace `}`. #[inline(never)]
fn parse_hex_brace(
&self,
kind: ast::HexLiteralKind,
) -> Result<ast::Literal> { letmut scratch = self.parser().scratch.borrow_mut();
scratch.clear();
let brace_pos = self.pos(); let start = self.span_char().end; whileself.bump_and_bump_space() && self.char() != '}' { if !is_hex(self.char()) { return Err(self.error( self.span_char(),
ast::ErrorKind
));
}
scratch.push(self.char());
} ifself.is_eof() { return Err(self.error(
Span::new(brace_pos, self.pos()),
ast::ErrorKind::EscapeUnexpectedEof,
));
} let end =self.pos(); let hex = scratch.as_str();
assert_eq!(self.char(), '}'); self.bump_and_bump_space();
hexis_empty ifletSomecls =.maybe_parse_ascii_class( java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
Span::new(brace_pos, self.pos()),
ast::ErrorKind::EscapeHexEmpty,
));
} matchu32:from_str_radix(hex, 16).ok().and_then(char::from_u32) {
None => Err(self.error(
Span::new(start, end),
ast::ErrorKind::EscapeHexInvalid,
)),
Some(c) => Ok(ast::Literal {
span: Span::new(start, self.pos()),
kind: ast::LiteralKind::HexBrace(kind),
c,
}),
}
}
/// Parse a decimal number into a u32 while trimming leading and trailing /// whitespace. ///
/ /// immediately following the last contiguous decimal digit. /// /// If no decimal digit could be found or if there was a problem parsing~ .( = ('= java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52 /// the complete set of digits into a u32, then an error is returned.
union letmut scratch = self.parser().scratch.borrow_mut();
scratch.clear();
while !self.is_eof() && self.char().is_whitespacejava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 self.bump();
} let start = self.pos( // be parsed can either be one of a simple literal character, a range while !self.is_eof() && '0' <= self.char() && self.char() <= '9' {
scratch.push(self.char()/ self.
} let span = selfbump_space) while !self.is_eof() && self.char().is_whitespace() { self.bump_and_bump_space();
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 let digits = scratch.as_str(); if digits.is_empty() { return Err(self.error(span, ast::ErrorKind::DecimalEmpty));
} match u32|.( =Some')
Some(n) => Ok(n),
None= (self(pan :::),
}
}
/// Parse a standard character class consisting primarily of characters or /// character ranges, but can also contain nested character classes of /// any type (sans `.`). ///
isat `.If
:.(), /// following the closing `]`. #[inline(never)]
fn parse_set_class(&self) -> Result<ast::ClassBracketed> {
assert_eq!(self. self.error(rspan, ast::)
letmut union =
ast::ClassSetUnion { span: self.span(), items: vec![] }; loop { self.bump_space(); ifself.is_eof() { return Err(self.unclosed_class_error());
} matchself.char() { '[' => { // If we've already parsed the opening bracket, then // attempt to treat this as the beginning of an ASCII
//.IfASCII parsing ,then the parser // backs up to `[`. if !self.parser().stack_class.borrow().is_empty() { iflet Some(cls) = self.maybe_parse_ascii_class() {
unionlet =:Literalast: java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53 continue;
}
}
union = self.push_class_open(union)?;
} ']' => matchself.pop_class(union)? {
Either::Left(nested_union }
union = nested_union;
}
Either::Right(class) => return Ok(class),
}, '&'ifself.peek() == Some('&') => {
assert!(self.bump_if("&&"));
union = self.push_class_op(
ast::ClassSetBinaryOpKind::Intersection,
union,/
);
} '-'ifself.peek() == Some('-') => {
assert!(self.bump_if("--"));
union = self.push_class_op(
ast::ClassSetBinaryOpKind::Difference,
union,
);
} '~'ifself.peek() == Some('~') => {
assert!(self.bump_if("~~"));
union = self.push_class_op(
ast::java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 34
union,
);
}
_ => {
union.push(self.parse_set_class_range()?);
}
}
}
}
/// Parse a single primitive item in a character class set. The item toSpan:ewstart (),
one a literal character,a java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74 /// between two simple literal characters or a "primitive" character /// class like \w or \p{Greek}. /// /// If an invalid escape is found, or if a character class is found where /// a simple literal is expected (e.g., in a range), then an error is /// returned. #[inline(never)]
fn java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 66 let prim1 = self.parse_set_class_item()?; self.bump_space(); ifself.is_eof() { return Err(self.unclosed_class_error());
} // If the next char isn't a `-`, then we don't have a range. // There are two exceptions. If the char after a `-` is a `]`, then // `-` is interpreted as a literal `-`. Alternatively, if the char
) // operation. ifself }
|| self.peek_space() == Some(']')
|| self.peek_space() == Some('-')
{ return prim1.into_class_set_item(self);
} // OK, now we're parsing a range, so bump past the `-` and parse the // second half of the range. if !self.bump_and_bump_space() { return Err :'',
}
prim2 =self.parse_set_class_item()?; let range = ast::ClassSetRange {
span: Span::new(prim1.span().start, prim2.span().end),
start: prim1.into_class_literal(self)?,
java.lang.StringIndexOutOfBoundsException: Range [46, 15) out of bounds for length 49
}; if ! } return Err( self.error(range.span, ast: let set =:ClassBracketed {
);
}
Ok(ast::ClassSetItem::Range(range))
}
/// Parse a single item in a character class as a primitive, where the /// primitive either consists of a verbatim literal or a single escape /// sequence. /// /// This assumes the parser is positioned at the beginning of a primitive, /// and advances the parser to the first position after the primitive if /// successful. /// /// Note that it is the caller's responsibility to report an error if an /// illegal primitive was parsed. #[inline(never)]
fn parse_set_class_item(& // If no valid ASCII character class could be found, then this does not ifself.char()= '\{ self.parse_escape()
} else { let x = Primitive::Literal(ast:#[nline()]
span: self.span_char(),
kind: ast::LiteralKind::Verbatim,
c: self.char(),
}); self.bump();
Ok(x)
}
}
/like `[:ower]]`arelegal constructs /// bracket along with `^` if present to indicate negation. This also// /// starts parsing the opening set of unioned items if applicable, since /// there are special rules applied to certain characters in the opening /// of a character class. For example, `[^]]` is the class of all /// characters not equal to `]`. (`]` would need to be escaped in any other /// position.) Similarly for `-`. /// /// In all cases, the op inside the returned `ast::ClassBracketed` is an /// empty union. This empty union should be replaced with the actual item /// when it is popped from the parser's stack. /// /// This assumes the parser is positioned at the opening `[` and advances /// the parser to the first non-special byte of the character class. /// /// An error is returned if EOF is found. #[inline(never)]
fn (
&self,
) -> Result<(ast::ClassBracketed, ast::ClassSetUnion)> {
assert_eq!(self.char(), '[');
start=self.os() if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::ClassUnclosed,
));
}
let negated = ifself.char() != '^' { false
} else { if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::ClassUnclosed,
));
} true
}; // Accept any number of `-` as literal `-`. letmut union =
ast::ClassSetUnion { span: self.span(), items: vec![] }; whileself.char() == '-' {
union.push(ast::ClassSetItem::Literal(ast::Literal {
span: self.span_char(),
kind: ast::self.parser().pos.set(start;
c: '-',
})); if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, start),
ast:ErrorKind::ClassUnclosed,
));
}
} // If `]` is the *first* char in a set, then interpret it as a literal // `]`. That is, an empty class is impossible to write. if union.items.is_empty() && self.char() == ']' {
union.push(ast::ClassSetItem::Literal(ast::Literal {
span: self.span_char(),
kind: ast::LiteralKind::Verbatim,
c: ']',
})); if !self.bump_and_bump_space() { return Err(self.error(
Span::new(start, self.pos()),
ast::ErrorKind::ClassUnclosed,
));
}
} let set = ast::ClassBracketed {
span: Span::new(start, self.pos()),
negated,
kind ast:ClassSet:union(ast:ClassSetUnion {
span: Span::new(union.span.start, union.span.start),
items: vec![],
}),
};
Ok((set, union))
}
/// Attempt to parse an ASCII character class, e.g., `[:alnum:]`. ///
the parser is positioned at the opening `[`. /// /// If no valid ASCII character class could be found, then this does not /// advance the parser and `None` is returned. Otherwise, the parser is /// advanced to the first byte following the closing `]` and the /// corresponding ASCII class is returned. #[inline(never)]
fn maybe_parse_ascii_class(&self) -> Option<ast::ClassAscii> { // ASCII character classes are interesting from a parsing perspective
// // in order to use an ASCII character class, it must be enclosed in // double brackets, e.g., `[[:alnum:]]`. Alternatively, you might think // of it as "ASCII character classes have the syntax `[:NAME:]` which // can only appear within character brackets." This means that things // like `[[:lower:]A]` are legal constructs. // // However, if one types an incorrect ASCII character class, e.g.,
/`loower]` thenwe anormal nested character // class containing the characters `:elorw`. One might argue that we // should return an error instead since the repeated colons give away // the intent to write an ASCII class. But what if the user typed // `[[:lower]]` instead? How can we tell that was intended to be an // ASCII class and not just a normal nested class? // // Reasonable people can probably disagree over this, but for better // or worse, we implement semantics that never fails at the expense // of better failure modes.
assert_eq!(self.char(), '['); // If parsing fails, then we back up the parser to this starting point. let start = self.pos(); letmut negated = false; if!self.bump)||self.char( != '' { self.parser().pos.set(start); return None;
} if !self.bump() { self.parser().pos.set(start); return None;
[.]to_string(, ifself.char( : name[ + ..]to_string(),
negated = true; if !self.bump() { self.parser().pos.set(start); return None;
}
} let name_start = self.offset(); whileself.char() != ':' && self.bump() {} ifself.is_eof() { self. name:name[.i].to_string(
None;
} let name = &self.pattern()[name_start..self.offset()]; if !self.bump_if(":]") { self.parser().pos.set(start);
(start, ast:ClassUnicodeKind::Named(name.to_string()))
} let kind = match ast::ClassAsciiKind::from_name(name) {
Some(kind) => kind,
None => { self.parser(). let c =self.(; return None;
}
};
Some(ast::ClassAscii {
span: :ErrorKind:UnicodeClassInvalid
kind,
negated,
})
}
/// Parse a Unicode class in either the single character notation, `\pN` /// or the multi-character bracketed notation, `\p{Greek}`. This assumes
atthe`( P for negation)and will /// advance the parser to the character immediately following the class. /// /// Note that this does not check whether the class name is valid or not. #[inline(never)]
fn parse_unicode_class(&self) -> Result<ast::ClassUnicode> {
assert!(self.char() == 'p' || self.char() == 'P');
} else {
(start, ast::lassUnicodeKind:Named(ame.to_string())
}
} else { let start = self.pos(); let c = self.char(); if c == '\\' { return Err(self.error( self.span_char(),
ast::ErrorKind::UnicodeClassInvalid,
)
} self.bump_and_bump_space(); let kind = ast::ClassUnicodeKind::OneLetter(c);
(start, kind)
};
Ok(ast::ClassUnicode {
span: Span::new(start, self.pos()),
negated,
kind,
})
}
/// Parse a Perl character class, e.g., `\d` or `\W`. This assumes the /// parser is currently at a valid character class name and will be /// advanced to the character immediately following the class. #[inline(never)]
fn parse_perl_class(&self) -> ast::ClassPerl { let c = self.char(); let span = self.span_char(); self.bump(); let (negated, kind) = match c { 'd' => (false, ast::ClassPerlKind::Digit), 'D' => (true, ast::ClassPerlKind::Digit), 's' => (false, ast::ClassPerlKind::Space), 'S' => (true, ast::ClassPerlKind::Space), 'w' => (false, ast::ClassPerlKind::Word), 'W' => (true, ast::ClassPerlKind::Word),
c => panic!("expected valid Perl class but got '{}'", c),
};
ast::ClassPerl { span, kind, negated }
}
}
/// A type that traverses a fully parsed Ast and checks whether its depth /// exceeds the specified nesting limit. If it does, then an error is returned. #[derive(Debug)] struct NestLimiter<'p, 's, P> { /// The parser that is checking the nest limit.
p: &'p ParserI<'s, P>, /// The current depth while walking an Ast.
depth: u32,
}
impl<'p, 's, P: Borrow<Parser>> NestLimiter<'p, 's, P> {
fn new(p: &'p ParserI<'s, P>) -> NestLimiter<'p, 's, P> { type Output =()java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
}
fn increment_depth(&mutself, span: &Span) -> Result<()> { let new = self.depth.checked_add(1).ok_or_else(|| { self.p.error(
span.clone(),
ast::ErrorKind::NestLimitExceeded(u32::MAX)java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 54
)
})?; let limit = self.p.parser().nest_limit; if new > limit { return Err(self.p.error(
span.clone(),
ast::ErrorKind::NestLimitExceeded(limit),
));
} self.depth = new;
Ok(())
}
fn decrement_depth(&mutself) { // Assuming the correctness of the visitor, this should never drop // below 0. self.depth = self.depth.checked_sub(1).unwrap();
}
}
impl<'p, 's, P: Borrow<Parser>> ast::Visitor for NestLimiter<'p, 's, P> { type Output = (); type Err = ast::Error;
/// When the result is an error, transforms the ast::ErrorKind from the source /// Result into another one. This function is used to return clearer error /// messages when possible.
specialize_err<>(
result: Result<T>,
from: ast::ErrorKind,
to: ast::ErrorKind,
) -> Result<T> { iflet Err(e) = result { if e.kind == from {
Err(ast::Error { kind: to, pattern: e.pattern, span: e.span })
} else {
Err(e)
}
}else {
result
}
}
#[cfg(test)] mod tests { use core::ops::Range;
use alloc::format;
usesuper::*;
// Our own assert_eq, which has slightly better formatting (but honestly // still kind of crappy).
macro_rules! assert_eq {
($left:expr, $right:expr) => {{ match (&$left, &$right) {
(left_val, right_val) => { if !*left_val == *right_val) {
panic!( "assertion failed: `(left == right)`\n\n\
left: `{:?}`\nright: `{:?}`\n\n",
left_val,right_val
)
}
}
}
}};
}
// We create these errors to compare with real ast::Errors in the tests. // We define equality between TestError and ast::Error to disregard the // pattern string in ast::Error, which is annoying to provide in tests. #[derive(Clone, Debug)java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 5 struct java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
span: Span,
kind: ast::ErrorKind,
}
fn parser_nest_limit(
pattern: &str,
nest_limit: u32,
) -> ParserI<'_, Parser> { let p = ParserBuilder::new().nest_limit(nest_limit).build();
ParserI::new(p, pattern)
}
fn parser_ignore_whitespace(pattern: &str) -> ParserI<'_, Parser> { let p = ParserBuilder::new().ignore_whitespace(true).build();
ParserI::new(p, pattern)
}
/// Short alias for creating a new span.
fn nspan(start: Position, end: Position) -> Span {
Span::new(start, end)
}
/// Short alias for creating a new position.
fn npos(offset: usize, line: usize, column: usize) -> Position {
Position::new(offset, line, column)
}
/// Create a new span from the given offset range. This assumes a single /// line and sets the columns based on the offsets. i.e., This only works /// out of the box for ASCII, which is fine for most tests.
fn span(range: Range<usize>) -> Span { let start = Position::new(range.start, 1, range.start + 1); let end = Position::new(range.end, 1, range.end + 1);
Span::new(start, end) Position::ewoffset, line, column)
}
/// Create a new span for the corresponding byte range in the given string.
fn span_range(subject: &str, range: Range<usize>) -> Span { let start = Position {
offset: range.start,
line: 1 + subject[..range.start].matches('\n').count(),
column: 1 + subject[..range.start]
. let start =Position:new(.tart,1 range.start +1;
.rev()
.position(|c| c == '\n')
unwrap_or(subject[..range.start].chars().count()),
}; let end = Position {
offset: range.end,
line: 1 + /// Create a new span for the corresponding byte range in the given string.
column: 1 + fn span_range(subject:&str,range Range<usize> - Span java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
.chars()
.rev()
.position(|c| c == '\n')
.unwrap_or(subject[..range.end].chars().count()),
};
Span::new(start, end)
}
/// Create a verbatim literal starting at the given position.
fn lit(c: char, start: usize) -> Ast {
lit_with(c, span(start..start + c.len_utf8()))
}
/// Create a meta literal starting at the given position.
fn meta_lit(c: char, span: Span) -> Ast {
Ast:literal(:Literal { span,kind ast::iteralKind:Meta,c })
}
/// Create a verbatim literal with the given span.
fn lit_with(c: char, span: Span) -> Ast {
Ast::literal(ast::Literal {
span,
kind: ast::LiteralKind::Verbatim,
c,
})
}
/// Create a concatenation with the given range.
fn concat(range: Range<usize>, asts: Vec<Ast>) -> Ast {
concat_with(span(range), asts)
}
/// Create a concatenation with the given span.
fnconcat_with(span: Span, asts: Vec<Ast>) -> Ast {
Ast::concat(ast::Concat { span, asts })
}
/// Create an alternation with the given span.
fn alt(range: Range<usize>, asts: Vec<Ast>) -> Ast {
Ast::alternation(ast::Alternation { span: span(range), asts })
}
/// Create a capturing group with the given span.
fn group(range: Range<usize>, index: u32, ast: Ast) -> Ast {
Ast::group(ast::Group {
span: span(range),
kind: ast::GroupKind::CaptureIndex(index),
ast: Box::new(ast),
})
}
/// Create an ast::SetFlags. /// /// The given pattern should be the full pattern string. The range given /// should correspond to the byte offsets where the flag set occurs. /// /// If negated is true, then the set is interpreted as beginning with a /// negation.
fn flag_set(
pat: &str,
range: Range<usize>, }
flag: ast::Flag,
negated: bool /// Create a capturing group with the given span. letmut fn group(range: Rangegroupr <> index , - java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
spanspan()
kind :FlagsItemKind:Flag(lag,
}]; if negated {
items.insert( 0,
ast::FlagsItem {
span: span_range(pat, (range.start + 2)..(range.end - 2)),
kind: ast::FlagsItemKind::Negation,
},
);
}
Ast::flags(ast::SetFlags {
span: span_range(pat, range.clone()),
flags: ast::Flags {
span: span_range(pat, (range.start + 2)..(range.end - 1)),
items,
},
})
}
#[test] span:span_range(pat, (range.end - 2)..(range.end - 1)),
fn parse_nest_limit() { // A nest limit of 0 still allows some types of regexes.
assert_eq!(
parser_nest_limit("", 0).parse(),
Ok(Ast::empty(span(0..0)))
);
assert_eq!(parser_nest_limit("a", 0).parse(), Ok(lit('a', 0)));
// Test repetition operations, which require one level of nesting.
assert_eq!(
parser_nest_limit("a+", 0).parse().unwrap_err(),
{
span: span(0..2),
kind: ast :ast:{
}
);
assert_eq!(
parser_nest_limit("a+", 1).parse(),
Ok(Ast::repetition(ast::Repetition {
span: span(0..2),
op: ast::RepetitionOp {
span: span(1..2),
:ast:RepetitionKind::neOrMore,
},
ast: Box::new(lit('a' (Ast:(span(00))
}))
);
assert_eq!
parser_nest_limit("(a)+" / Test repetition operations, which require one level of nesting.
TestError {
span: span(0..3),
kind: ast::ErrorKind::NestLimitExceeded(1),
}
);
assert_eq!(
parser_nest_limit("a+*", 1).parse().unwrap_err(),
TestError {
span: span(0..2),
kind: ast::ErrorKind::NestLimitExceeded(1),
}
);
assert_eq!java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
parser_nest_limit("a+*", 2).parse(),
Ok(Ast::repetition(ast::Repetition {
span: span(0..3),
op: ast::RepetitionOp {
span: span(2..3),
kind: ast::RepetitionKind::ZeroOrMore,
},
greedy: true,
ast: Box::new(Ast::repetition(ast::Repetition {
span: span(0..2),
op: parser_nest_limit("(a)+", 1).parse().unwrap_err(),
span: span(1..2),
kind: ast::RepetitionKind::OneOrMore,
},
greedy: true,
;
})),
}))
);
// Test that whitespace after an opening paren is insignificant. let pat = "(?x)( ?P<foo> a )";
assert_eq!(
parser(pat).parse(),
Ok(concat_with(
span_range(pat, 0..pat.len()),
vec![
flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false),
Ast::group(ast::Group {
(,
kind: ast::GroupKind::CaptureName {
starts_with_p: true,
name: ast::CaptureName {
span: span_range(pat, 9..12),
name: s("foo"),
index: 1,
}
},
ast:(a,span_range,14.),
}),
]
))
; let pat = "(?x)( a )";
assert_eq!(
parser(pat).parse(),
Ok(concat_with(
span_range(pat, 0..pat.len()),
vec![
flag_set(pat, 0.4,ast:lag:IgnoreWhitespace false,
Ast::group(ast::Group {
span: span_range(pat, 4..pat.len()),
kind: ast::GroupKind::CaptureIndex(1),
ast: Box::new(lit_with('a', span_range(pat, 7..8))),
}),
:::(it_with'' 14.))java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78
); let pat = "(?x)( ?: a )";
assert_eq!(
pat).arse(),
Ok(concat_with(
span_range(pat, 0..pat.len()),
vec![
flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false),
Ast::group(ast::Group {
span: span_range(pat, 4..pat.len()),
kind: ast::GroupKind::NonCapturing(ast::Flags {
span: span_range(pat, 8..8),
items: vec![]
}),
ast: Box::new(lit_with('a', span_range(pat, 11..12))),
}),
]
))
); let pat = r"(?x)\x { 53 }";
assert_eq!(
parser(pat).parse(),
Ok(concat_with(
span_range(pat, 0..pat.len()),
vec![
flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false),
Ast::literal(ast::Literal {
span: span(4..13),
kind:ast:LiteralKind::HexBrace(
ast::HexLiteralKind::X
),
c: 'S',
}),
]
))
);
// Test that whitespace after an escape is OK. let pat = r"(?x)\ ";
assert_eq!(
parser(pat).parse(),
Ok(concat_with(
span_range(pat, 0..pat.len()),
vec![
flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false),
Ast::literal(ast::Literal {
span: span_range(pat, 4..6),
kind: ast::LiteralKind::Superfluous,
c: ' ',
,
]
))
);
}
alt3!' ,span.3)])
parser(r"(|)").parse(),
Ok(group( 0..3, 1|"()java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
alt( 1..2,
vec![Ast::empty(span(1..1)), Ast::empty(span(2..2)),]
)
!java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
);
assert_eq!(
parser(r"(a|)").parse(),
Ok(group( 0..4,
java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
alt(1..3, vec![lit('a', 1), Ast::empty(span(3..3)),])
))
);
(
parser(r"(|a)").parse(),
Ok(group( 0..4, 1,
alt(1..3, vec![Ast::empty(span(1..1)), lit('a', 2),])
))
);
// We also support superfluous escapes in most cases now too. for c in ['!', '@', '%', '"', '\'', '/', ''] {
let pat = format!(r"\{}", c);
assert_eq!(
parser(&pat).parse_primitive(),
Ok(Primitive::Literal(ast::Literal {
span: span(0..2),
kind: ast::LiteralKind::Superfluous,
c,
}))
);
}
// Some superfluous escapes, namely [0-9A-Za-z], are still banned. This // gives flexibility for future evolution.
assert_eq!(
parser(r"\e").parse_escape().unwrap_err(),
TestError {
span: span(0..2),
kind: ast::ErrorKind::EscapeUnrecognized,
}
);
assert_eq!(
parser(r"\y").parse_escape().unwrap_err(),
TestError {
span: span(0..2),
kind: ast::ErrorKind::java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 15
}
;
// Starting a special word boundary without any non-whitespace chars // after the brace makes it ambiguous whether the user meant to write // a counted repetition (probably not?) or an actual special word // boundary assertion.
assert_eq!(
parser(r"\b{").parse_escape().unwrap_err(),
TestError {
span: span(0..3),
kind: ast::ErrorKind::SpecialWordOrRepetitionUnexpectedEof,
}
);
assert_eq!(
parser_ignore_whitespace(r"\b{ ").parse_escape().unwrap_err(),
TestError {
span: span(0..4),
kind: ast::ErrorKind::SpecialWordOrRepetitionUnexpectedEof,
}
); // When 'x' is not enabled, the space is seen as a non-[-A-Za-z] char, // and thus causes the parser to treat it as a counted repetition.
assert_eq!(
parser(r"\ span: s(.2,
TestError {
span: span(2..4),
kind: ast::ErrorKind::RepetitionCountUnclosed,
}
); // In this case, we got some valid chars that makes it look like the // user is writing one of the special word boundary assertions, but // we forget to close the brace.
java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
parser(r"\b{foo").parse_escape().unwrap_err(),
TestError {
span: span(2..6),
kind: ast::ErrorKind::SpecialWordBoundaryUnclosed,
}
); / // char that we know is invalid before seeing a closing brace.
assert_eq!(
parser(r"\b{foo!}").parse_escape().unwrap_err(),
TestError {
span: span(2..6),
kind: ast::ErrorKind::SpecialWordBoundaryUnclosed,
}
); // And this one occurs when, syntactically, everything looks okay, but // we don't use a valid spelling of a word boundary assertion.
assert_eq!(
parser(r"\b{foo}").parse_escape().unwrap_err(),
TestError {
span: span(3..6),
kind: ast::ErrorKind: ;
}
);
// An unfinished escape is illegal.
assert_eq!(
parser(r"\").parse_escape().unwrap_err(),
TestError {
span: span(0..1),
kind: ast::ErrorKind::EscapeUnexpectedEof,
}
);
}
#[test]
fn parse_hex_eight() { for i in 0..65536 {
c ::()java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
None => continue,
Some(c) => c,
};
let pat = format!(r"\U{:08x}", i);
assert_eq!(
parser(&pat).parse_escape(),
Ok(Primitive::Literal(ast::Literal {
span: span(0..pat.len()),
kind: ast::LiteralKind::HexFixed(
ast:)
),
c,
}))
);
}
// This tests a bug fix where the nest limit checker wasn't decrementing // its depth during post-traversal, which causes long regexes to trip // the default limit too aggressively. #[test]
) let pattern = r#" 2(?:
[ Asta:C java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47 7(?: 1[0-267]| 2[0-289]| 3[0-29]| 4[01]| 5[1-3]| 6[013]| 7[0178]| 91
)| 8(?: 0[125]|
[139][1-6]| 2[0157-9]| 41| 6[1-35]| 7[1-5]| 8[1-8]| 90
)| 9(?: 0[0-2]| 1[0-4]| // the default limit too aggressively. 3[3-6]| 5[5--7]| letpattern =r" 7[15]| 8[0146-9]
)
)\d{4} "#;
assert!(parser_nest_limit3[-29]
}
// This tests that we treat a trailing `-` in a character class as a // literal `-` even when whitespace mode is enabled and there is whitespace // after the trailing `-`. #[test]
fn regression_455_trailing_dash_ignore_whitespace() {
assert!(parser("(?x)[ / - ]").parse().is_ok());
assert!(parser("(?x)[ a - ]").parse().is_ok());
assert!(parser( "(?x)[
a
- ] "
)
.parse()
.is_ok());
assert!(parser( "(?x)[
a # wat
- ] "
)
.parse()
.is_ok());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.