cuicui_chirp 0.12.0

A file format based on cuicui_dsl to describe bevy UIs
Documentation
use winnow::combinator::{dispatch, opt, repeat, success};
use winnow::error::ErrMode::{Backtrack, Cut};
use winnow::stream::Stream;
use winnow::token::any;
use winnow::trace::trace;
use winnow::{PResult, Parser};

use super::Error;
use crate::parser::stream::{tokens, Token, TokenType};
use crate::parser::{ast, Input};

#[rustfmt::skip]
macro_rules! token {
    ($first:tt $(| $many:tt)*) => { token!(@ $first) $(| token!(@ $many))* };
    (@ "ident")  => { Token::Ident(_) };
    (@ "string") => { Token::String(_) };
    (@ '(') => { Token::Lparen };
    (@ ')') => { Token::Rparen };
    (@ '{') => { Token::Lcurly };
    (@ '}') => { Token::Rcurly };
    (@ '[') => { Token::Lbracket };
    (@ ']') => { Token::Rbracket };
    (@ ',') => { Token::Comma };
    (@ '=') => { Token::Equal };
}
#[rustfmt::skip]
macro_rules! tokens {
    ($inner:expr, ')') => { winnow::combinator::terminated($inner, tokens::Rparen) };
    ($inner:expr, ']') => { winnow::combinator::terminated($inner, tokens::Rbracket) };
    ($inner:expr, '}') => { winnow::combinator::terminated($inner, tokens::Rcurly) };
}

#[inline(always)]
pub(super) fn ident(input: &mut Input) -> PResult<ast::IdentOffset, Error> {
    let start = input.next_start();
    match input.next_token() {
        Some(token!("ident")) => Ok(ast::IdentOffset { start }),
        got => Err(Backtrack(Error::Expected(TokenType::Ident, got.into()))),
    }
}
fn span_from_len(start: u32, len: usize) -> (u32, u32) {
    (start, start + u32::try_from(len).unwrap())
}
#[inline(always)]
pub(super) fn many_tts<const SPLIT_COMMA: bool>(input: &mut Input) -> PResult<(u32, u32), Error> {
    let start = input.next_start();
    repeat::<_, _, (), _, _>(1.., token_tree::<SPLIT_COMMA>)
        .recognize()
        .map(|v| span_from_len(start, v.len()))
        .parse_next(input)
}
#[inline(always)]
pub(super) fn token_tree<const SPLIT_COMMA: bool>(input: &mut Input) -> PResult<(), Error> {
    let parser = dispatch! { opt(any);
        Some(token!('(')) => tokens!(many_tts::<false>.void(), ')'),
        Some(token!('[')) => tokens!(many_tts::<false>.void(), ']'),
        Some(token!('{')) => tokens!(many_tts::<false>.void(), '}'),
        Some(token!(',')) if SPLIT_COMMA => |_: &mut _| Err(Backtrack(Error::Unexpected)),
        Some(token!("ident" | "string" | ',' | '=')) => success(()),
        None | Some(token!(')' | ']' | '}')) => |_: &mut _| Err(Backtrack(Error::Unexpected)),
        _ => |_: &mut _| Err(Cut(Error::Unbalanced)),
    };
    trace("token_tree", parser).parse_next(input)
}