1#![cfg_attr(not(feature = "spanned"), allow(dead_code))]
6
7use core::num::NonZeroI64;
8
9mod error;
10mod eval;
11mod parse;
12mod span;
13#[cfg(test)]
14mod tests;
15mod token;
16
17pub use error::{FailReason, ParseFail};
18pub use span::Span;
19#[cfg(feature = "spanned")]
20pub use span::Spanned;
21
22type Input = char;
25type Error = ParseFail<char, ()>;
26
27pub struct Ident {
31 #[cfg(feature = "spanned")]
32 span: Span,
33 val: String,
34}
35
36impl Ident {
37 #[must_use]
39 pub fn as_str(&self) -> &str {
40 &self.val
41 }
42}
43
44pub struct BoolLit {
46 #[cfg(feature = "spanned")]
47 span: Span,
48 val: bool,
49}
50
51impl BoolLit {
52 #[must_use]
54 pub fn as_bool(&self) -> bool {
55 self.val
56 }
57}
58
59pub struct NullLit {
61 #[cfg(feature = "spanned")]
62 span: Span,
63}
64
65pub struct IntLit {
67 #[cfg(feature = "spanned")]
68 span: Span,
69 val: i64,
70}
71
72impl IntLit {
73 #[must_use]
75 pub fn as_int(&self) -> i64 {
76 self.val
77 }
78}
79
80pub struct NonZeroIntLit {
82 #[cfg(feature = "spanned")]
83 span: Span,
84 val: NonZeroI64,
85}
86
87impl NonZeroIntLit {
88 #[must_use]
90 pub fn as_int(&self) -> NonZeroI64 {
91 self.val
92 }
93}
94
95struct StringContent {
96 #[cfg(feature = "spanned")]
97 span: Span,
98 val: String,
99}
100
101pub struct SingleStringLit {
103 start: token::SingleQuote,
104 content: StringContent,
105 end: token::SingleQuote,
106}
107
108impl SingleStringLit {
109 #[must_use]
111 pub fn as_str(&self) -> &str {
112 &self.content.val
113 }
114}
115
116pub struct DoubleStringLit {
118 start: token::DoubleQuote,
119 content: StringContent,
120 end: token::DoubleQuote,
121}
122
123impl DoubleStringLit {
124 #[must_use]
126 pub fn as_str(&self) -> &str {
127 &self.content.val
128 }
129}
130
131pub enum StringLit {
133 Single(SingleStringLit),
135 Double(DoubleStringLit),
137}
138
139impl StringLit {
140 #[must_use]
142 pub fn as_str(&self) -> &str {
143 match self {
144 StringLit::Single(s) => s.as_str(),
145 StringLit::Double(s) => s.as_str(),
146 }
147 }
148}
149
150#[must_use = "A path does nothing on its own, call `find` or `find_str` to evaluate the path on a \
155 value"]
156pub struct Path {
157 dollar: token::Dollar,
158 segments: Vec<Segment>,
159 tilde: Option<token::Tilde>,
160}
161
162impl Path {
163 #[must_use]
165 pub fn segments(&self) -> &[Segment] {
166 &self.segments
167 }
168}
169
170pub struct SubPath {
173 kind: PathKind,
174 segments: Vec<Segment>,
175 tilde: Option<token::Tilde>,
176}
177
178impl SubPath {
179 #[must_use]
181 pub fn kind(&self) -> &PathKind {
182 &self.kind
183 }
184
185 #[must_use]
187 pub fn segments(&self) -> &[Segment] {
188 &self.segments
189 }
190
191 #[must_use]
193 pub fn is_id(&self) -> bool {
194 self.tilde.is_some()
195 }
196}
197
198#[non_exhaustive]
200pub enum PathKind {
201 Root(token::Dollar),
203 Relative(token::At),
205}
206
207impl PathKind {
208 #[must_use]
210 pub fn is_root(&self) -> bool {
211 matches!(self, PathKind::Root(_))
212 }
213
214 #[must_use]
216 pub fn is_relative(&self) -> bool {
217 matches!(self, PathKind::Relative(_))
218 }
219}
220
221#[non_exhaustive]
223pub enum Segment {
224 Dot(token::Dot, RawSelector),
226 Bracket(token::Bracket, BracketSelector),
228 Recursive(token::DotDot, Option<RawSelector>),
230}
231
232#[non_exhaustive]
234pub enum RawSelector {
235 Wildcard(token::Star),
237 Parent(token::Caret),
239 Name(Ident),
241}
242
243pub struct StepRange {
246 start: Option<IntLit>,
247 colon1: token::Colon,
248 end: Option<IntLit>,
249 colon2: token::Colon,
250 step: Option<NonZeroIntLit>,
251}
252
253impl StepRange {
254 #[must_use]
256 pub fn start_lit(&self) -> Option<&IntLit> {
257 self.start.as_ref()
258 }
259
260 #[must_use]
262 pub fn end_lit(&self) -> Option<&IntLit> {
263 self.end.as_ref()
264 }
265
266 #[must_use]
268 pub fn step_lit(&self) -> Option<&NonZeroIntLit> {
269 self.step.as_ref()
270 }
271
272 #[must_use]
274 pub fn start(&self) -> Option<i64> {
275 self.start.as_ref().map(|a| a.as_int())
276 }
277
278 #[must_use]
280 pub fn end(&self) -> Option<i64> {
281 self.end.as_ref().map(|a| a.as_int())
282 }
283
284 #[must_use]
286 pub fn step(&self) -> Option<NonZeroI64> {
287 self.step.as_ref().map(|a| a.as_int())
288 }
289}
290
291pub struct Range {
293 start: Option<IntLit>,
294 colon: token::Colon,
295 end: Option<IntLit>,
296}
297
298impl Range {
299 #[must_use]
301 pub fn start_lit(&self) -> Option<&IntLit> {
302 self.start.as_ref()
303 }
304
305 #[must_use]
307 pub fn end_lit(&self) -> Option<&IntLit> {
308 self.end.as_ref()
309 }
310
311 #[must_use]
313 pub fn start(&self) -> Option<i64> {
314 self.start.as_ref().map(|a| a.as_int())
315 }
316
317 #[must_use]
319 pub fn end(&self) -> Option<i64> {
320 self.end.as_ref().map(|a| a.as_int())
321 }
322}
323
324#[non_exhaustive]
326pub enum UnionComponent {
327 StepRange(StepRange),
329 Range(Range),
331 Parent(token::Caret),
333 Path(SubPath),
335 Filter(Filter),
337 Literal(BracketLit),
339}
340
341impl TryFrom<BracketSelector> for UnionComponent {
342 type Error = ();
343
344 fn try_from(value: BracketSelector) -> Result<Self, Self::Error> {
345 Ok(match value {
346 BracketSelector::StepRange(sr) => UnionComponent::StepRange(sr),
347 BracketSelector::Range(r) => UnionComponent::Range(r),
348 BracketSelector::Parent(p) => UnionComponent::Parent(p),
349 BracketSelector::Path(p) => UnionComponent::Path(p),
350 BracketSelector::Filter(f) => UnionComponent::Filter(f),
351 BracketSelector::Literal(l) => UnionComponent::Literal(l),
352 _ => return Err(()),
353 })
354 }
355}
356
357#[non_exhaustive]
359pub enum BracketSelector {
360 Union(Vec<UnionComponent>),
362 StepRange(StepRange),
364 Range(Range),
366 Wildcard(token::Star),
368 Parent(token::Caret),
370 Path(SubPath),
372 Filter(Filter),
374 Literal(BracketLit),
376}
377
378#[non_exhaustive]
380pub enum BracketLit {
381 Int(IntLit),
383 String(StringLit),
385}
386
387impl BracketLit {
388 #[must_use]
390 pub fn is_int(&self) -> bool {
391 matches!(self, BracketLit::Int(_))
392 }
393
394 #[must_use]
396 pub fn is_str(&self) -> bool {
397 matches!(self, BracketLit::String(_))
398 }
399
400 #[must_use]
402 pub fn as_int(&self) -> Option<i64> {
403 if let BracketLit::Int(i) = self {
404 Some(i.as_int())
405 } else {
406 None
407 }
408 }
409
410 #[must_use]
412 pub fn as_str(&self) -> Option<&str> {
413 if let BracketLit::String(s) = self {
414 Some(s.as_str())
415 } else {
416 None
417 }
418 }
419}
420
421pub struct Filter {
423 question: token::Question,
424 paren: token::Paren,
425 inner: FilterExpr,
426}
427
428impl Filter {
429 #[must_use]
431 pub fn expression(&self) -> &FilterExpr {
432 &self.inner
433 }
434}
435
436#[non_exhaustive]
438pub enum ExprLit {
439 Int(IntLit),
441 String(StringLit),
443 Bool(BoolLit),
445 Null(NullLit),
447}
448
449impl ExprLit {
450 #[must_use]
452 pub fn is_int(&self) -> bool {
453 matches!(self, ExprLit::Int(_))
454 }
455
456 #[must_use]
458 pub fn is_str(&self) -> bool {
459 matches!(self, ExprLit::String(_))
460 }
461
462 #[must_use]
464 pub fn is_bool(&self) -> bool {
465 matches!(self, ExprLit::Bool(_))
466 }
467
468 #[must_use]
470 pub fn is_null(&self) -> bool {
471 matches!(self, ExprLit::Null(_))
472 }
473
474 #[must_use]
476 pub fn as_int(&self) -> Option<i64> {
477 if let ExprLit::Int(i) = self {
478 Some(i.as_int())
479 } else {
480 None
481 }
482 }
483
484 #[must_use]
486 pub fn as_str(&self) -> Option<&str> {
487 if let ExprLit::String(s) = self {
488 Some(s.as_str())
489 } else {
490 None
491 }
492 }
493
494 #[must_use]
496 pub fn as_bool(&self) -> Option<bool> {
497 if let ExprLit::Bool(s) = self {
498 Some(s.as_bool())
499 } else {
500 None
501 }
502 }
503}
504
505#[non_exhaustive]
507pub enum FilterExpr {
508 Unary(UnOp, Box<FilterExpr>),
510 Binary(Box<FilterExpr>, BinOp, Box<FilterExpr>),
512 Path(SubPath),
514 Lit(ExprLit),
516 Parens(token::Paren, Box<FilterExpr>),
518}
519
520#[non_exhaustive]
522pub enum UnOp {
523 Neg(token::Dash),
525 Not(token::Bang),
527}
528
529#[non_exhaustive]
531pub enum BinOp {
532 And(token::DoubleAnd),
534 Or(token::DoublePipe),
536
537 Eq(token::EqEq),
539 Le(token::LessEq),
541 Lt(token::LessThan),
543 Gt(token::GreaterThan),
545 Ge(token::GreaterEq),
547
548 Add(token::Plus),
550 Sub(token::Dash),
552 Mul(token::Star),
554 Div(token::RightSlash),
556 Rem(token::Percent),
558}