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