jaq_parse/
lib.rs

1//! JSON query language parser.
2//!
3//! **Note**:
4//! This crate is not maintained anymore.
5//! It has been superseded by the `jaq-syn` crate.
6#![no_std]
7#![forbid(unsafe_code)]
8#![warn(missing_docs)]
9
10extern crate alloc;
11
12mod def;
13mod filter;
14mod path;
15mod prec_climb;
16mod string;
17mod token;
18
19pub use def::{defs, main};
20use token::{Delim, Token};
21
22use alloc::{string::String, string::ToString, vec::Vec};
23use chumsky::prelude::*;
24use jaq_syn::Spanned;
25
26/// Lex/parse error.
27pub type Error = Simple<String>;
28
29fn lex() -> impl Parser<char, Vec<Spanned<Token>>, Error = Simple<char>> {
30    recursive(token::tree)
31        .map_with_span(|tree, span| tree.tokens(span))
32        .repeated()
33        .flatten()
34        .collect()
35}
36
37/// Parse a string with a given parser.
38///
39/// May produce `Some` output even if there were errors.
40pub fn parse<T, P>(src: &str, parser: P) -> (Option<T>, Vec<Error>)
41where
42    P: Parser<Token, T, Error = Simple<Token>> + Clone,
43{
44    let (tokens, lex_errs) = lex()
45        .then_ignore(end())
46        .recover_with(skip_then_retry_until([]))
47        .parse_recovery(src);
48
49    let (parsed, parse_errs) = if let Some(tokens) = tokens {
50        let len = src.chars().count();
51        let stream = chumsky::Stream::from_iter(len..len + 1, tokens.into_iter());
52        parser.then_ignore(end()).parse_recovery(stream)
53    } else {
54        (None, Vec::new())
55    };
56
57    let lex_errs = lex_errs.into_iter().map(|e| e.map(|c| c.to_string()));
58    let parse_errs = parse_errs.into_iter().map(|e| e.map(|tok| tok.to_string()));
59    let errs: Vec<_> = lex_errs.chain(parse_errs).collect();
60
61    (parsed, errs)
62}