1use crate::vm::{Callable, Func};
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6use core::fmt;
7use object_query::Query;
8use serde::Deserialize;
9
10#[derive(Debug)]
12pub enum MatchError {
13 Nlsd(nlsd::Error),
15 MismatchedStaticToken,
17 EmptyQuery,
19 UnknownQueryVar,
21 UnknownDataVar,
23 UnfilledVar,
25 UnexpectedEof,
27 ExpectedEof,
29 InvalidCtx,
31}
32
33pub struct Matcher<'a> {
35 src: &'a str,
36}
37
38impl<'a> Matcher<'a> {
39 pub fn new(src: &'a str) -> Self {
41 Self { src }
42 }
43
44 pub fn next_static(&mut self) -> Result<&'a str, MatchError> {
46 if let Ok((_, tok, rest)) = nl_parser::parse_token(self.src) {
47 self.src = rest;
48 Ok(tok)
49 } else {
50 Err(MatchError::UnexpectedEof)
51 }
52 }
53
54 pub fn next_query(&mut self) -> Result<Vec<Query<'a>>, MatchError> {
56 let mut nloq_de = nloq::Deserializer::from_str(self.src);
57 let query = nloq_de.query();
58 if query.is_empty() {
59 Err(MatchError::EmptyQuery)
60 } else {
61 self.src = nloq_de.rest();
62 Ok(query)
63 }
64 }
65
66 pub fn next_query_owned(&mut self) -> Result<Vec<Query<'static>>, MatchError> {
68 Ok(self
69 .next_query()?
70 .into_iter()
71 .map(|q| q.to_owned())
72 .collect())
73 }
74
75 pub fn next_data<T>(&mut self) -> Result<T, MatchError>
77 where
78 T: Deserialize<'a>,
79 {
80 let mut nlsd_de = nlsd::Deserializer::from_str(self.src);
81 let out = T::deserialize(&mut nlsd_de)?;
82 self.src = nlsd_de.rest();
83 Ok(out)
84 }
85
86 pub fn is_empty(&self) -> bool {
88 self.src.trim_start().is_empty()
89 }
90}
91
92pub trait Match<'a, C>: Sized {
95 fn match_str(ctx: &mut C, string: &'a str) -> Result<Self, MatchError>;
96}
97
98pub type FuncMatcher<'a, C> = fn(&mut C, &'a str) -> Result<Func<'a>, MatchError>;
100
101pub trait MatchFunc<'a, C>: 'a + Match<'a, C> + Callable {
103 fn match_func(ctx: &mut C, string: &'a str) -> Result<Func<'a>, MatchError> {
104 Self::match_str(ctx, string).map(|this| Box::new(this) as Box<dyn Callable>)
105 }
106}
107
108impl<'a, C, T> MatchFunc<'a, C> for T where T: 'a + Match<'a, C> + Callable {}
109
110impl From<nlsd::Error> for MatchError {
111 fn from(err: nlsd::Error) -> Self {
112 Self::Nlsd(err)
113 }
114}
115
116impl fmt::Display for MatchError {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 match self {
119 Self::Nlsd(err) => f.write_fmt(format_args!("NLSD err: {}", err)),
120 Self::MismatchedStaticToken => f.write_str("mismatched static token"),
121 Self::EmptyQuery => f.write_str("empty NLOQ query"),
122 Self::UnknownQueryVar => f.write_str("mismatched query variable name"),
123 Self::UnknownDataVar => f.write_str("mismatched data variable name"),
124 Self::UnfilledVar => f.write_str("variable not set"),
125 Self::UnexpectedEof => f.write_str("unexpected end of file"),
126 Self::ExpectedEof => f.write_str("clause has extra tokens"),
127 Self::InvalidCtx => f.write_str("context error when parsing"),
128 }
129 }
130}
131
132#[cfg(feature = "std")]
133impl std::error::Error for MatchError {}