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