1mod all;
17mod anchor_end;
18mod anchor_start;
19mod duration_expr;
20mod expr_map;
21mod filter;
22mod first_match_of;
23mod fixed_phrase;
24mod longest_match_of;
25mod mergeable_words;
26mod not;
27mod optional;
28mod pronoun_be;
29mod reflexive_pronoun;
30mod repeating;
31mod sequence_expr;
32mod similar_to_phrase;
33mod space_or_hyphen;
34mod spelled_number_expr;
35mod step;
36mod time_unit_expr;
37mod unless_step;
38mod word_expr_group;
39
40#[cfg(not(feature = "concurrent"))]
41use std::rc::Rc;
42use std::sync::Arc;
43
44pub use all::All;
45pub use anchor_end::AnchorEnd;
46pub use anchor_start::AnchorStart;
47pub use duration_expr::DurationExpr;
48pub use expr_map::ExprMap;
49pub use filter::Filter;
50pub use first_match_of::FirstMatchOf;
51pub use fixed_phrase::FixedPhrase;
52pub use longest_match_of::LongestMatchOf;
53pub use mergeable_words::MergeableWords;
54pub use not::Not;
55pub use optional::Optional;
56pub use pronoun_be::PronounBe;
57pub use reflexive_pronoun::ReflexivePronoun;
58pub use repeating::Repeating;
59pub use sequence_expr::SequenceExpr;
60pub use similar_to_phrase::SimilarToPhrase;
61pub use space_or_hyphen::SpaceOrHyphen;
62pub use spelled_number_expr::SpelledNumberExpr;
63pub use step::Step;
64pub use time_unit_expr::TimeUnitExpr;
65pub use unless_step::UnlessStep;
66pub use word_expr_group::WordExprGroup;
67
68use crate::{Document, LSend, Span, Token};
69
70pub trait Expr: LSend {
71 fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>>;
72}
73
74impl<S> Expr for S
75where
76 S: Step + ?Sized,
77{
78 fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
79 self.step(tokens, cursor, source).map(|s| {
80 if s >= 0 {
81 Span::new_with_len(cursor, s as usize)
82 } else {
83 Span::new(add(cursor, s).unwrap(), cursor)
84 }
85 })
86 }
87}
88
89impl<E> Expr for Arc<E>
90where
91 E: Expr,
92{
93 fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
94 self.as_ref().run(cursor, tokens, source)
95 }
96}
97
98impl Expr for Box<dyn Expr> {
99 fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
100 self.as_ref().run(cursor, tokens, source)
101 }
102}
103
104#[cfg(not(feature = "concurrent"))]
105impl<E> Expr for Rc<E>
106where
107 E: Expr,
108{
109 fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
110 self.as_ref().run(cursor, tokens, source)
111 }
112}
113
114fn add(u: usize, i: isize) -> Option<usize> {
115 if i.is_negative() {
116 u.checked_sub(i.wrapping_abs() as u32 as usize)
117 } else {
118 u.checked_add(i as usize)
119 }
120}
121
122pub trait ExprExt {
123 fn iter_matches<'a>(
126 &'a self,
127 tokens: &'a [Token],
128 source: &'a [char],
129 ) -> Box<dyn Iterator<Item = Span<Token>> + 'a>;
130
131 fn iter_matches_in_doc<'a>(
132 &'a self,
133 doc: &'a Document,
134 ) -> Box<dyn Iterator<Item = Span<Token>> + 'a>;
135}
136
137impl<E: ?Sized> ExprExt for E
138where
139 E: Expr,
140{
141 fn iter_matches<'a>(
142 &'a self,
143 tokens: &'a [Token],
144 source: &'a [char],
145 ) -> Box<dyn Iterator<Item = Span<Token>> + 'a> {
146 let mut last_end = 0usize;
147
148 Box::new((0..tokens.len()).filter_map(move |i| {
149 let span = self.run(i, tokens, source)?;
150 if span.start >= last_end {
151 last_end = span.end;
152 Some(span)
153 } else {
154 None
155 }
156 }))
157 }
158
159 fn iter_matches_in_doc<'a>(
160 &'a self,
161 doc: &'a Document,
162 ) -> Box<dyn Iterator<Item = Span<Token>> + 'a> {
163 Box::new(self.iter_matches(doc.get_tokens(), doc.get_source()))
164 }
165}
166
167pub trait OwnedExprExt {
168 fn or(self, other: impl Expr + 'static) -> FirstMatchOf;
169 fn and(self, other: impl Expr + 'static) -> All;
170 fn but_not(self, other: impl Expr + 'static) -> All;
171 fn or_longest(self, other: impl Expr + 'static) -> LongestMatchOf;
172}
173
174impl<E> OwnedExprExt for E
175where
176 E: Expr + 'static,
177{
178 fn or(self, other: impl Expr + 'static) -> FirstMatchOf {
180 let exprs: Vec<Box<dyn Expr>> = vec![Box::new(self), Box::new(other)];
181 FirstMatchOf::new(exprs)
182 }
183
184 fn and(self, other: impl Expr + 'static) -> All {
186 let exprs: Vec<Box<dyn Expr>> = vec![Box::new(self), Box::new(other)];
187 All::new(exprs)
188 }
189
190 fn but_not(self, other: impl Expr + 'static) -> All {
192 self.and(UnlessStep::new(other, |_tok: &Token, _src: &[char]| true))
193 }
194
195 fn or_longest(self, other: impl Expr + 'static) -> LongestMatchOf {
199 let exprs: Vec<Box<dyn Expr>> = vec![Box::new(self), Box::new(other)];
200 LongestMatchOf::new(exprs)
201 }
202}
203
204pub trait IntoBoxedExpr {
205 fn into_boxed(self) -> Box<dyn Expr>;
206}
207
208impl<T: Expr + 'static> IntoBoxedExpr for Box<T> {
209 fn into_boxed(self) -> Box<dyn Expr> {
210 self
211 }
212}
213
214impl IntoBoxedExpr for Box<dyn Expr> {
215 fn into_boxed(self) -> Box<dyn Expr> {
216 self
217 }
218}
219
220pub trait AsBoxedExpr {
221 fn into_boxed_expr(self) -> Box<dyn Expr>;
222}
223
224impl<T: Expr + 'static> AsBoxedExpr for Box<T> {
225 fn into_boxed_expr(self) -> Box<dyn Expr> {
226 self
227 }
228}
229
230impl AsBoxedExpr for Box<dyn Expr> {
231 fn into_boxed_expr(self) -> Box<dyn Expr> {
232 self
233 }
234}