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