use super::alternation::DEFAULT_NEST_LIMIT;
use super::ast::{Ast, Flags};
use super::lexer::{Lexer, Token, TokenKind};
use crate::error::{Error, ErrorKind, Result};
pub fn parse(pattern: &str) -> Result<Ast> {
parse_with_nest_limit(pattern, DEFAULT_NEST_LIMIT)
}
pub fn parse_with_nest_limit(pattern: &str, nest_limit: u32) -> Result<Ast> {
let mut parser = Parser::with_nest_limit(pattern, nest_limit)?;
parser.parse()
}
pub struct Parser<'a> {
pub(super) lexer: Lexer<'a>,
pub(super) current: Token,
pub(super) pattern: &'a str,
pub(super) next_capture: u32,
pub(super) capture_count: u32,
pub(super) flags: Flags,
pub(super) named_groups: std::collections::HashMap<String, u32>,
pub(super) depth: u32,
pub(super) nest_limit: u32,
}
impl<'a> Parser<'a> {
pub fn new(pattern: &'a str) -> Result<Self> {
Self::with_nest_limit(pattern, DEFAULT_NEST_LIMIT)
}
pub fn with_nest_limit(pattern: &'a str, nest_limit: u32) -> Result<Self> {
let mut lexer = Lexer::new(pattern);
let current = lexer.next_token()?;
Ok(Self {
lexer,
current,
pattern,
next_capture: 1,
capture_count: 0,
flags: Flags::default(),
named_groups: std::collections::HashMap::new(),
depth: 0,
nest_limit,
})
}
pub(super) fn with_nesting<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
self.depth += 1;
if self.depth > self.nest_limit {
let depth = self.depth;
let limit = self.nest_limit;
let span = self.current.span;
self.depth -= 1;
return Err(Error::with_span(
ErrorKind::NestingTooDeep { depth, limit },
self.pattern,
span,
));
}
let result = f(self);
self.depth -= 1;
result
}
pub fn parse(&mut self) -> Result<Ast> {
let expr = self.parse_alternation()?;
if !self.is_at_end() {
return Err(Error::with_span(
ErrorKind::UnexpectedChar(self.current_char().unwrap_or('?')),
self.pattern,
self.current.span,
));
}
Ok(Ast {
expr,
flags: self.flags,
})
}
pub(super) fn advance(&mut self) -> Result<Token> {
let prev = std::mem::replace(&mut self.current, self.lexer.next_token()?);
Ok(prev)
}
pub(super) fn is_at_end(&self) -> bool {
matches!(self.current.kind, TokenKind::Eof)
}
pub(super) fn current_char(&self) -> Option<char> {
match &self.current.kind {
TokenKind::Literal(c) => Some(*c),
_ => None,
}
}
pub(super) fn check(&self, kind: &TokenKind) -> bool {
std::mem::discriminant(&self.current.kind) == std::mem::discriminant(kind)
}
pub(super) fn expect(&mut self, kind: TokenKind) -> Result<Token> {
if self.check(&kind) {
self.advance()
} else {
Err(Error::with_span(
ErrorKind::UnexpectedChar(self.current_char().unwrap_or('?')),
self.pattern,
self.current.span,
))
}
}
pub(super) fn restore_flags(&mut self, flags: Flags) {
self.flags = flags;
self.lexer.set_extended(flags.extended);
}
pub(super) fn current_text(&self) -> &str {
self.pattern
.get(self.current.span.start..self.current.span.end)
.unwrap_or_default()
}
}