use super::{
Input, component::component, inner_text::inner_text, rust_block::rust_block,
rust_stmt::rust_stmt, simple_expr::simple_expr, simple_expr_paren::simple_expr_paren,
template_params::template_params, text::text, use_directive::use_directive,
};
use crate::{
extensions::ParserDiagnostic,
rshtml_file::{
break_directive::break_directive, child_content_directive::child_content_directive,
continue_directive::continue_directive,
},
};
use proc_macro2::TokenStream;
use quote::quote;
use winnow::{
ModalResult, Parser,
ascii::multispace0,
combinator::{alt, cut_err, eof, fail, opt, peek, repeat},
token::{any, none_of, one_of, take_while},
};
pub fn template<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<TokenStream> {
(
opt("\u{FEFF}"),
multispace0,
opt((
peek(('@', multispace0, '(')),
template_params.label("template parameters"),
))
.void(),
template_content,
eof.expected("end of file"),
)
.map(|(_, _, _, content, _)| content)
.parse_next(input)
}
pub fn template_content<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<TokenStream> {
repeat(0.., alt((text.label("html text"), block)))
.fold(TokenStream::new, |mut acc, ts| {
acc.extend(ts);
acc
})
.parse_next(input)
}
pub fn inner_template_content<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<TokenStream> {
(
'{',
repeat(0.., alt((inner_text.label("html text"), block))).fold(
TokenStream::new,
|mut acc, ts| {
acc.extend(ts);
acc
},
),
cut_err('}').expected("}"),
)
.map(|(_, content, _)| {
let ts = quote! {{#content}};
ts
})
.parse_next(input)
}
#[cfg(not(debug_assertions))]
pub fn block<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<TokenStream> {
alt((
component.label("component"),
(
'@',
multispace0,
alt((
use_directive.label("use directive"),
rust_block.label("code block"),
rust_stmt.label("statement"),
child_content_directive.label("child content"),
continue_directive.label("continue"),
break_directive.label("break"),
simple_expr_paren
.map(|(_, x)| x)
.label("parenthesized expression"),
simple_expr.map(|(_, x)| x).label("expression"),
cut_err(fail).expected("a valid directive or an expression after '@'"),
)),
)
.map(|(_, _, ts)| ts),
fail.expected("a valid directive or an expression or a component"),
))
.parse_next(input)
}
#[cfg(debug_assertions)]
pub fn block<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<TokenStream> {
use std::ops::Range;
use crate::debug::Snippet;
let extract = |span: Range<usize>| input.state.source[span.start..span.end].to_owned();
let (ts, snippet) = alt((
component
.with_span()
.map(|(ts, span)| (ts, Snippet::Component(span.to_owned(), extract(span))))
.label("component"),
(
'@',
multispace0,
alt((
use_directive
.map(|ts| (ts, Snippet::None))
.label("use directive"),
rust_block
.with_span()
.map(|(ts, span)| (ts, Snippet::Block(span.to_owned(), extract(span))))
.label("code block"),
rust_stmt
.with_span()
.map(|(ts, span)| (ts, Snippet::Stmt(span.to_owned(), extract(span))))
.label("statement"),
child_content_directive
.with_span()
.map(|(ts, span)| (ts, Snippet::ChildContent(span.to_owned(), extract(span))))
.label("child content"),
continue_directive
.with_span()
.map(|(ts, span)| (ts, Snippet::Continue(span.to_owned(), extract(span))))
.label("continue"),
break_directive
.with_span()
.map(|(ts, span)| (ts, Snippet::Break(span.to_owned(), extract(span))))
.label("break"),
simple_expr_paren
.with_span()
.map(|((_, x), span)| (x, Snippet::ExprParen(span.to_owned(), extract(span))))
.label("parenthesized expression"),
simple_expr
.with_span()
.map(|((_, x), span)| (x, Snippet::ExprSimple(span.to_owned(), extract(span))))
.label("expression"),
cut_err(fail).expected("a valid directive or an expression after '@'"),
)),
)
.map(|(_, _, ts)| ts),
fail.expected("a valid directive or an expression or a component"),
))
.parse_next(input)?;
input.state.info.debug.push(snippet);
Ok(ts)
}
pub fn rust_identifier<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<&'a str> {
let start = input.input;
(
one_of(|c: char| c.is_alphabetic() || c == '_'),
take_while(0.., |c: char| c.is_alphanumeric() || c == '_'),
)
.parse_next(input)?;
let consumed = start.len() - input.input.len();
Ok(&start[..consumed])
}
pub fn string_line<'a, 'ctx>(input: &mut Input<'a, 'ctx>) -> ModalResult<&'a str> {
let start = input.input;
alt((
(
'"',
repeat(0.., alt((("\\", any).void(), none_of(['"', '\\']).void())))
.map(|_: Vec<()>| ()),
'"',
),
(
'\'',
repeat(0.., alt((("\\", any).void(), none_of(['\'', '\\']).void())))
.map(|_: Vec<()>| ()),
'\'',
),
))
.void()
.parse_next(input)?;
let parsed_len = start.len() - input.input.len();
Ok(&start[..parsed_len])
}