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