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