use std::sync::Mutex;
pub use regast_core::{
Backend, Disambiguation, MatchError, NoMatch, ParseTree, ParseTreeWalk, PtKind, PtNode,
TraceStep,
};
pub use regast_syntax::{
AnchorKind, AstKind, ClassItem, ClassRange, ClassSet, Cursor, Flow, GroupInfo, GroupKind,
JsonShape, NodeId, NodeMap, ParseError, ParseErrorKind, Pattern, PerlClass, RepKind, Span,
Visitor, visit,
};
use regast_core::Matcher;
const DEFAULT_SIZE_LIMIT: usize = 100_000;
pub struct Regast {
ast: Pattern,
matcher: Mutex<Matcher>,
}
impl Regast {
pub fn new(pattern: &str) -> Result<Self, ParseError> {
Self::builder(pattern).build()
}
#[must_use]
pub fn builder(pattern: &str) -> Builder {
Builder {
pattern: pattern.to_owned(),
disambiguation: Disambiguation::Posix,
size_limit: DEFAULT_SIZE_LIMIT,
backend: Backend::Derivative,
}
}
#[must_use]
pub const fn ast(&self) -> &Pattern {
&self.ast
}
pub fn parse(&self, input: &str) -> Result<ParseTree, MatchError> {
self.matcher
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.parse(input)
}
pub fn find_parse(&self, input: &str) -> Result<Option<ParseTree>, MatchError> {
self.matcher
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.find_parse(input)
}
#[must_use]
pub fn is_match(&self, input: &str) -> bool {
self.matcher
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.is_match(input)
}
pub fn try_is_match(&self, input: &str) -> Result<bool, MatchError> {
self.matcher
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.try_is_match(input)
}
#[must_use]
pub fn trace(&self, input: &str) -> Vec<TraceStep> {
self.matcher
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.trace(input)
}
}
#[derive(Clone, Debug)]
pub struct Builder {
pattern: String,
disambiguation: Disambiguation,
size_limit: usize,
backend: Backend,
}
impl Builder {
#[must_use]
pub const fn disambiguation(mut self, disambiguation: Disambiguation) -> Self {
self.disambiguation = disambiguation;
self
}
#[must_use]
pub const fn posix(self) -> Self {
self.disambiguation(Disambiguation::Posix)
}
#[must_use]
pub const fn greedy(self) -> Self {
self.disambiguation(Disambiguation::Greedy)
}
#[must_use]
pub const fn size_limit(mut self, limit: usize) -> Self {
self.size_limit = limit;
self
}
#[must_use]
pub const fn backend(mut self, backend: Backend) -> Self {
self.backend = backend;
self
}
pub fn build(self) -> Result<Regast, ParseError> {
let ast = Pattern::parse(&self.pattern)?;
let matcher = Matcher::new_with_backend(
ast.clone(),
self.disambiguation,
self.size_limit,
self.backend,
);
Ok(Regast {
ast,
matcher: Mutex::new(matcher),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn facade_exposes_ast_match_and_parse_tree() {
let regex = Regast::new("(?<letter>a|b)+").unwrap();
assert_eq!(regex.ast().source(), "(?<letter>a|b)+");
assert!(regex.is_match("aba"));
let tree = regex.parse("aba").unwrap();
assert_eq!(tree.group_by_name_all("letter").len(), 3);
}
#[test]
fn compiled_pattern_is_send_and_sync() {
const fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Regast>();
}
}