1#![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
26pub 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
37pub 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}