use super::ast::*;
use super::lexer::TokenKind;
use super::state::Parser;
use crate::error::{Error, ErrorKind, Result};
pub const MAX_REPETITION: u32 = 65535;
pub const DEFAULT_NEST_LIMIT: u32 = 250;
impl Parser<'_> {
pub(super) fn parse_alternation(&mut self) -> Result<Expr> {
let left = self.parse_concat()?;
if matches!(self.current.kind, TokenKind::Pipe) {
self.parse_alternation_rest(left)
} else {
Ok(left)
}
}
#[inline(never)]
fn parse_alternation_rest(&mut self, first: Expr) -> Result<Expr> {
let mut alternatives = vec![first];
while matches!(self.current.kind, TokenKind::Pipe) {
self.advance()?;
alternatives.push(self.parse_concat()?);
}
Ok(Expr::Alt(alternatives))
}
fn parse_concat(&mut self) -> Result<Expr> {
let mut exprs = Vec::new();
while !self.is_at_end() && !self.is_concat_terminator() {
let outer_flags = self.flags;
exprs.push(self.parse_repeat()?);
if self.flags != outer_flags {
exprs.push(self.parse_flag_scope()?);
break;
}
}
Ok(match exprs.len() {
0 => Expr::Empty,
1 => exprs.pop().unwrap(),
_ => Expr::Concat(exprs),
})
}
#[inline(never)]
fn parse_flag_scope(&mut self) -> Result<Expr> {
let scoped_flags = self.flags;
let rest = self.with_nesting(Self::parse_concat)?;
Ok(Expr::Group(Box::new(Group {
expr: rest,
kind: GroupKind::Flagged(scoped_flags),
})))
}
fn is_concat_terminator(&self) -> bool {
matches!(
self.current.kind,
TokenKind::Pipe | TokenKind::CloseParen | TokenKind::Eof
)
}
fn parse_repeat(&mut self) -> Result<Expr> {
let expr = self.parse_atom()?;
self.parse_quantifier(expr)
}
fn parse_quantifier(&mut self, expr: Expr) -> Result<Expr> {
let (min, max) = match &self.current.kind {
TokenKind::Star => {
self.advance()?;
(0, None)
}
TokenKind::Plus => {
self.advance()?;
(1, None)
}
TokenKind::Question => {
self.advance()?;
(0, Some(1))
}
TokenKind::OpenBrace => {
self.advance()?;
let (min, max) = self.parse_repetition_range()?;
self.expect(TokenKind::CloseBrace)?;
(min, max)
}
_ => return Ok(expr),
};
let greedy = if matches!(self.current.kind, TokenKind::Question) {
self.advance()?;
false
} else {
true
};
if matches!(self.current.kind, TokenKind::Plus) {
let span = self.current.span;
return Err(Error::with_span(
ErrorKind::PossessiveQuantifier,
self.pattern,
span,
));
}
if matches!(
self.current.kind,
TokenKind::Star | TokenKind::Question | TokenKind::OpenBrace
) {
return Err(Error::with_span(
ErrorKind::NestedQuantifier,
self.pattern,
self.current.span,
));
}
Ok(Expr::Repeat(Box::new(Repeat::new(expr, min, max, greedy))))
}
fn check_repetition_bound(&self, bound: u32) -> Result<()> {
if bound > MAX_REPETITION {
return Err(Error::with_span(
ErrorKind::RepetitionTooLarge {
bound,
limit: MAX_REPETITION,
},
self.pattern,
self.current.span,
));
}
Ok(())
}
fn parse_repetition_range(&mut self) -> Result<(u32, Option<u32>)> {
let mut min = 0u32;
while let TokenKind::Digit(d) = self.current.kind {
min = min.saturating_mul(10).saturating_add(d);
self.advance()?;
}
self.check_repetition_bound(min)?;
if matches!(self.current.kind, TokenKind::CloseBrace) {
return Ok((min, Some(min)));
}
if !matches!(self.current.kind, TokenKind::Comma) {
return Err(Error::with_span(
ErrorKind::InvalidRepetition,
self.pattern,
self.current.span,
));
}
self.advance()?;
if matches!(self.current.kind, TokenKind::CloseBrace) {
return Ok((min, None));
}
let mut max = 0u32;
let mut has_max = false;
while let TokenKind::Digit(d) = self.current.kind {
has_max = true;
max = max.saturating_mul(10).saturating_add(d);
self.advance()?;
}
self.check_repetition_bound(max)?;
if !has_max {
return Err(Error::with_span(
ErrorKind::InvalidRepetition,
self.pattern,
self.current.span,
));
}
if max < min {
return Err(Error::with_span(
ErrorKind::InvalidRepetition,
self.pattern,
self.current.span,
));
}
Ok((min, Some(max)))
}
}