jaq_syn/
parse.rs

1//! Parsing.
2
3use crate::lex::{StrPart, Token};
4use crate::path;
5use alloc::{boxed::Box, vec::Vec};
6
7/// Parse error, storing what we expected and what we got instead.
8pub type Error<S, T = S> = (Expect<S>, T);
9/// Parse error that stores what token it found.
10pub type TError<'t, S> = Error<S, Option<&'t Token<S>>>;
11
12type Path<T> = Vec<(path::Part<T>, path::Opt)>;
13
14/// Type of token that we expected.
15///
16/// Each variant is annoted with jq programs that trigger it.
17#[derive(Debug)]
18pub enum Expect<S> {
19    /// `if 0` (expected "then"), `reduce .` (expected "as")
20    Keyword(S),
21    /// `0 as $x` (expected "|"), `{(.)}` (expected ":")
22    Char(S),
23    /// `0 as`, `label`, `break`
24    Var,
25    /// `if 0 then 0`
26    ElseOrEnd,
27    /// `{a;}`
28    CommaOrRBrace,
29    /// `f(0:)`
30    SemicolonOrRParen,
31    /// `` (empty input), `-`, `()`
32    Term,
33    /// `.[].`
34    Key,
35    /// `def`, `import "foo" as`
36    Ident,
37    /// `def f()`
38    Arg,
39    /// `import`
40    Str,
41    /// `0;`
42    Nothing,
43}
44
45impl<'a> Expect<&'a str> {
46    /// String representation of an expected token.
47    pub fn as_str(&self) -> &'a str {
48        match self {
49            Self::Keyword(s) | Self::Char(s) => s,
50            Self::Var => "variable",
51            Self::ElseOrEnd => "else or end",
52            Self::CommaOrRBrace => "comma or right brace",
53            Self::SemicolonOrRParen => "semicolon or right parenthesis",
54            Self::Term => "term",
55            Self::Key => "key",
56            Self::Ident => "identifier",
57            Self::Arg => "argument",
58            Self::Str => "string",
59            Self::Nothing => "nothing",
60        }
61    }
62}
63
64/// Output of a fallible parsing operation.
65pub type Result<'s, 't, T> = core::result::Result<T, TError<'t, &'s str>>;
66
67/// Parser for jq programs.
68pub struct Parser<'s, 't> {
69    i: core::slice::Iter<'t, Token<&'s str>>,
70    e: Vec<TError<'t, &'s str>>,
71    /// names of fold-like filters, e.g. "reduce" and "foreach"
72    fold: &'s [&'s str],
73}
74
75/// Function from value to stream of values, such as `.[] | add / length`.
76#[derive(Debug, Default)]
77pub enum Term<S> {
78    /// Identity, i.e. `.`
79    #[default]
80    Id,
81    /// Recursion (`..`)
82    Recurse,
83
84    /// Integer or floating-point number
85    Num(S),
86    /// String
87    ///
88    /// This consists of an optional format filter starting with `@` (such as `@text`),
89    /// followed by quoted string parts (such as `"Hello, \(.name)! \u263A"`).
90    Str(Option<S>, Vec<StrPart<S, Self>>),
91    /// Array, empty if `None`
92    Arr(Option<Box<Self>>),
93    /// Object, specifying its key-value pairs
94    Obj(Vec<(Self, Option<Self>)>),
95
96    /// Negation
97    Neg(Box<Self>),
98    /// Application, i.e. `l | r` if no string is given, else `l as $x | r`
99    Pipe(Box<Self>, Option<S>, Box<Self>),
100    /// Sequence of binary operations, e.g. `1 + 2 - 3 * 4`
101    BinOp(Box<Self>, Vec<(S, Self)>),
102
103    /// Control flow variable declaration, e.g. `label $x | ...`
104    Label(S, Box<Self>),
105    /// Break out from control flow to location variable, e.g. `break $x`
106    Break(S),
107
108    /// `reduce` and `foreach`, e.g. `reduce .[] as $x (0; .+$x)`
109    Fold(S, Box<Self>, S, Vec<Self>),
110    /// `try` and optional `catch`
111    TryCatch(Box<Self>, Option<Box<Self>>),
112    /// If-then-else
113    IfThenElse(Vec<(Self, Self)>, Option<Box<Self>>),
114
115    /// Local definition
116    Def(Vec<Def<S, Self>>, Box<Self>),
117    /// Call to another filter, e.g. `map(.+1)`
118    Call(S, Vec<Self>),
119    /// Variable, such as `$x` (including leading '$')
120    Var(S),
121
122    /// Path such as `.a`, `.[][]."b"`, `f[0]`
123    Path(Box<Self>, Path<Self>),
124}
125
126impl<S> Term<S> {
127    pub(crate) fn str(s: S) -> Self {
128        Self::Str(None, [StrPart::Str(s)].into())
129    }
130}
131
132impl<'s, 't> Parser<'s, 't> {
133    /// Initialise a new parser on a sequence of [`Token`]s.
134    #[must_use]
135    pub fn new(i: &'t [Token<&'s str>]) -> Self {
136        Self {
137            i: i.iter(),
138            e: Vec::new(),
139            fold: &["reduce", "foreach", "for"],
140        }
141    }
142
143    /// Parse tokens with the given function.
144    ///
145    /// Returns [`Ok`] if the function consumes the whole output without producing any error.
146    pub fn parse<T: Default, F>(mut self, f: F) -> core::result::Result<T, Vec<TError<'t, &'s str>>>
147    where
148        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
149    {
150        let y = self.finish("", f);
151        if self.e.is_empty() {
152            Ok(y)
153        } else {
154            Err(self.e)
155        }
156    }
157
158    /// Verifies that the remaining input tokens correspond to the given string.
159    fn verify_last(&mut self, last: &'static str) -> Result<'s, 't, ()> {
160        match (self.i.as_slice(), last) {
161            ([], "") => Ok(()),
162            ([Token::Char(c)], last) if *c == last => Ok(()),
163            ([], _) => Err((Expect::Char(last), None))?,
164            ([next, ..], "") => Err((Expect::Nothing, Some(next)))?,
165            ([next, ..], _) => Err((Expect::Char(last), Some(next)))?,
166        }
167    }
168
169    /// Run given parse function with given tokens, then reset tokens to previous tokens.
170    fn with_tok<T>(&mut self, tokens: &'t [Token<&'s str>], f: impl FnOnce(&mut Self) -> T) -> T {
171        let i = core::mem::replace(&mut self.i, tokens.iter());
172        let y = f(self);
173        self.i = i;
174        y
175    }
176
177    /// Parse with given function, then
178    /// ensure that remaining input tokens correspond to `last`, and
179    /// return default if any error occurred.
180    fn finish<T: Default, F>(&mut self, last: &'static str, f: F) -> T
181    where
182        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
183    {
184        f(self)
185            .and_then(|y| {
186                self.verify_last(last)?;
187                Ok(y)
188            })
189            .unwrap_or_else(|e| {
190                self.e.push(e);
191                T::default()
192            })
193    }
194
195    fn with<T: Default, F>(&mut self, tokens: &'t [Token<&'s str>], last: &'static str, f: F) -> T
196    where
197        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
198    {
199        self.with_tok(tokens, |p| p.finish(last, f))
200    }
201
202    /// Parse with the given function, and rewind input if it returns `None`.
203    fn maybe<T>(&mut self, f: impl Fn(&mut Self) -> Option<T>) -> Option<T> {
204        let i = self.i.clone();
205        let y = f(self);
206        // rewind to previous state in case of non-match
207        if y.is_none() {
208            self.i = i;
209        }
210        y
211    }
212
213    /// Parse with the given function, and rewind input if it returns `Ok(None)`.
214    fn try_maybe<T, F>(&mut self, f: F) -> Result<'s, 't, Option<T>>
215    where
216        F: Fn(&mut Self) -> Result<'s, 't, Option<T>>,
217    {
218        let i = self.i.clone();
219        let y = f(self)?;
220        // rewind to previous state in case of non-match
221        if y.is_none() {
222            self.i = i;
223        }
224        Ok(y)
225    }
226
227    /// Parse sequence of shape `f ("," f)* ","? "}"`.
228    fn obj_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
229    where
230        F: Fn(&mut Self) -> Result<'s, 't, T>,
231    {
232        let mut y = Vec::from([f(self)?]);
233        let rbrace = |p: &mut Self| p.i.next().filter(|tk| matches!(tk, Token::Char("}")));
234        loop {
235            match self.i.next() {
236                Some(Token::Char("}")) => break,
237                Some(Token::Char(",")) if self.maybe(rbrace).is_some() => break,
238                Some(Token::Char(",")) => y.push(f(self)?),
239                next => Err((Expect::CommaOrRBrace, next))?,
240            }
241        }
242        Ok(y)
243    }
244
245    /// Parse sequence of shape `f (";" f)* ")"`.
246    fn arg_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
247    where
248        F: Fn(&mut Self) -> Result<'s, 't, T>,
249    {
250        let mut y = Vec::from([f(self)?]);
251        loop {
252            match self.i.next() {
253                Some(Token::Char(";")) => y.push(f(self)?),
254                Some(Token::Char(")")) => break,
255                next => Err((Expect::SemicolonOrRParen, next))?,
256            }
257        }
258        Ok(y)
259    }
260
261    /// Parse `("(" arg (";" arg)* ")")?`.
262    fn args<T>(&mut self, f: fn(&mut Self) -> Result<'s, 't, T>) -> Vec<T> {
263        self.maybe(|p| match p.i.next() {
264            Some(Token::Block(full, tokens)) if full.starts_with('(') => {
265                Some(p.with(tokens, "", |p| p.arg_items(f)))
266            }
267            _ => None,
268        })
269        .unwrap_or_default()
270    }
271
272    /// Parse a binary operator, including `,` if `with_comma` is true.
273    fn op(&mut self, with_comma: bool) -> Option<&'s str> {
274        self.maybe(|p| match p.i.next() {
275            // handle pipe directly in `term()`
276            Some(Token::Op("|")) => None,
277            Some(Token::Op(o) | Token::Word(o @ ("and" | "or"))) => Some(*o),
278            Some(Token::Char(o @ ",")) if with_comma => Some(*o),
279            _ => None,
280        })
281    }
282
283    fn char0(&mut self, c: char) -> Option<&'s str> {
284        self.maybe(|p| match p.i.next() {
285            Some(Token::Char(s)) if s.chars().eq([c]) => Some(*s),
286            _ => None,
287        })
288    }
289
290    fn dot(&mut self) -> Option<&'s str> {
291        self.maybe(|p| match p.i.next() {
292            Some(Token::Char(c)) if *c != ".." => c.strip_prefix('.'),
293            _ => None,
294        })
295    }
296
297    fn terminated<T, F>(&mut self, f: F) -> Result<'s, 't, T>
298    where
299        F: FnOnce(&mut Self) -> Result<'s, 't, T>,
300    {
301        let y = f(self)?;
302        self.char1(";")?;
303        Ok(y)
304    }
305
306    fn char1(&mut self, c: &'static str) -> Result<'s, 't, &'s str> {
307        match self.i.next() {
308            Some(Token::Char(s)) if *s == c => Ok(*s),
309            next => Err((Expect::Char(c), next))?,
310        }
311    }
312
313    fn keyword(&mut self, kw: &'static str) -> Result<'s, 't, ()> {
314        match self.i.next() {
315            Some(Token::Word(w)) if *w == kw => Ok(()),
316            next => Err((Expect::Keyword(kw), next))?,
317        }
318    }
319
320    fn var(&mut self) -> Result<'s, 't, &'s str> {
321        match self.i.next() {
322            Some(Token::Word(x)) if x.starts_with('$') => Ok(*x),
323            next => Err((Expect::Var, next))?,
324        }
325    }
326
327    fn pipe(&mut self) -> Result<'s, 't, ()> {
328        match self.i.next() {
329            Some(Token::Op("|")) => Ok(()),
330            next => Err((Expect::Char("|"), next))?,
331        }
332    }
333
334    /// Parse a term.
335    ///
336    /// Only if `with_comma` is true, the parsed term may be of the shape `t, u`.
337    /// This matters for the parsing of object values, such as `{k1: v1, k2: v2}`:
338    /// if we would permit terms of the shape `t, u` inside objects,
339    /// then this would be parsed like `{k1: (v1, k2): v2}`, which is invalid.
340    fn term_with_comma(&mut self, with_comma: bool) -> Result<'s, 't, Term<&'s str>> {
341        let head = self.atom()?;
342        let tail = core::iter::from_fn(|| self.op(with_comma).map(|op| Ok((op, self.atom()?))))
343            .collect::<Result<Vec<_>>>()?;
344
345        let tm = if tail.is_empty() {
346            head
347        } else {
348            Term::BinOp(Box::new(head), tail)
349        };
350
351        let pipe = self.try_maybe(|p| match p.i.next() {
352            Some(Token::Op("|")) => Ok(Some(None)),
353            Some(Token::Word("as")) => {
354                let x = p.var()?;
355                p.pipe()?;
356                Ok(Some(Some(x)))
357            }
358            _ => Ok(None),
359        })?;
360        Ok(match pipe {
361            None => tm,
362            Some(x) => Term::Pipe(Box::new(tm), x, Box::new(self.term_with_comma(with_comma)?)),
363        })
364    }
365
366    /// Parse an atomic term.
367    ///
368    /// A term `t` is atomic if and only if `try t catch 0` is syntactically correct.
369    /// For example, the term `1 + 2` is not atomic, because `try 1 + 2 catch 0` is invalid.
370    /// However, the term `.[]` is atomic, because `try .[] catch 0` is valid.
371    fn atom(&mut self) -> Result<'s, 't, Term<&'s str>> {
372        let tm = match self.i.next() {
373            Some(Token::Op("-")) => Term::Neg(Box::new(self.atom()?)),
374            Some(Token::Word("def")) => {
375                let head = self.def_tail()?;
376                let tail = self.defs()?;
377                let tm = self.term()?;
378                Term::Def(core::iter::once(head).chain(tail).collect(), Box::new(tm))
379            }
380            Some(Token::Word("if")) => {
381                let if_then = |p: &mut Self| -> Result<_> {
382                    let if_ = p.term()?;
383                    p.keyword("then")?;
384                    Ok((if_, p.term()?))
385                };
386                let mut if_thens = Vec::from([if_then(self)?]);
387                let else_ = loop {
388                    match self.i.next() {
389                        Some(Token::Word("elif")) => if_thens.push(if_then(self)?),
390                        Some(Token::Word("else")) => {
391                            let else_ = self.term()?;
392                            self.keyword("end")?;
393                            break Some(else_);
394                        }
395                        Some(Token::Word("end")) => break None,
396                        next => Err((Expect::ElseOrEnd, next))?,
397                    }
398                };
399                Term::IfThenElse(if_thens, else_.map(Box::new))
400            }
401            Some(Token::Word("try")) => {
402                let try_ = self.atom()?;
403                let catch = self.try_maybe(|p| match p.i.next() {
404                    Some(Token::Word("catch")) => Ok(Some(p.atom()?)),
405                    _ => Ok(None),
406                })?;
407                Term::TryCatch(Box::new(try_), catch.map(Box::new))
408            }
409            Some(Token::Word("label")) => {
410                let x = self.var()?;
411                self.pipe()?;
412                let tm = self.term()?;
413                Term::Label(x, Box::new(tm))
414            }
415            Some(Token::Word("break")) => Term::Break(self.var()?),
416            Some(Token::Word(fold)) if self.fold.contains(fold) => {
417                let xs = self.atom()?;
418                self.keyword("as")?;
419                let x = self.var()?;
420                let args = self.args(Self::term);
421                Term::Fold(*fold, Box::new(xs), x, args)
422            }
423            Some(Token::Word(id)) if id.starts_with('$') => Term::Var(*id),
424            Some(Token::Word(id)) if id.starts_with('@') => {
425                let s = self.maybe(|p| match p.i.next() {
426                    Some(Token::Str(_, parts)) => Some(p.str_parts(parts)),
427                    _ => None,
428                });
429                match s {
430                    None => Term::Call(*id, Vec::new()),
431                    Some(parts) => Term::Str(Some(*id), parts),
432                }
433            }
434            Some(Token::Word(id)) => Term::Call(*id, self.args(Self::term)),
435            Some(Token::Char("..")) => Term::Recurse,
436            Some(Token::Char(c)) if c.starts_with('.') => {
437                let key = if c.len() > 1 {
438                    Some(Term::str(&c[1..]))
439                } else {
440                    // TODO: this returns None on things like "@json .",
441                    // whereas it should return an error instead
442                    self.maybe(|p| p.key().ok())
443                };
444
445                if let Some(key) = key {
446                    let head = (path::Part::Index(key), self.opt());
447                    let path = core::iter::once(head).chain(self.path()?).collect();
448                    Term::Path(Box::new(Term::Id), path)
449                } else {
450                    Term::Id
451                }
452            }
453            Some(Token::Num(n)) => Term::Num(*n),
454            Some(Token::Block(full, tokens)) => match &full[..1] {
455                "[" if matches!(tokens[..], [Token::Char("]")]) => Term::Arr(None),
456                "{" if matches!(tokens[..], [Token::Char("}")]) => Term::Obj(Vec::new()),
457                "[" => Term::Arr(Some(Box::new(self.with(tokens, "]", Self::term)))),
458                "{" => self.with(tokens, "", |p| p.obj_items(Self::obj_entry).map(Term::Obj)),
459                "(" => self.with(tokens, ")", Self::term),
460                _ => panic!(),
461            },
462            Some(Token::Str(_, parts)) => Term::Str(None, self.str_parts(parts)),
463            next => Err((Expect::Term, next))?,
464        };
465
466        let tm = match self.opt() {
467            path::Opt::Optional => Term::TryCatch(Box::new(tm), None),
468            path::Opt::Essential => tm,
469        };
470
471        let path = self.path()?;
472        Ok(if path.is_empty() {
473            tm
474        } else {
475            Term::Path(Box::new(tm), path)
476        })
477    }
478
479    /// Parse a term such as `.[] | .+1`.
480    pub fn term(&mut self) -> Result<'s, 't, Term<&'s str>> {
481        self.term_with_comma(true)
482    }
483
484    /// Parse an object entry.
485    ///
486    /// An object is written as `{e1, ..., en}`, where `ei` is an object entry.
487    /// An example of an object entry is `"key": value` or `(key): value`.
488    /// When the key is a term surrounded by parentheses, a value is required,
489    /// otherwise the value may be omitted (e.g. `"key"` or `$x`).
490    fn obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Option<Term<&'s str>>)> {
491        let i = self.i.clone();
492        let key = match self.i.next() {
493            Some(Token::Block(full, tokens)) if full.starts_with('(') => {
494                let k = self.with(tokens, ")", Self::term);
495                self.char1(":")?;
496                return Ok((k, Some(self.term_with_comma(false)?)));
497            }
498            Some(Token::Word(id)) if !id.starts_with(['$', '@']) && !id.contains("::") => {
499                Term::str(*id)
500            }
501            _ => {
502                self.i = i;
503                self.key()?
504            }
505        };
506        let v = self.char0(':').map(|_| self.term_with_comma(false));
507        Ok((key, v.transpose()?))
508    }
509
510    fn str_parts(
511        &mut self,
512        parts: &'t [StrPart<&'s str, Token<&'s str>>],
513    ) -> Vec<StrPart<&'s str, Term<&'s str>>> {
514        let parts = parts.iter().map(|part| match part {
515            StrPart::Str(s) => StrPart::Str(*s),
516            StrPart::Filter(Token::Block(full, tokens)) if full.starts_with('(') => {
517                StrPart::Filter(self.with(tokens, ")", Self::term))
518            }
519            StrPart::Filter(_) => unreachable!(),
520            StrPart::Char(c) => StrPart::Char(*c),
521        });
522        parts.collect()
523    }
524
525    fn path(&mut self) -> Result<'s, 't, Path<Term<&'s str>>> {
526        let mut path: Vec<_> = core::iter::from_fn(|| self.path_part_opt()).collect();
527        while let Some(key) = self.dot() {
528            let key = if key.is_empty() {
529                self.key()?
530            } else {
531                Term::str(key)
532            };
533            path.push((path::Part::Index(key), self.opt()));
534            path.extend(core::iter::from_fn(|| self.path_part_opt()));
535        }
536        Ok(path)
537    }
538
539    /// Parse `[]`, `[t]`, `[t:]`, `[t:t]`, `[:t]` (all without brackets).
540    fn path_part(&mut self) -> Result<'s, 't, path::Part<Term<&'s str>>> {
541        use path::Part::{Index, Range};
542        let done = |p: &Self| matches!(p.i.as_slice(), [Token::Char("]")]);
543        Ok(if done(self) {
544            Range(None, None)
545        } else if self.char0(':').is_some() {
546            Range(None, Some(self.term()?))
547        } else {
548            let tm = self.term()?;
549            if self.char0(':').is_some() {
550                if done(self) {
551                    Range(Some(tm), None)
552                } else {
553                    Range(Some(tm), Some(self.term()?))
554                }
555            } else {
556                Index(tm)
557            }
558        })
559    }
560
561    fn path_part_opt(&mut self) -> Option<(path::Part<Term<&'s str>>, path::Opt)> {
562        let part = self.maybe(|p| match p.i.next() {
563            Some(Token::Block(full, tokens)) if full.starts_with('[') => {
564                Some(p.with(tokens, "]", Self::path_part))
565            }
566            _ => None,
567        })?;
568        Some((part, self.opt()))
569    }
570
571    fn key(&mut self) -> Result<'s, 't, Term<&'s str>> {
572        Ok(match self.i.next() {
573            Some(Token::Word(id)) if id.starts_with('$') => Term::Var(*id),
574            Some(Token::Word(id)) if id.starts_with('@') => match self.i.next() {
575                Some(Token::Str(_, parts)) => Term::Str(Some(*id), self.str_parts(parts)),
576                next => Err((Expect::Str, next))?,
577            },
578            Some(Token::Str(_, parts)) => Term::Str(None, self.str_parts(parts)),
579            next => Err((Expect::Key, next))?,
580        })
581    }
582
583    fn opt(&mut self) -> path::Opt {
584        let mut opt = path::Opt::Essential;
585        while self.char0('?').is_some() {
586            opt = path::Opt::Optional;
587        }
588        opt
589    }
590
591    /// Parse a sequence of definitions, such as `def x: 1; def y: 2;`.
592    pub fn defs(&mut self) -> Result<'s, 't, Defs<&'s str>> {
593        let head = |p: &mut Self| p.keyword("def").ok();
594        core::iter::from_fn(|| self.maybe(head).map(|_| self.def_tail())).collect()
595    }
596
597    /// Parse `name args ":" term ";"`.
598    fn def_tail(&mut self) -> Result<'s, 't, Def<&'s str, Term<&'s str>>> {
599        let name = match self.i.next() {
600            Some(Token::Word(w)) if !w.starts_with('$') && !w.contains("::") => w,
601            next => Err((Expect::Ident, next))?,
602        };
603        let args = self.args(|p| {
604            Ok(match p.i.next() {
605                Some(Token::Word(w)) if !w.contains("::") => *w,
606                next => Err((Expect::Arg, next))?,
607            })
608        });
609        self.char1(":")?;
610
611        let body = self.term()?;
612        self.char1(";")?;
613
614        Ok(Def { name, args, body })
615    }
616
617    fn bare_str(&mut self) -> Result<'s, 't, &'s str> {
618        match self.i.next() {
619            next @ Some(Token::Str(_, parts)) => match parts[..] {
620                [StrPart::Str(s)] => Ok(s),
621                _ => Err((Expect::Str, next))?,
622            },
623            next => Err((Expect::Str, next))?,
624        }
625    }
626
627    fn include(&mut self) -> Result<'s, 't, (&'s str, Option<&'s str>)> {
628        self.bare_str().map(|path| (path, None))
629    }
630
631    fn import(&mut self) -> Result<'s, 't, (&'s str, Option<&'s str>)> {
632        let path = self.bare_str()?;
633        self.keyword("as")?;
634        let name = match self.i.next() {
635            Some(Token::Word(w)) if !w.starts_with(['$', '@']) && !w.contains("::") => *w,
636            next => Err((Expect::Ident, next))?,
637        };
638        Ok((path, Some(name)))
639    }
640
641    /// Parse a module with a body returned by the given function.
642    pub fn module<B, F>(&mut self, f: F) -> Result<'s, 't, Module<&'s str, B>>
643    where
644        F: FnOnce(&mut Self) -> Result<'s, 't, B>,
645    {
646        let meta = self
647            .maybe(|p| match p.i.next() {
648                Some(Token::Word("module")) => Some(p.terminated(Self::term)),
649                _ => None,
650            })
651            .transpose()?;
652
653        let deps = core::iter::from_fn(|| {
654            self.maybe(|p| match p.i.next() {
655                Some(Token::Word("include")) => Some(p.terminated(Self::include)),
656                Some(Token::Word("import")) => Some(p.terminated(Self::import)),
657                _ => None,
658            })
659        })
660        .collect::<Result<_>>()?;
661
662        let body = f(self)?;
663
664        Ok(Module { meta, deps, body })
665    }
666}
667
668/// jq module, consisting of metadata, imports/includes, and a body.
669///
670/// Example (where the body is a sequence of definitions):
671///
672/// ~~~ jq
673/// module {};
674///
675/// import "foo" as foo;
676/// include "bar";
677///
678/// def iter: .[];
679/// ~~~
680#[derive(Debug, Default)]
681pub struct Module<S, B> {
682    #[allow(dead_code)]
683    pub(crate) meta: Option<Term<S>>,
684    pub(crate) deps: Vec<(S, Option<S>)>,
685    pub(crate) body: B,
686}
687
688/// jq definition, consisting of a name, optional arguments, and a body.
689///
690/// Examples:
691///
692/// ~~~ jq
693/// def pi: 3.1415;
694/// def double($x): $x + $x;
695/// def map(f): [.[] | f];
696/// def recurse(f; cond): recurse(f | select(cond));
697/// ~~~
698#[derive(Debug)]
699pub struct Def<S, F> {
700    pub(crate) name: S,
701    pub(crate) args: Vec<S>,
702    /// Body of the filter, e.g. `[.[] | f]`.
703    pub(crate) body: F,
704}
705
706pub(crate) type Defs<S> = Vec<Def<S, Term<S>>>;