jaq_core/load/
parse.rs

1//! Parsing.
2
3use super::lex::{StrPart, Tok, Token};
4use super::path::{self, Path};
5use super::{ops, prec_climb};
6use alloc::{boxed::Box, vec::Vec};
7use core::fmt::{self, Debug};
8
9/// Parse error, storing what we expected and what we got instead.
10pub type Error<S, T = S> = (Expect<S>, T);
11/// Parse error that stores what token it found.
12pub type TError<'t, S> = Error<S, Option<&'t Token<S>>>;
13
14/// Type of token that we expected.
15///
16/// Each variant is annoted with jq programs that trigger it.
17#[derive(Debug)]
18#[non_exhaustive]
19pub enum Expect<S> {
20    /// `if 0` (expected "then"), `reduce .` (expected "as"),
21    /// `0 as $x` (expected "|"), `{(.)}` (expected ":")
22    Just(S),
23    /// `label`, `break`
24    Var,
25    /// `0 as`
26    Pattern,
27    /// `if 0 then 0`
28    ElseOrEnd,
29    /// `0 as [$x;]`
30    CommaOrRBrack,
31    /// `{a;}`
32    CommaOrRBrace,
33    /// `f(0:)`
34    SemicolonOrRParen,
35    /// `` (empty input), `-`, `()`
36    Term,
37    /// `.[].`
38    Key,
39    /// `def`, `import "foo" as`
40    Ident,
41    /// `def f()`
42    Arg,
43    /// `import`
44    Str,
45    /// `0;`
46    Nothing,
47}
48
49impl<'a> Expect<&'a str> {
50    /// String representation of an expected token.
51    pub fn as_str(&self) -> &'a str {
52        match self {
53            Self::Just(s) => s,
54            Self::Var => "variable",
55            Self::Pattern => "pattern",
56            Self::ElseOrEnd => "else or end",
57            Self::CommaOrRBrack => "comma or right bracket",
58            Self::CommaOrRBrace => "comma or right brace",
59            Self::SemicolonOrRParen => "semicolon or right parenthesis",
60            Self::Term => "term",
61            Self::Key => "key",
62            Self::Ident => "identifier",
63            Self::Arg => "argument",
64            Self::Str => "string",
65            Self::Nothing => "nothing",
66        }
67    }
68}
69
70/// Output of a fallible parsing operation.
71pub type Result<'s, 't, T> = core::result::Result<T, TError<'t, &'s str>>;
72
73/// Parser for jq programs.
74pub struct Parser<'s, 't> {
75    i: core::slice::Iter<'t, Token<&'s str>>,
76    e: Vec<TError<'t, &'s str>>,
77}
78
79/// Function from value to stream of values, such as `.[] | add / length`.
80#[derive(Debug, Default)]
81pub enum Term<S> {
82    /// Identity, i.e. `.`
83    #[default]
84    Id,
85    /// Recursion (`..`)
86    Recurse,
87
88    /// Integer or floating-point number
89    Num(S),
90    /// String
91    ///
92    /// This consists of an optional format filter starting with `@` (such as `@text`),
93    /// followed by quoted string parts (such as `"Hello, \(.name)! \u263A"`).
94    Str(Option<S>, Vec<StrPart<S, Self>>),
95    /// Array, empty if `None`
96    Arr(Option<Box<Self>>),
97    /// Object, specifying its key-value pairs
98    Obj(Vec<(Self, Option<Self>)>),
99
100    /// Negation
101    Neg(Box<Self>),
102    /// Application, i.e. `l | r` if no string is given, else `l as $x | r`
103    Pipe(Box<Self>, Option<Pattern<S>>, Box<Self>),
104
105    /// Sequence of binary operations, e.g. `1 + 2 - 3 * 4`
106    BinOp(Box<Self>, BinaryOp, Box<Self>),
107
108    /// Control flow variable declaration, e.g. `label $x | ...`
109    Label(S, Box<Self>),
110    /// Break out from control flow to location variable, e.g. `break $x`
111    Break(S),
112
113    /// `reduce` and `foreach`, e.g. `reduce .[] as $x (0; .+$x)`
114    Fold(S, Box<Self>, Pattern<S>, Vec<Self>),
115    /// `try` and optional `catch`
116    TryCatch(Box<Self>, Option<Box<Self>>),
117    /// If-then-else
118    IfThenElse(Vec<(Self, Self)>, Option<Box<Self>>),
119
120    /// Local definition
121    Def(Vec<Def<S, Self>>, Box<Self>),
122    /// Call to another filter, e.g. `map(.+1)`
123    Call(S, Vec<Self>),
124    /// Variable, such as `$x` (including leading '$')
125    Var(S),
126
127    /// Path such as `.a`, `.[][]."b"`, `f[0]`
128    Path(Box<Self>, Path<Self>),
129}
130
131/// Variable-binding pattern, such as in `.[] as [$x, {$y, (f): $z}]`
132#[derive(Debug)]
133pub enum Pattern<S> {
134    /// Variable
135    Var(S),
136    /// Array
137    Arr(Vec<Self>),
138    /// Object
139    Obj(Vec<(Term<S>, Self)>),
140}
141
142/// Binary operators, such as `|`, `,`, `//`, ...
143#[derive(Debug)]
144pub enum BinaryOp {
145    /// Concatenation, i.e. `l, r`
146    Comma,
147    /// Alternation, i.e. `l // r`
148    Alt,
149    /// Logical disjunction, i.e. `l or r`
150    Or,
151    /// Logical conjunction, i.e. `l and r`
152    And,
153    /// Mathematical operation, e.g. `l + r`, `l - r`, ...
154    Math(ops::Math),
155    /// Comparison operation, e.g. `l == r`, `l <= r`, ...
156    Cmp(ops::Cmp),
157    /// Assignment, i.e. `l = r`,
158    Assign,
159    /// Update, i.e. `l |= r`
160    Update,
161    /// Mathematical assignment, i.e. `l += r`, `l -= r`, ...
162    /// (this is identical to `r as $x | l |= . + $x`, ...)
163    UpdateMath(ops::Math),
164    /// `l //= r`
165    UpdateAlt,
166}
167
168impl<S> Term<S> {
169    #[cfg(feature = "std")]
170    pub(crate) fn as_str(&self) -> Option<&S> {
171        if let Term::Str(None, s) = self {
172            if let [StrPart::Str(s)] = &s[..] {
173                return Some(s);
174            }
175        }
176        None
177    }
178
179    pub(crate) fn from_str(s: S) -> Self {
180        Self::Str(None, [StrPart::Str(s)].into())
181    }
182
183    /// `{}[]` returns zero values.
184    pub(crate) fn empty() -> Self {
185        // `[]`
186        let path = (path::Part::Range(None, None), path::Opt::Essential);
187        // `{}`
188        let obj = Term::Obj(Vec::new());
189        // `{}[]`
190        Term::Path(obj.into(), Path(Vec::from([path])))
191    }
192}
193
194impl<S> Pattern<S> {
195    pub(crate) fn vars(&self) -> Box<dyn Iterator<Item = &S> + '_> {
196        match self {
197            Pattern::Var(x) => Box::new(core::iter::once(x)),
198            Pattern::Arr(a) => Box::new(a.iter().flat_map(|p| p.vars())),
199            Pattern::Obj(o) => Box::new(o.iter().flat_map(|(_k, p)| p.vars())),
200        }
201    }
202}
203
204impl<'s, 't> Parser<'s, 't> {
205    /// Initialise a new parser on a sequence of [`Token`]s.
206    #[must_use]
207    pub fn new(i: &'t [Token<&'s str>]) -> Self {
208        Self {
209            i: i.iter(),
210            e: Vec::new(),
211        }
212    }
213
214    /// Parse tokens with the given function.
215    ///
216    /// Returns [`Ok`] if the function consumes the whole output without producing any error.
217    pub fn parse<T: Default, F>(mut self, f: F) -> core::result::Result<T, Vec<TError<'t, &'s str>>>
218    where
219        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
220    {
221        let y = self.finish("", f);
222        if self.e.is_empty() {
223            Ok(y)
224        } else {
225            Err(self.e)
226        }
227    }
228
229    /// Verifies that the remaining input tokens correspond to the given string.
230    fn verify_last(&mut self, last: &'static str) -> Result<'s, 't, ()> {
231        match (self.i.as_slice(), last) {
232            ([], "") => Ok(()),
233            ([Token(c, _)], last) if *c == last => Ok(()),
234            ([], _) => Err((Expect::Just(last), None)),
235            ([next, ..], "") => Err((Expect::Nothing, Some(next))),
236            ([next, ..], _) => Err((Expect::Just(last), Some(next))),
237        }
238    }
239
240    /// Run given parse function with given tokens, then reset tokens to previous tokens.
241    fn with_tok<T>(&mut self, tokens: &'t [Token<&'s str>], f: impl FnOnce(&mut Self) -> T) -> T {
242        let i = core::mem::replace(&mut self.i, tokens.iter());
243        let y = f(self);
244        self.i = i;
245        y
246    }
247
248    /// Parse with given function, then
249    /// ensure that remaining input tokens correspond to `last`, and
250    /// return default if any error occurred.
251    fn finish<T: Default, F>(&mut self, last: &'static str, f: F) -> T
252    where
253        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
254    {
255        f(self)
256            .and_then(|y| {
257                self.verify_last(last)?;
258                Ok(y)
259            })
260            .unwrap_or_else(|e| {
261                self.e.push(e);
262                T::default()
263            })
264    }
265
266    fn with<T: Default, F>(&mut self, tokens: &'t [Token<&'s str>], last: &'static str, f: F) -> T
267    where
268        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
269    {
270        self.with_tok(tokens, |p| p.finish(last, f))
271    }
272
273    /// Parse with the given function, and rewind input if it returns `None`.
274    fn maybe<T>(&mut self, f: impl Fn(&mut Self) -> Option<T>) -> Option<T> {
275        let i = self.i.clone();
276        let y = f(self);
277        // rewind to previous state in case of non-match
278        if y.is_none() {
279            self.i = i;
280        }
281        y
282    }
283
284    /// Parse with the given function, and rewind input if it returns `Ok(None)`.
285    fn try_maybe<T, F>(&mut self, f: F) -> Result<'s, 't, Option<T>>
286    where
287        F: Fn(&mut Self) -> Result<'s, 't, Option<T>>,
288    {
289        let i = self.i.clone();
290        let y = f(self)?;
291        // rewind to previous state in case of non-match
292        if y.is_none() {
293            self.i = i;
294        }
295        Ok(y)
296    }
297
298    fn many1<T>(
299        &mut self,
300        f: impl Fn(&mut Self) -> Result<'s, 't, T>,
301        sep: &'s str,
302        allow_trailing_sep: bool,
303        last: &'s str,
304        expect: Expect<&'s str>,
305    ) -> Result<'s, 't, Vec<T>> {
306        let mut y = Vec::from([f(self)?]);
307        let get_last = |p: &mut Self| p.i.next().filter(|Token(s, _)| *s == last);
308        let next_last = |p: &mut Self| allow_trailing_sep && p.maybe(get_last).is_some();
309        loop {
310            match self.i.next() {
311                Some(Token(s, _)) if *s == last => break,
312                Some(Token(s, _)) if *s == sep && next_last(self) => break,
313                Some(Token(s, _)) if *s == sep => y.push(f(self)?),
314                next => return Err((expect, next)),
315            }
316        }
317        Ok(y)
318    }
319
320    /// Parse sequence of shape `f ("," f)* ","? "}"`.
321    fn obj_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
322    where
323        F: Fn(&mut Self) -> Result<'s, 't, T>,
324    {
325        self.many1(f, ",", true, "}", Expect::CommaOrRBrace)
326    }
327
328    /// Parse `("(" arg (";" arg)* ")")?`.
329    fn args<T>(&mut self, f: fn(&mut Self) -> Result<'s, 't, T>) -> Vec<T> {
330        self.maybe(|p| match p.i.next() {
331            Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
332                Some(p.with(tokens, "", |p| {
333                    p.many1(f, ";", false, ")", Expect::SemicolonOrRParen)
334                }))
335            }
336            _ => None,
337        })
338        .unwrap_or_default()
339    }
340
341    /// Parse a binary operator, including `,` if `with_comma` is true.
342    fn op(&mut self, with_comma: bool) -> Option<BinaryOp> {
343        use ops::{Cmp, Math};
344        self.maybe(|p| match p.i.next() {
345            Some(Token(s, _)) => Some(match *s {
346                "," if with_comma => BinaryOp::Comma,
347                "+" => BinaryOp::Math(Math::Add),
348                "-" => BinaryOp::Math(Math::Sub),
349                "*" => BinaryOp::Math(Math::Mul),
350                "/" => BinaryOp::Math(Math::Div),
351                "%" => BinaryOp::Math(Math::Rem),
352                "=" => BinaryOp::Assign,
353                "|=" => BinaryOp::Update,
354                "+=" => BinaryOp::UpdateMath(Math::Add),
355                "-=" => BinaryOp::UpdateMath(Math::Sub),
356                "*=" => BinaryOp::UpdateMath(Math::Mul),
357                "/=" => BinaryOp::UpdateMath(Math::Div),
358                "%=" => BinaryOp::UpdateMath(Math::Rem),
359                "<" => BinaryOp::Cmp(Cmp::Lt),
360                ">" => BinaryOp::Cmp(Cmp::Gt),
361                "<=" => BinaryOp::Cmp(Cmp::Le),
362                ">=" => BinaryOp::Cmp(Cmp::Ge),
363                "==" => BinaryOp::Cmp(Cmp::Eq),
364                "!=" => BinaryOp::Cmp(Cmp::Ne),
365                "//" => BinaryOp::Alt,
366                "//=" => BinaryOp::UpdateAlt,
367                "or" => BinaryOp::Or,
368                "and" => BinaryOp::And,
369                _ => return None,
370            }),
371            None => None,
372        })
373    }
374
375    /// If the next token corresponds to `c`, return its string and advance input.
376    fn char0(&mut self, c: char) -> Option<&'s str> {
377        self.maybe(|p| match p.i.next() {
378            Some(Token(s, _)) if s.chars().eq([c]) => Some(*s),
379            _ => None,
380        })
381    }
382
383    /// If the next token starts with `.`, but is not `..`,
384    /// return the string after the initial `.` and advance input.
385    ///
386    /// This matches `.` and `.key`, where `key` is any valid identifier that matches
387    /// `[a-zA-Z_][a-zA-Z0-9_]*`.
388    fn dot(&mut self) -> Option<&'s str> {
389        self.maybe(|p| match p.i.next() {
390            Some(Token(c, _)) if *c != ".." => c.strip_prefix('.'),
391            _ => None,
392        })
393    }
394
395    fn terminated<T, F>(&mut self, f: F) -> Result<'s, 't, T>
396    where
397        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
398    {
399        let y = f(self)?;
400        self.just(";")?;
401        Ok(y)
402    }
403
404    fn just(&mut self, c: &'static str) -> Result<'s, 't, &'s str> {
405        match self.i.next() {
406            Some(Token(s, _)) if *s == c => Ok(*s),
407            next => Err((Expect::Just(c), next)),
408        }
409    }
410
411    fn var(&mut self) -> Result<'s, 't, &'s str> {
412        match self.i.next() {
413            Some(Token(x, Tok::Var)) => Ok(*x),
414            next => Err((Expect::Var, next)),
415        }
416    }
417
418    fn pattern(&mut self) -> Result<'s, 't, Pattern<&'s str>> {
419        match self.i.next() {
420            Some(Token(x, Tok::Var)) => Ok(Pattern::Var(*x)),
421            next @ Some(Token(full, Tok::Block(tokens))) => match &full[..1] {
422                "[" => Ok(Pattern::Arr(self.with(tokens, "", |p| {
423                    p.many1(Self::pattern, ",", false, "]", Expect::CommaOrRBrack)
424                }))),
425                "{" => Ok(Pattern::Obj(
426                    self.with(tokens, "", |p| p.obj_items(Self::pat_obj_entry)),
427                )),
428                _ => Err((Expect::Pattern, next)),
429            },
430            next => Err((Expect::Pattern, next)),
431        }
432    }
433
434    /// Parse a term.
435    ///
436    /// Only if `with_comma` is true, the parsed term may be of the shape `t, u`.
437    /// This matters for the parsing of object values, such as `{k1: v1, k2: v2}`:
438    /// if we would permit terms of the shape `t, u` inside objects,
439    /// then this would be parsed like `{k1: (v1, k2): v2}`, which is invalid.
440    fn term_with_comma(&mut self, with_comma: bool) -> Result<'s, 't, Term<&'s str>> {
441        let head = self.atom()?;
442        let tail = core::iter::from_fn(|| self.op(with_comma).map(|op| Ok((op, self.atom()?))))
443            .collect::<Result<Vec<_>>>()?;
444        let tm = prec_climb::climb(head, tail);
445
446        let pipe = self.try_maybe(|p| match p.i.next() {
447            Some(Token("|", _)) => Ok(Some(None)),
448            Some(Token("as", _)) => {
449                let x = p.pattern()?;
450                p.just("|")?;
451                Ok(Some(Some(x)))
452            }
453            _ => Ok(None),
454        })?;
455        Ok(match pipe {
456            None => tm,
457            Some(x) => Term::Pipe(Box::new(tm), x, Box::new(self.term_with_comma(with_comma)?)),
458        })
459    }
460
461    /// Parse an atomic term.
462    ///
463    /// A term `t` is atomic if and only if `try t catch 0` is syntactically correct.
464    /// For example, the term `1 + 2` is not atomic, because `try 1 + 2 catch 0` is invalid.
465    /// However, the term `.[]` is atomic, because `try .[] catch 0` is valid.
466    fn atom(&mut self) -> Result<'s, 't, Term<&'s str>> {
467        let tm = match self.i.next() {
468            Some(Token("-", _)) => Term::Neg(Box::new(self.atom()?)),
469            Some(Token("def", _)) => {
470                let head = self.def_tail()?;
471                let tail = self.defs()?;
472                let tm = self.term()?;
473                Term::Def(core::iter::once(head).chain(tail).collect(), Box::new(tm))
474            }
475            Some(Token("if", _)) => {
476                let if_then = |p: &mut Self| -> Result<_> {
477                    let if_ = p.term()?;
478                    p.just("then")?;
479                    Ok((if_, p.term()?))
480                };
481                let mut if_thens = Vec::from([if_then(self)?]);
482                let else_ = loop {
483                    match self.i.next() {
484                        Some(Token("elif", _)) => if_thens.push(if_then(self)?),
485                        Some(Token("else", _)) => {
486                            let else_ = self.term()?;
487                            self.just("end")?;
488                            break Some(else_);
489                        }
490                        Some(Token("end", _)) => break None,
491                        next => return Err((Expect::ElseOrEnd, next)),
492                    }
493                };
494                Term::IfThenElse(if_thens, else_.map(Box::new))
495            }
496            Some(Token("try", _)) => {
497                let try_ = self.atom()?;
498                let catch = self.try_maybe(|p| match p.i.next() {
499                    Some(Token("catch", _)) => Ok(Some(p.atom()?)),
500                    _ => Ok(None),
501                })?;
502                Term::TryCatch(Box::new(try_), catch.map(Box::new))
503            }
504            Some(Token("label", _)) => {
505                let x = self.var()?;
506                self.just("|")?;
507                let tm = self.term()?;
508                Term::Label(x, Box::new(tm))
509            }
510            Some(Token("break", _)) => Term::Break(self.var()?),
511            Some(Token(fold @ ("reduce" | "foreach"), _)) => {
512                let xs = self.atom()?;
513                self.just("as")?;
514                let x = self.pattern()?;
515                let args = self.args(Self::term);
516                Term::Fold(*fold, Box::new(xs), x, args)
517            }
518            Some(Token(id, Tok::Var)) => Term::Var(*id),
519            Some(Token(id, Tok::Fmt)) => {
520                let s = self.maybe(|p| match p.i.next() {
521                    Some(Token(_, Tok::Str(parts))) => Some(p.str_parts(parts)),
522                    _ => None,
523                });
524                match s {
525                    None => Term::Call(*id, self.args(Self::term)),
526                    Some(parts) => Term::Str(Some(*id), parts),
527                }
528            }
529            Some(Token(id, Tok::Word)) => Term::Call(*id, self.args(Self::term)),
530            Some(Token("..", _)) => Term::Recurse,
531            Some(Token(c, Tok::Sym)) if c.starts_with('.') => {
532                let key = if c.len() > 1 {
533                    Some(Term::from_str(&c[1..]))
534                } else {
535                    // TODO: this returns None on things like "@json .",
536                    // whereas it should return an error instead
537                    self.maybe(|p| p.str_key().ok())
538                };
539
540                if let Some(key) = key {
541                    let head = (path::Part::Index(key), self.opt());
542                    let path = core::iter::once(head).chain(self.path()?.0).collect();
543                    Term::Path(Box::new(Term::Id), Path(path))
544                } else {
545                    Term::Id
546                }
547            }
548            Some(Token(n, Tok::Num)) => Term::Num(*n),
549            Some(Token(full, Tok::Block(tokens))) => match &full[..1] {
550                "[" if matches!(tokens[..], [Token("]", _)]) => Term::Arr(None),
551                "{" if matches!(tokens[..], [Token("}", _)]) => Term::Obj(Vec::new()),
552                "[" => Term::Arr(Some(Box::new(self.with(tokens, "]", Self::term)))),
553                "{" => self.with(tokens, "", |p| p.obj_items(Self::obj_entry).map(Term::Obj)),
554                "(" => self.with(tokens, ")", Self::term),
555                _ => panic!(),
556            },
557            Some(Token(_, Tok::Str(parts))) => Term::Str(None, self.str_parts(parts)),
558            next => return Err((Expect::Term, next)),
559        };
560
561        let tm = match self.opt() {
562            path::Opt::Optional => Term::TryCatch(Box::new(tm), None),
563            path::Opt::Essential => tm,
564        };
565
566        let path = self.path()?;
567        Ok(if path.0.is_empty() {
568            tm
569        } else {
570            Term::Path(Box::new(tm), path)
571        })
572    }
573
574    /// Parse a term such as `.[] | .+1`.
575    pub fn term(&mut self) -> Result<'s, 't, Term<&'s str>> {
576        self.term_with_comma(true)
577    }
578
579    /// Parse a pattern object entry.
580    ///
581    /// Examples:
582    ///
583    /// * `$x`
584    /// * `(f): pat`
585    /// * ` a : pat`
586    /// * `"a": pat`
587    fn pat_obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Pattern<&'s str>)> {
588        let i = self.i.clone();
589        let key = match self.i.next() {
590            Some(Token(x, Tok::Var)) => return Ok((Term::from_str(&x[1..]), Pattern::Var(x))),
591            Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
592                self.with(tokens, ")", Self::term)
593            }
594            Some(Token(id, Tok::Word)) if !id.contains("::") => Term::from_str(*id),
595            _ => {
596                self.i = i;
597                self.str_key()?
598            }
599        };
600        self.just(":")?;
601        Ok((key, self.pattern()?))
602    }
603
604    /// Parse an object entry.
605    ///
606    /// An object is written as `{e1, ..., en}`, where `ei` is an object entry.
607    /// An example of an object entry is `"key": value` or `(key): value`.
608    /// When the key is a term surrounded by parentheses, a value is required,
609    /// otherwise the value may be omitted (e.g. `"key"` or `$x`).
610    fn obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Option<Term<&'s str>>)> {
611        let i = self.i.clone();
612        let key = match self.i.next() {
613            Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
614                let k = self.with(tokens, ")", Self::term);
615                self.just(":")?;
616                return Ok((k, Some(self.term_with_comma(false)?)));
617            }
618            Some(Token(id, Tok::Var)) => Term::Var(*id),
619            Some(Token(id, Tok::Word)) if !id.contains("::") => Term::from_str(*id),
620            _ => {
621                self.i = i;
622                self.str_key()?
623            }
624        };
625        let v = self.char0(':').map(|_| self.term_with_comma(false));
626        Ok((key, v.transpose()?))
627    }
628
629    fn str_parts(
630        &mut self,
631        parts: &'t [StrPart<&'s str, Token<&'s str>>],
632    ) -> Vec<StrPart<&'s str, Term<&'s str>>> {
633        let parts = parts.iter().map(|part| match part {
634            StrPart::Str(s) => StrPart::Str(*s),
635            StrPart::Term(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
636                StrPart::Term(self.with(tokens, ")", Self::term))
637            }
638            StrPart::Term(_) => unreachable!(),
639            StrPart::Char(c) => StrPart::Char(*c),
640        });
641        parts.collect()
642    }
643
644    fn path(&mut self) -> Result<'s, 't, Path<Term<&'s str>>> {
645        let mut path: Vec<_> = core::iter::from_fn(|| self.path_part_opt()).collect();
646        while let Some(key) = self.dot() {
647            let key = if key.is_empty() {
648                self.str_key()?
649            } else {
650                Term::from_str(key)
651            };
652            path.push((path::Part::Index(key), self.opt()));
653            path.extend(core::iter::from_fn(|| self.path_part_opt()));
654        }
655        Ok(Path(path))
656    }
657
658    /// Parse `[]`, `[t]`, `[t:]`, `[t:t]`, `[:t]` (all without brackets).
659    fn path_part(&mut self) -> Result<'s, 't, path::Part<Term<&'s str>>> {
660        use path::Part::{Index, Range};
661        let done = |p: &Self| matches!(p.i.as_slice(), [Token("]", _)]);
662        Ok(if done(self) {
663            Range(None, None)
664        } else if self.char0(':').is_some() {
665            Range(None, Some(self.term()?))
666        } else {
667            let tm = self.term()?;
668            if self.char0(':').is_some() {
669                if done(self) {
670                    Range(Some(tm), None)
671                } else {
672                    Range(Some(tm), Some(self.term()?))
673                }
674            } else {
675                Index(tm)
676            }
677        })
678    }
679
680    fn path_part_opt(&mut self) -> Option<(path::Part<Term<&'s str>>, path::Opt)> {
681        let part = self.maybe(|p| match p.i.next() {
682            Some(Token(full, Tok::Block(tokens))) if full.starts_with('[') => {
683                Some(p.with(tokens, "]", Self::path_part))
684            }
685            _ => None,
686        })?;
687        Some((part, self.opt()))
688    }
689
690    fn str_key(&mut self) -> Result<'s, 't, Term<&'s str>> {
691        match self.i.next() {
692            Some(Token(id, Tok::Fmt)) => match self.i.next() {
693                Some(Token(_, Tok::Str(parts))) => Ok(Term::Str(Some(*id), self.str_parts(parts))),
694                next => Err((Expect::Str, next)),
695            },
696            Some(Token(_, Tok::Str(parts))) => Ok(Term::Str(None, self.str_parts(parts))),
697            next => Err((Expect::Key, next)),
698        }
699    }
700
701    fn opt(&mut self) -> path::Opt {
702        let mut opt = path::Opt::Essential;
703        while self.char0('?').is_some() {
704            opt = path::Opt::Optional;
705        }
706        opt
707    }
708
709    /// Parse a sequence of definitions, such as `def x: 1; def y: 2;`.
710    pub fn defs(&mut self) -> Result<'s, 't, Vec<Def<&'s str>>> {
711        let head = |p: &mut Self| p.just("def").ok();
712        core::iter::from_fn(|| self.maybe(head).map(|_| self.def_tail())).collect()
713    }
714
715    /// Parse `name args ":" term ";"`.
716    fn def_tail(&mut self) -> Result<'s, 't, Def<&'s str, Term<&'s str>>> {
717        let name = match self.i.next() {
718            Some(Token(w, Tok::Word | Tok::Fmt)) if !w.contains("::") => w,
719            next => return Err((Expect::Ident, next)),
720        };
721        let args = self.args(|p| match p.i.next() {
722            Some(Token(w, Tok::Word | Tok::Var)) if !w.contains("::") => Ok(*w),
723            next => Err((Expect::Arg, next)),
724        });
725        self.just(":")?;
726
727        let body = self.term()?;
728        self.just(";")?;
729
730        Ok(Def { name, args, body })
731    }
732
733    fn bare_str(&mut self) -> Result<'s, 't, &'s str> {
734        match self.i.next() {
735            next @ Some(Token(_, Tok::Str(parts))) => match parts[..] {
736                [StrPart::Str(s)] => Ok(s),
737                _ => Err((Expect::Str, next)),
738            },
739            next => Err((Expect::Str, next)),
740        }
741    }
742
743    /// Parse what comes after an include / import.
744    fn dep(&mut self, import: bool) -> Result<'s, 't, Dep<&'s str>> {
745        let path = self.bare_str()?;
746        let name = import.then(|| {
747            self.just("as")?;
748            match self.i.next() {
749                Some(Token(v, Tok::Word | Tok::Var)) => Ok(*v),
750                next => Err((Expect::Ident, next)),
751            }
752        });
753        let name = name.transpose()?;
754        let meta = !matches!(self.i.as_slice(), [Token(";", _), ..]);
755        let meta = meta.then(|| self.term()).transpose()?;
756        Ok((path, name, meta))
757    }
758
759    /// Parse a module with a body returned by the given function.
760    pub(crate) fn module<B, F>(&mut self, f: F) -> Result<'s, 't, Module<&'s str, B>>
761    where
762        F: FnOnce(&mut Self) -> Result<'s, 't, B>,
763    {
764        let meta = self
765            .maybe(|p| match p.i.next() {
766                Some(Token("module", _)) => Some(p.terminated(Self::term)),
767                _ => None,
768            })
769            .transpose()?;
770
771        let deps = core::iter::from_fn(|| {
772            self.maybe(|p| match p.i.next() {
773                Some(Token("include", _)) => Some(p.terminated(|p| p.dep(false))),
774                Some(Token("import", _)) => Some(p.terminated(|p| p.dep(true))),
775                _ => None,
776            })
777        })
778        .collect::<Result<_>>()?;
779
780        let body = f(self)?;
781
782        Ok(Module { meta, deps, body })
783    }
784}
785
786type Dep<S> = (S, Option<S>, Option<Term<S>>);
787
788/// jq module, consisting of metadata, imports/includes, and a body.
789///
790/// Example (where the body is a sequence of definitions):
791///
792/// ~~~ jq
793/// module {};
794///
795/// import "foo" as foo;
796/// include "bar";
797///
798/// def iter: .[];
799/// ~~~
800#[derive(Debug, Default)]
801pub(crate) struct Module<S, B> {
802    pub meta: Option<Term<S>>,
803    pub deps: Vec<Dep<S>>,
804    pub body: B,
805}
806
807/// jq definition, consisting of a name, optional arguments, and a body.
808///
809/// Examples:
810///
811/// ~~~ jq
812/// def pi: 3.1415;
813/// def double($x): $x + $x;
814/// def map(f): [.[] | f];
815/// def recurse(f; cond): recurse(f | select(cond));
816/// ~~~
817// TODO v3.0: Make this just a tuple?
818pub struct Def<S, F = Term<S>> {
819    /// name, e.g. `"double"` or `"map"`
820    pub name: S,
821    /// arguments, e.g. `["$x"]`, `["f"]`, or `["f", "cond"]`
822    pub args: Vec<S>,
823    /// right-hand side, e.g. a term corresponding to `[.[] | f]`
824    pub body: F,
825}
826
827// required for Haskell interop
828impl<S: Debug, F: Debug> Debug for Def<S, F> {
829    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
830        write!(f, "({:?}, {:?}, {:?})", self.name, self.args, self.body)
831    }
832}
833
834impl<S, F> Def<S, F> {
835    pub(crate) fn new(name: S, args: Vec<S>, body: F) -> Self {
836        Self { name, args, body }
837    }
838}
839
840impl prec_climb::Op for BinaryOp {
841    fn precedence(&self) -> usize {
842        use ops::{Cmp, Math};
843        match self {
844            Self::Comma => 1,
845            Self::Assign | Self::Update | Self::UpdateMath(_) | Self::UpdateAlt => 2,
846            Self::Alt => 3,
847            Self::Or => Self::Alt.precedence() + 1,
848            Self::And => Self::Or.precedence() + 1,
849            Self::Cmp(Cmp::Eq | Cmp::Ne) => Self::And.precedence() + 1,
850            Self::Cmp(Cmp::Lt | Cmp::Gt | Cmp::Le | Cmp::Ge) => Self::And.precedence() + 2,
851            Self::Math(Math::Add | Math::Sub) => Self::And.precedence() + 3,
852            Self::Math(Math::Mul | Math::Div) => Self::Math(Math::Add).precedence() + 1,
853            Self::Math(Math::Rem) => Self::Math(Math::Mul).precedence() + 1,
854        }
855    }
856
857    fn associativity(&self) -> prec_climb::Associativity {
858        use prec_climb::Associativity;
859        match self {
860            Self::Assign | Self::Update | Self::UpdateMath(_) | Self::UpdateAlt => {
861                Associativity::Right
862            }
863            _ => Associativity::Left,
864        }
865    }
866}
867
868impl<S> prec_climb::Expr<BinaryOp> for Term<S> {
869    fn from_op(lhs: Self, op: BinaryOp, rhs: Self) -> Self {
870        Self::BinOp(Box::new(lhs), op, Box::new(rhs))
871    }
872}