layered_nlp/ll_line/
x.rs

1//! # Matcher pieces
2
3mod all;
4mod any_of;
5mod attr;
6mod attr_eq;
7mod functions;
8mod seq;
9mod token_has_any;
10mod token_text;
11
12pub use all::{All, All2, All3};
13pub use any_of::{AnyOf, AnyOf2, AnyOf2Matcher, AnyOf3, AnyOf3Matcher};
14pub use attr::Attr;
15pub use attr_eq::AttrEq;
16pub use functions::{all, any_of, attr, attr_eq, seq, token_has_any, token_text, whitespace};
17pub use seq::{Seq, Seq2, Seq3};
18pub use token_has_any::TokenHasAny;
19pub use token_text::TokenText;
20
21use super::{LLLine, LLToken, LToken};
22
23/// Examples: Attr, AttrEq
24pub trait XMatch<'l> {
25    /// Usually must be [Copy] so it's compatible with any multi-matchers.
26    /// The Out must be copied in the event of "cartesian" product scenarios where multi-matchers
27    /// return multiple combinations of their inner matchers' Out.
28    ///
29    /// This usually isn't a big deal to implement, since most Out values will be a reference
30    /// like `&'l Tag`, and all references in Rust are [Copy].
31    type Out: Copy;
32
33    fn go<M>(&self, direction: &M, ll_line: &'l LLLine) -> Vec<(Self::Out, ToIdx)>
34    where
35        M: XDirection<'l>;
36}
37
38#[derive(PartialEq, Eq, Clone, Copy)]
39pub struct ToIdx(pub(crate) usize);
40
41pub trait XDirection<'l>
42where
43    Self: Sized,
44{
45    // hmm... succeeding, next_after_idx? Consolidate boundary checking?
46    // #[derive(Debug)]
47    // pub struct OutOfBoundsError;
48    // /// Includes bounds checking, returns None if out of bounds
49    // fn from_idx(ll_line: &'l LLLine, idx: usize) -> Result<Self, OutOfBoundsError> {
50    //     todo!()
51    // }
52    fn attr<T: 'static>(&self, ll_line: &'l LLLine) -> Vec<(&'l T, ToIdx)>;
53    fn attr_eq<T: 'static + PartialEq>(&self, equals: &T, ll_line: &'l LLLine) -> Vec<((), ToIdx)>;
54    fn token_attr_one_of<T: 'static + PartialEq>(
55        &self,
56        set: &[T],
57        ll_line: &'l LLLine,
58    ) -> Vec<(&'l T, ToIdx)>;
59    /// If the next token is Text, return the inner string slice
60    fn text_token(&self, ll_line: &'l LLLine) -> Option<(&'l str, ToIdx)>;
61    fn after(&self, idx: usize, ll_line: &'l LLLine) -> Option<Self>
62    where
63        Self: Sized;
64}
65
66pub(crate) struct XForwards {
67    pub(super) from_idx: usize,
68}
69
70// TODO:
71//        ╰─╯Amount(1000.25)
72//  ╰───╯Person(A)
73//                 ╰───╯Person(B)
74//           ╰───╯VerbPhrase
75// selection
76//  .find_by(attr::<Clause>())
77//  .iter ... .map
78//      .contains_in_any_order(&(multiple::<Person, 2>(), attr::<Amount>(), attr::<VerbPhrase>()))
79//        -> Vec of 2 -> Full original selection
80//             - ([&Person(A), &Person(B)], &Amount, &VerbPhrase)
81// pub(crate) struct XContains {
82//     pub(super) start_idx: usize,
83//     pub(super) end_idx: usize,
84// }
85
86impl<'l> XDirection<'l> for XForwards {
87    fn attr_eq<T: 'static + PartialEq>(&self, equals: &T, ll_line: &'l LLLine) -> Vec<((), ToIdx)> {
88        ll_line
89            .attrs
90            .starts_at
91            .get(self.from_idx)
92            .expect("Huh... match_forwards was at the end")
93            .get::<T>()
94            .iter()
95            .flat_map(|range| {
96                ll_line
97                    .attrs
98                    .values
99                    .get(&range)
100                    .unwrap()
101                    .get::<T>()
102                    .iter()
103                    .filter_map(move |val| {
104                        if val == equals {
105                            Some(((), ToIdx(range.1)))
106                        } else {
107                            None
108                        }
109                    })
110            })
111            .collect()
112    }
113
114    fn attr<T: 'static>(&self, ll_line: &'l LLLine) -> Vec<(&'l T, ToIdx)> {
115        ll_line
116            .attrs
117            .starts_at
118            .get(self.from_idx)
119            .expect("Huh... match_forwards was at the end")
120            .get::<T>()
121            .iter()
122            .flat_map(|range| {
123                ll_line
124                    .attrs
125                    .values
126                    .get(&range)
127                    .unwrap()
128                    .get::<T>()
129                    .iter()
130                    .map(move |val| (val, ToIdx(range.1)))
131            })
132            .collect()
133    }
134
135    fn token_attr_one_of<T: 'static + PartialEq>(
136        &self,
137        set: &[T],
138        ll_line: &'l LLLine,
139    ) -> Vec<(&'l T, ToIdx)> {
140        // [ ... ] - Current Selection
141        //        [ ... ] - Trying to match Attr
142        ll_line
143            .attrs
144            .values
145            .get(&(self.from_idx, self.from_idx))
146            .expect("Huh... match_forwards was at the end")
147            .get::<T>()
148            .iter()
149            .filter_map(|value| {
150                if set.contains(value) {
151                    Some((value, ToIdx(self.from_idx)))
152                } else {
153                    None
154                }
155            })
156            .collect()
157    }
158
159    fn text_token(&self, ll_line: &'l LLLine) -> Option<(&'l str, ToIdx)> {
160        // [ ... ] - Current Selection
161        //        [ ... ] - Trying to match Attr
162        match ll_line
163            .ll_tokens
164            .get(self.from_idx)
165            .expect("Huh... XForwards::text_token was out of LLLine")
166        {
167            LLToken {
168                token: LToken::Text(s, _),
169                ..
170            } => Some((s, ToIdx(self.from_idx))),
171            _ => None,
172        }
173    }
174
175    fn after(&self, idx: usize, ll_line: &'l LLLine) -> Option<Self> {
176        let next_idx = idx + 1;
177        if next_idx < ll_line.ll_tokens.len() {
178            Some(XForwards { from_idx: next_idx })
179        } else {
180            None
181        }
182    }
183}
184
185pub(crate) struct XBackwards {
186    pub(super) from_idx: usize,
187}
188
189impl<'l> XDirection<'l> for XBackwards {
190    fn attr_eq<T: 'static + PartialEq>(&self, equals: &T, ll_line: &'l LLLine) -> Vec<((), ToIdx)> {
191        //        [ ... ] - Current Selection
192        // [ ... ] - Trying to match Attr
193        //   [...] - Trying to match Attr
194        ll_line
195            .attrs
196            .ends_at
197            .get(self.from_idx)
198            .expect("Huh... match_backwards was out of LLLine")
199            .get::<T>()
200            .iter()
201            .flat_map(|range| {
202                ll_line
203                    .attrs
204                    .values
205                    .get(&range)
206                    .unwrap()
207                    .get::<T>()
208                    .iter()
209                    .filter_map(move |val| {
210                        if val == equals {
211                            Some(((), ToIdx(range.0)))
212                        } else {
213                            None
214                        }
215                    })
216            })
217            .collect()
218    }
219
220    fn attr<T: 'static>(&self, ll_line: &'l LLLine) -> Vec<(&'l T, ToIdx)> {
221        //        [ ... ] - Current Selection
222        // [ ... ] - Trying to match Attr
223        //   [...] - Trying to match Attr
224        ll_line
225            .attrs
226            .ends_at
227            .get(self.from_idx)
228            .expect("Huh... Backwards::next_attr was at the start")
229            .get::<T>()
230            .iter()
231            .flat_map(|range| {
232                ll_line
233                    .attrs
234                    .values
235                    .get(&range)
236                    .unwrap()
237                    .get::<T>()
238                    .iter()
239                    .map(move |val| (val, ToIdx(range.0)))
240            })
241            .collect()
242    }
243
244    fn token_attr_one_of<T: 'static + PartialEq>(
245        &self,
246        set: &[T],
247        ll_line: &'l LLLine,
248    ) -> Vec<(&'l T, ToIdx)> {
249        //        [ ... ] - Current Selection
250        // [ ... ] - Trying to match Attr
251        //   [...] - Trying to match Attr
252        ll_line
253            .attrs
254            .ends_at
255            .get(self.from_idx)
256            .expect("Huh... Backwards::next_attr was at the start")
257            .get::<T>()
258            .iter()
259            .flat_map(|range| {
260                ll_line
261                    .attrs
262                    .values
263                    .get(&range)
264                    .unwrap()
265                    .get::<T>()
266                    .iter()
267                    .filter_map(move |val| {
268                        if set.contains(&val) {
269                            Some((val, ToIdx(range.0)))
270                        } else {
271                            None
272                        }
273                    })
274            })
275            .collect()
276    }
277
278    fn text_token(&self, ll_line: &'l LLLine) -> Option<(&'l str, ToIdx)> {
279        ll_line
280            .ll_tokens()
281            .get(self.from_idx)
282            .and_then(|token| match &token.token {
283                LToken::Text(text, _) => Some((text.as_str(), ToIdx(self.from_idx))),
284                LToken::Value => None,
285            })
286    }
287
288    fn after(&self, idx: usize, _: &'l LLLine) -> Option<Self> {
289        if idx > 0 {
290            Some(XBackwards {
291                from_idx: self.from_idx - 1,
292            })
293        } else {
294            None
295        }
296    }
297}