git_bug/query/parse/parser/
mod.rs1use super::tokenizer::{Token, TokenSpan, Tokenizer};
14use crate::query::{
15 ParseMode, Query,
16 parse::tokenizer::TokenKind,
17 queryable::{QueryKeyValue, Queryable},
18};
19
20pub mod relaxed;
21pub mod strict;
22
23#[derive(Debug, thiserror::Error)]
24pub enum Error<E: Queryable>
27where
28 <E::KeyValue as QueryKeyValue>::Err: std::fmt::Debug + std::fmt::Display,
29{
30 #[error(transparent)]
31 Strict(#[from] strict::Error<E>),
33
34 #[error(transparent)]
35 Relaxed(#[from] relaxed::Error<E>),
37}
38
39#[allow(clippy::trivially_copy_pass_by_ref)]
41fn format_unexpected_token(
42 expected: &TokenKind,
43 found: &Token,
44 f: &mut std::fmt::Formatter<'_>,
45) -> Result<(), std::fmt::Error> {
46 write!(
47 f,
48 "Expected token '{expected}' but got token '{found}' instead."
49 )
50}
51fn format_unknown_key<E: Queryable>(
52 err: &<E::KeyValue as QueryKeyValue>::Err,
53 key: &str,
54 _at: &TokenSpan,
55 f: &mut std::fmt::Formatter<'_>,
56) -> Result<(), std::fmt::Error>
57where
58 <E::KeyValue as QueryKeyValue>::Err: std::fmt::Debug + std::fmt::Display,
59{
60 write!(f, "The input stream countained a unknown key {key}: {err}")
61}
62
63#[allow(missing_docs)]
64pub mod parsing {
65 use crate::query::{
66 parse::{
67 parser::format_unexpected_token,
68 tokenizer::{Token, TokenKind, TokenSpan},
69 },
70 queryable::{QueryKeyValue, Queryable},
71 };
72
73 #[derive(Debug, thiserror::Error)]
74 pub enum Error<E: Queryable>
75 where
76 <E::KeyValue as QueryKeyValue>::Err: std::fmt::Debug + std::fmt::Display,
77 {
78 #[error(fmt = format_unexpected_token)]
79 UnexpectedToken { expected: TokenKind, found: Token },
80
81 #[error("The input stream countained a unknown key {key}: {err}")]
83 UnknownKey {
84 err: <E::KeyValue as QueryKeyValue>::Err,
86
87 key: String,
89
90 at: TokenSpan,
92 },
93 }
94}
95
96pub(crate) struct Parser<'a, E: Queryable> {
97 tokenizer: Tokenizer<'a>,
98 user_state: &'a <E::KeyValue as QueryKeyValue>::UserState,
99}
100
101impl<'a, E: Queryable> Parser<'a, E>
102where
103 <E::KeyValue as QueryKeyValue>::Err: std::fmt::Debug + std::fmt::Display,
104{
105 pub(crate) fn new(
106 user_state: &'a <E::KeyValue as QueryKeyValue>::UserState,
107 tokenizer: Tokenizer<'a>,
108 ) -> Self {
109 Self {
110 tokenizer,
111 user_state,
112 }
113 }
114
115 pub(crate) fn parse(&'a mut self, mode: ParseMode) -> Result<Query<E>, Error<E>> {
117 let matcher = match mode {
118 ParseMode::Strict => strict::Parser::parse(self)?,
119 ParseMode::Relaxed => relaxed::Parser::parse(self)?,
120 };
121
122 Ok(Query {
123 root: Some(matcher),
124 })
125 }
126
127 fn parse_key_from(
128 &self,
129 key_tokens: &[Token],
130 value: String,
131 value_tokens_end: usize,
132 ) -> Result<E::KeyValue, parsing::Error<E>> {
133 let key = key_tokens.iter().fold(String::new(), |mut acc, t| {
134 if let TokenKind::Char(ch) = t.kind {
135 acc.push(ch);
136 acc
137 } else {
138 unreachable!("We filtered by chars in the `take_while`");
139 }
140 });
141
142 E::KeyValue::from_key_value(self.user_state, &key, value).map_err(|err| {
143 parsing::Error::UnknownKey {
144 err,
145 key,
146 at: TokenSpan {
147 start: key_tokens.first().expect("Exists").span.start,
148 stop: value_tokens_end,
149 },
150 }
151 })
152 }
153
154 fn parse_value_from(tokens: &[Token]) -> String {
155 tokens.iter().fold(String::new(), |mut acc, t| {
156 if let TokenKind::Char(ch) = t.kind {
157 acc.push(ch);
158 acc
159 } else {
160 unreachable!("We filtered by Chars()s in the `take_while`");
161 }
162 })
163 }
164
165 fn expect(&mut self, expected: TokenKind) -> Result<Token, parsing::Error<E>> {
166 let next = self.tokenizer.next_token();
167 if next.kind == expected {
168 Ok(next)
169 } else {
170 Err(parsing::Error::UnexpectedToken {
171 expected,
172 found: next,
173 })
174 }
175 }
176
177 fn take_while<F>(&mut self, pred: F) -> Result<Vec<Token>, parsing::Error<E>>
178 where
179 F: Fn(TokenKind) -> bool,
180 {
181 let mut output = vec![];
182 loop {
183 let token = self.tokenizer.peek();
184
185 if !pred(token.kind) {
186 return Ok(output);
187 }
188
189 output.push(self.tokenizer.next_token());
190 }
191 }
192}
193
194#[cfg(test)]
195pub(crate) mod test {
196 macro_rules! query {
197 ($name:ident {
198 lhs: $lhs:tt,
199 rhs: $rhs:tt $(,)?
200 }) => {
201 Query {
202 root: Some($name {
203 lhs: Box::new(query!(@run $lhs)),
204 rhs: Box::new(query!(@run $rhs)),
205 })
206 }
207 };
208
209 (@run {$name:ident {
210 lhs: $lhs:tt,
211 rhs: $rhs:tt $(,)?
212 } $(,)?}) => {
213 $name {
214 lhs: Box::new(query!(@run $lhs)),
215 rhs: Box::new(query!(@run $rhs)),
216 }
217 };
218 (@run { Match(Key1 , $value:tt) }) => {
219 Match {
220 key_value: Key1($value),
221 }
222 };
223 (@run { Match(Key2 , $value:expr) }) => {
224 Match {
225 key_value: Key2($value.to_owned()),
226 }
227 };
228 (@run { Match(Key3 , $number:expr) }) => {
229 Match {
230 key_value: Key3 {
231 _value: $number,
232 original: stringify!($number).to_owned(),
233 },
234 }
235 };
236 }
237 pub(crate) use query;
238
239 use crate::query::{
240 Matcher, Query,
241 queryable::{QueryKeyValue, Queryable},
242 };
243
244 impl PartialEq for Query<QueryTestObj> {
245 fn eq(&self, other: &Self) -> bool {
246 if let Some(me) = &self.root {
247 if let Some(other) = &other.root {
248 me == other
249 } else {
250 false
251 }
252 } else {
253 self.root.is_none() && other.root.is_none()
254 }
255 }
256 }
257
258 impl PartialEq for Matcher<QueryTestObj> {
259 fn eq(&self, other: &Self) -> bool {
260 match self {
261 Matcher::Or {
262 lhs: me_lhs,
263 rhs: me_rhs,
264 } => match other {
265 Matcher::Or { lhs, rhs } => me_lhs == lhs && me_rhs == rhs,
266 Matcher::And { .. } | Matcher::Match { .. } => false,
267 },
268 Matcher::And {
269 lhs: me_lhs,
270 rhs: me_rhs,
271 } => match other {
272 Matcher::And { lhs, rhs } => me_lhs == lhs && me_rhs == rhs,
273 Matcher::Or { .. } | Matcher::Match { .. } => false,
274 },
275 Matcher::Match {
276 key_value: me_key_value,
277 } => match other {
278 Matcher::Or { .. } | Matcher::And { .. } => false,
279 Matcher::Match { key_value } => key_value == me_key_value,
280 },
281 }
282 }
283 }
284
285 #[derive(Debug)]
286 pub(crate) struct QueryTestObj;
287
288 impl Queryable for QueryTestObj {
289 type KeyValue = QueryTestKeyValue;
290
291 fn matches(&self, _key: &Self::KeyValue) -> bool {
292 true
293 }
294 }
295
296 #[derive(Debug, PartialEq, Eq, Clone)]
297 pub(crate) enum QueryTestKeyValue {
298 Key1(QueryTestKey1),
299 Key2(String),
300 Key3 { _value: u32, original: String },
301 }
302
303 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
304 pub(crate) enum QueryTestKey1 {
305 Value1,
306 Value2,
307 }
308
309 impl QueryKeyValue for QueryTestKeyValue {
310 type Err = QueryTestError;
311 type UserState = ();
312
313 fn from_key_value(
314 _user_state: &Self::UserState,
315 key: &str,
316 value: String,
317 ) -> Result<Self, Self::Err>
318 where
319 Self: Sized,
320 {
321 match key {
322 "key1" => Ok(Self::Key1(match value.as_str() {
323 "value1" => QueryTestKey1::Value1,
324 "value2" => QueryTestKey1::Value2,
325 other => todo!("{other}"),
326 })),
327 "key2" => Ok(Self::Key2(value)),
328 "key3" => Ok(Self::Key3 {
329 _value: value.parse().unwrap(),
330 original: value,
331 }),
332 other => todo!("{other}"),
333 }
334 }
335
336 fn from_value(_user_state: &Self::UserState, value: String) -> Result<Self, Self::Err>
337 where
338 Self: Sized,
339 {
340 Ok(Self::Key2(value))
341 }
342
343 fn to_key_and_value(&self) -> (&str, &str)
344 where
345 Self: Sized,
346 {
347 match self {
348 QueryTestKeyValue::Key1(query_test_key1) => {
349 let query_test_key1_str = match query_test_key1 {
350 QueryTestKey1::Value1 => "value1",
351 QueryTestKey1::Value2 => "value2",
352 };
353
354 ("key1", query_test_key1_str)
355 }
356 QueryTestKeyValue::Key2(val) => ("key2", val.as_str()),
357 QueryTestKeyValue::Key3 { original, .. } => ("key3", original.as_str()),
358 }
359 }
360 }
361
362 #[derive(Debug, thiserror::Error)]
363 pub(crate) enum QueryTestError {}
364}