jsonpath_plus/ast/
span.rs

1use core::ops;
2use std::fmt;
3
4/// A source span in a path. Can be used to reference the source location of tokens or syntax
5/// structures.
6#[cfg_attr(docsrs, doc(cfg(feature = "spanned")))]
7#[derive(Copy, Clone, PartialEq)]
8pub struct Span {
9    start: usize,
10    end: usize,
11}
12
13impl Span {
14    pub(crate) fn join(self, other: Span) -> Span {
15        let start = usize::min(self.start, other.start);
16        let end = usize::max(self.end, other.end);
17        Span { start, end }
18    }
19
20    pub(crate) fn start(&self) -> usize {
21        self.start
22    }
23
24    pub(crate) fn end(&self) -> usize {
25        self.end
26    }
27
28    /// Get the string slice of this span on the source string. Note the provided string must be
29    /// the whole source string for this method to be meaningful.
30    #[must_use]
31    pub fn get_span(self, source: &str) -> &str {
32        let start = source.char_indices().nth(self.start);
33
34        let end = source.char_indices().nth(self.end);
35
36        let ((start, _), (end, _)) = start.zip(end).expect("Invalid source for span");
37
38        &source[start..end]
39    }
40}
41
42impl From<ops::Range<usize>> for Span {
43    fn from(span: ops::Range<usize>) -> Self {
44        Span {
45            start: span.start,
46            end: span.end,
47        }
48    }
49}
50
51impl fmt::Debug for Span {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        f.debug_tuple("Span")
54            .field(&(self.start..self.end))
55            .finish()
56    }
57}
58
59impl chumsky::Span for Span {
60    type Context = ();
61    type Offset = usize;
62
63    fn new(_context: Self::Context, range: ops::Range<Self::Offset>) -> Self {
64        range.into()
65    }
66
67    fn context(&self) -> Self::Context {}
68
69    fn start(&self) -> Self::Offset {
70        self.start
71    }
72
73    fn end(&self) -> Self::Offset {
74        self.end
75    }
76}
77
78/// Trait for any item that has a retrievable source span
79#[cfg(feature = "spanned")]
80#[cfg_attr(docsrs, doc(cfg(feature = "spanned")))]
81pub trait Spanned {
82    /// Get the source span of this item
83    fn span(&self) -> Span;
84}
85
86#[cfg(feature = "spanned")]
87mod __impl {
88    use super::*;
89    use crate::ast::*;
90
91    // Atoms
92
93    impl Spanned for Ident {
94        fn span(&self) -> Span {
95            self.span
96        }
97    }
98
99    impl Spanned for BoolLit {
100        fn span(&self) -> Span {
101            self.span
102        }
103    }
104
105    impl Spanned for NullLit {
106        fn span(&self) -> Span {
107            self.span
108        }
109    }
110
111    impl Spanned for IntLit {
112        fn span(&self) -> Span {
113            self.span
114        }
115    }
116
117    impl Spanned for NonZeroIntLit {
118        fn span(&self) -> Span {
119            self.span
120        }
121    }
122
123    impl Spanned for StringContent {
124        fn span(&self) -> Span {
125            self.span
126        }
127    }
128
129    impl Spanned for SingleStringLit {
130        fn span(&self) -> Span {
131            self.start
132                .span()
133                .join(self.content.span())
134                .join(self.end.span())
135        }
136    }
137
138    impl Spanned for DoubleStringLit {
139        fn span(&self) -> Span {
140            self.start
141                .span()
142                .join(self.content.span())
143                .join(self.end.span())
144        }
145    }
146
147    impl Spanned for StringLit {
148        fn span(&self) -> Span {
149            match self {
150                StringLit::Single(s) => s.span(),
151                StringLit::Double(d) => d.span(),
152            }
153        }
154    }
155
156    // AST
157
158    impl Spanned for Path {
159        fn span(&self) -> Span {
160            let mut out = self.dollar.span();
161
162            for s in &self.segments {
163                out = out.join(s.span());
164            }
165
166            if let Some(t) = &self.tilde {
167                out = out.join(t.span());
168            }
169
170            out
171        }
172    }
173
174    impl Spanned for SubPath {
175        fn span(&self) -> Span {
176            let mut out = self.kind.span();
177
178            for s in &self.segments {
179                out = out.join(s.span());
180            }
181
182            if let Some(t) = &self.tilde {
183                out = out.join(t.span());
184            }
185
186            out
187        }
188    }
189
190    impl Spanned for PathKind {
191        fn span(&self) -> Span {
192            match self {
193                PathKind::Root(d) => d.span(),
194                PathKind::Relative(a) => a.span(),
195            }
196        }
197    }
198
199    impl Spanned for Segment {
200        fn span(&self) -> Span {
201            match self {
202                Segment::Bracket(b, i) => b.span().join(i.span()),
203                Segment::Dot(d, i) => d.span().join(i.span()),
204                Segment::Recursive(r, i) => i
205                    .as_ref()
206                    .map_or_else(|| r.span(), |i| r.span().join(i.span())),
207            }
208        }
209    }
210
211    impl Spanned for BracketSelector {
212        fn span(&self) -> Span {
213            match self {
214                BracketSelector::Union(comps) => {
215                    let mut out = comps[0].span();
216                    for comp in &comps[1..] {
217                        out = out.join(comp.span());
218                    }
219                    out
220                }
221                BracketSelector::StepRange(sr) => sr.span(),
222                BracketSelector::Range(r) => r.span(),
223                BracketSelector::Wildcard(s) => s.span(),
224                BracketSelector::Parent(c) => c.span(),
225                BracketSelector::Path(sp) => sp.span(),
226                BracketSelector::Filter(f) => f.span(),
227                BracketSelector::Literal(lit) => lit.span(),
228            }
229        }
230    }
231
232    impl Spanned for RawSelector {
233        fn span(&self) -> Span {
234            match self {
235                RawSelector::Wildcard(s) => s.span(),
236                RawSelector::Parent(c) => c.span(),
237                RawSelector::Name(i) => i.span(),
238            }
239        }
240    }
241
242    impl Spanned for UnionComponent {
243        fn span(&self) -> Span {
244            match self {
245                UnionComponent::StepRange(sr) => sr.span(),
246                UnionComponent::Range(r) => r.span(),
247                UnionComponent::Parent(c) => c.span(),
248                UnionComponent::Path(sp) => sp.span(),
249                UnionComponent::Filter(f) => f.span(),
250                UnionComponent::Literal(lit) => lit.span(),
251            }
252        }
253    }
254
255    impl Spanned for StepRange {
256        fn span(&self) -> Span {
257            let mut out = self
258                .start
259                .as_ref()
260                .map_or_else(|| self.colon1.span(), |s| s.span().join(self.colon1.span()));
261
262            if let Some(end) = &self.end {
263                out = out.join(end.span());
264            }
265
266            out = out.join(self.colon2.span());
267
268            if let Some(step) = &self.step {
269                out = out.join(step.span());
270            }
271
272            out
273        }
274    }
275
276    impl Spanned for Range {
277        fn span(&self) -> Span {
278            let mut out = self
279                .start
280                .as_ref()
281                .map_or_else(|| self.colon.span(), |s| s.span().join(self.colon.span()));
282
283            if let Some(end) = &self.end {
284                out = out.join(end.span());
285            }
286
287            out
288        }
289    }
290
291    impl Spanned for BracketLit {
292        fn span(&self) -> Span {
293            match self {
294                BracketLit::Int(i) => i.span(),
295                BracketLit::String(s) => s.span(),
296            }
297        }
298    }
299
300    impl Spanned for Filter {
301        fn span(&self) -> Span {
302            self.question
303                .span()
304                .join(self.paren.span())
305                .join(self.inner.span())
306        }
307    }
308
309    impl Spanned for FilterExpr {
310        fn span(&self) -> Span {
311            match self {
312                FilterExpr::Unary(op, expr) => op.span().join(expr.span()),
313                FilterExpr::Binary(lhs, op, rhs) => lhs.span().join(op.span()).join(rhs.span()),
314                FilterExpr::Path(sp) => sp.span(),
315                FilterExpr::Lit(el) => el.span(),
316                FilterExpr::Parens(p, expr) => p.span().join(expr.span()),
317            }
318        }
319    }
320
321    impl Spanned for ExprLit {
322        fn span(&self) -> Span {
323            match self {
324                ExprLit::Int(i) => i.span(),
325                ExprLit::String(s) => s.span(),
326                ExprLit::Bool(b) => b.span(),
327                ExprLit::Null(n) => n.span(),
328            }
329        }
330    }
331
332    impl Spanned for UnOp {
333        fn span(&self) -> Span {
334            match self {
335                UnOp::Neg(d) => d.span(),
336                UnOp::Not(b) => b.span(),
337            }
338        }
339    }
340
341    impl Spanned for BinOp {
342        fn span(&self) -> Span {
343            match self {
344                BinOp::And(a) => a.span(),
345                BinOp::Or(p) => p.span(),
346                BinOp::Eq(e) => e.span(),
347                BinOp::Le(l) => l.span(),
348                BinOp::Lt(l) => l.span(),
349                BinOp::Gt(g) => g.span(),
350                BinOp::Ge(g) => g.span(),
351                BinOp::Add(p) => p.span(),
352                BinOp::Sub(d) => d.span(),
353                BinOp::Mul(s) => s.span(),
354                BinOp::Div(s) => s.span(),
355                BinOp::Rem(p) => p.span(),
356            }
357        }
358    }
359}