moxy-template 0.3.2

Rust quasi-quoting and token templating with explicit interpolation syntax and built-in template control flow
Documentation
#![allow(unused)]

use std::str::FromStr;

use moxy_ast::{Cursor, Parse, ParseError, Parser};
use moxy_token::{Punct, Span, ToTokens, TokenStream, TokenTree};

#[doc = "Literal passthrough tokens in a template: any tokens not matched by interpolation or control flow."]
#[derive(Clone)]
#[cfg_attr(feature = "derives", derive(Debug))]
pub struct TmplTokens {
    pub span: Span,
    pub tokens: TokenStream,
}

impl Parse for TmplTokens {
    fn peek(cursor: Cursor<'_>) -> bool {
        match cursor.curr() {
            Some(TokenTree::Punct(Punct::At(_))) | None => false,
            Some(TokenTree::Group(group)) => !super::Node::is_interp_group(group) && !super::Node::group_has_interp(group),
            Some(_) => true,
        }
    }

    fn parse(parser: &Parser) -> Result<Self, ParseError> {
        let span = parser.span();
        let mut tokens = TokenStream::new();

        while let Some(token) = parser.curr() {
            if matches!(token, TokenTree::Punct(Punct::At(_))) {
                break;
            }

            if let TokenTree::Group(group) = token
                && (super::Node::is_interp_group(group) || super::Node::group_has_interp(group))
            {
                break;
            }

            tokens.extend_one(token.clone());
            parser.advance();
        }

        if tokens.is_empty() {
            return parser.error("expected template tokens").into();
        }

        Ok(Self { span, tokens })
    }

    fn skip(mut cursor: Cursor<'_>) -> Option<Cursor<'_>> {
        let mut skipped = false;

        while let Some(token) = cursor.curr() {
            if matches!(token, TokenTree::Punct(Punct::At(_))) {
                break;
            }

            if let TokenTree::Group(group) = token
                && (super::Node::is_interp_group(group) || super::Node::group_has_interp(group))
            {
                break;
            }

            cursor = cursor.offset(1);
            skipped = true;
        }

        skipped.then_some(cursor)
    }
}

impl ToTokens for TmplTokens {
    fn to_tokens(&self, out: &mut TokenStream) {
        let src = self.tokens.to_string();
        out.extend(TokenStream::from_str(&format!("::moxy::token::ToTokens::to_tokens(&{src:?}, &mut __moxy_tmpl);")).unwrap());
    }
}