jaq-parse 1.0.3

Parser for the jaq language
Documentation
use super::{Delim, Token};
use chumsky::prelude::*;
use jaq_syn::{Call, Spanned, Str};

pub fn str_<T, P>(expr: P) -> impl Parser<Token, Str<Spanned<T>>, Error = P::Error> + Clone
where
    T: From<Call<Spanned<T>>>,
    P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
{
    let call = |name| Call {
        name,
        args: Default::default(),
    };
    let ident = select! {
        Token::Ident(ident) if ident.starts_with('@') => ident,
    };
    let fmt = ident.map_with_span(move |x, span| (T::from(call(x)), span).into());

    let chars = select! {
        Token::Str(s) => s,
    };
    let parts = chars.then(Delim::Paren.around(expr).then(chars).repeated());
    let parts = parts.map(|(head, tail)| {
        use core::iter::once;
        use jaq_syn::string::Part::{Fun, Str};
        let tail = tail.into_iter().flat_map(|(f, s)| [Fun(f), Str(s)]);
        let parts = once(Str(head)).chain(tail);
        parts.filter(|p| !p.is_empty()).collect()
    });
    fmt.or_not()
        .then(parts.delimited_by(just(Token::Quote), just(Token::Quote)))
        .map(|(fmt, parts)| Str { fmt, parts })
        .labelled("string")
}