mod all;
mod anchor_end;
mod anchor_start;
mod duration_expr;
mod expr_map;
mod filter;
mod first_match_of;
mod fixed_phrase;
mod longest_match_of;
mod mergeable_words;
mod optional;
mod pronoun_be;
mod reflexive_pronoun;
mod repeating;
mod sequence_expr;
mod similar_to_phrase;
mod space_or_hyphen;
mod spelled_number_expr;
mod step;
mod time_unit_expr;
mod unless_step;
mod word_expr_group;
#[cfg(not(feature = "concurrent"))]
use std::rc::Rc;
use std::sync::Arc;
pub use all::All;
pub use anchor_end::AnchorEnd;
pub use anchor_start::AnchorStart;
pub use duration_expr::DurationExpr;
pub use expr_map::ExprMap;
pub use filter::Filter;
pub use first_match_of::FirstMatchOf;
pub use fixed_phrase::FixedPhrase;
pub use longest_match_of::LongestMatchOf;
pub use mergeable_words::MergeableWords;
pub use optional::Optional;
pub use pronoun_be::PronounBe;
pub use reflexive_pronoun::ReflexivePronoun;
pub use repeating::Repeating;
pub use sequence_expr::SequenceExpr;
pub use similar_to_phrase::SimilarToPhrase;
pub use space_or_hyphen::SpaceOrHyphen;
pub use spelled_number_expr::SpelledNumberExpr;
pub use step::Step;
pub use time_unit_expr::TimeUnitExpr;
pub use unless_step::UnlessStep;
pub use word_expr_group::WordExprGroup;
use crate::{Document, LSend, Span, Token};
pub trait Expr: LSend {
fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>>;
}
impl<S> Expr for S
where
S: Step + ?Sized,
{
fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
self.step(tokens, cursor, source).map(|s| {
if s >= 0 {
Span::new_with_len(cursor, s as usize)
} else {
Span::new(add(cursor, s).unwrap(), cursor)
}
})
}
}
impl<E> Expr for Arc<E>
where
E: Expr,
{
fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
self.as_ref().run(cursor, tokens, source)
}
}
impl Expr for Box<dyn Expr> {
fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
self.as_ref().run(cursor, tokens, source)
}
}
#[cfg(not(feature = "concurrent"))]
impl<E> Expr for Rc<E>
where
E: Expr,
{
fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
self.as_ref().run(cursor, tokens, source)
}
}
fn add(u: usize, i: isize) -> Option<usize> {
if i.is_negative() {
u.checked_sub(i.wrapping_abs() as u32 as usize)
} else {
u.checked_add(i as usize)
}
}
pub trait ExprExt {
fn iter_matches<'a>(
&'a self,
tokens: &'a [Token],
source: &'a [char],
) -> Box<dyn Iterator<Item = Span<Token>> + 'a>;
fn iter_matches_in_doc<'a>(
&'a self,
doc: &'a Document,
) -> Box<dyn Iterator<Item = Span<Token>> + 'a>;
}
impl<E: ?Sized> ExprExt for E
where
E: Expr,
{
fn iter_matches<'a>(
&'a self,
tokens: &'a [Token],
source: &'a [char],
) -> Box<dyn Iterator<Item = Span<Token>> + 'a> {
let mut last_end = 0usize;
Box::new((0..tokens.len()).filter_map(move |i| {
let span = self.run(i, tokens, source)?;
if span.start >= last_end {
last_end = span.end;
Some(span)
} else {
None
}
}))
}
fn iter_matches_in_doc<'a>(
&'a self,
doc: &'a Document,
) -> Box<dyn Iterator<Item = Span<Token>> + 'a> {
Box::new(self.iter_matches(doc.get_tokens(), doc.get_source()))
}
}
pub trait OwnedExprExt {
fn or(self, other: impl Expr + 'static) -> FirstMatchOf;
fn and(self, other: impl Expr + 'static) -> All;
fn and_not(self, other: impl Expr + 'static) -> All;
fn or_longest(self, other: impl Expr + 'static) -> LongestMatchOf;
}
impl<E> OwnedExprExt for E
where
E: Expr + 'static,
{
fn or(self, other: impl Expr + 'static) -> FirstMatchOf {
FirstMatchOf::new(vec![Box::new(self), Box::new(other)])
}
fn and(self, other: impl Expr + 'static) -> All {
All::new(vec![Box::new(self), Box::new(other)])
}
fn and_not(self, other: impl Expr + 'static) -> All {
self.and(UnlessStep::new(other, |_tok: &Token, _src: &[char]| true))
}
fn or_longest(self, other: impl Expr + 'static) -> LongestMatchOf {
LongestMatchOf::new(vec![Box::new(self), Box::new(other)])
}
}