Skip to main content

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