From b912bd9ca7ca8d029496b00f0c481649f2cb3df4 Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Tue, 7 Jan 2025 17:40:48 +1100 Subject: [PATCH] Disallow elements in attributes (redux) (#460) * Rename control flow nodes to avoid conflict with `syn` tokens * Remove calls to `Token!` * Disallow elements in attributes * Add test * Split `into_element` out of `MaybeElement` * Fix Clippy type complexity --- .../warnings/attribute-missing-value.stderr | 4 +- .../class-shorthand-missing-value.stderr | 4 +- maud/tests/warnings/elements-in-attributes.rs | 45 +++ .../warnings/elements-in-attributes.stderr | 47 +++ maud_macros/src/ast.rs | 277 +++++++++++------- maud_macros/src/generate.rs | 42 +-- 6 files changed, 282 insertions(+), 137 deletions(-) create mode 100644 maud/tests/warnings/elements-in-attributes.rs create mode 100644 maud/tests/warnings/elements-in-attributes.stderr diff --git a/maud/tests/warnings/attribute-missing-value.stderr b/maud/tests/warnings/attribute-missing-value.stderr index 61b1b3c2..c16e78a1 100644 --- a/maud/tests/warnings/attribute-missing-value.stderr +++ b/maud/tests/warnings/attribute-missing-value.stderr @@ -1,5 +1,5 @@ -error: unexpected end of input, expected one of: curly braces, literal, parentheses, identifier, `.`, `#`, `@`, `;` - --> $DIR/attribute-missing-value.rs:4:5 +error: unexpected end of input, expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/attribute-missing-value.rs:4:5 | 4 | / html! { 5 | | a href= diff --git a/maud/tests/warnings/class-shorthand-missing-value.stderr b/maud/tests/warnings/class-shorthand-missing-value.stderr index 2969befc..d2bd2947 100644 --- a/maud/tests/warnings/class-shorthand-missing-value.stderr +++ b/maud/tests/warnings/class-shorthand-missing-value.stderr @@ -1,5 +1,5 @@ -error: unexpected end of input, expected one of: curly braces, literal, parentheses, identifier, `.`, `#`, `@`, `;` - --> $DIR/class-shorthand-missing-value.rs:4:5 +error: unexpected end of input, expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/class-shorthand-missing-value.rs:4:5 | 4 | / html! { 5 | | p. diff --git a/maud/tests/warnings/elements-in-attributes.rs b/maud/tests/warnings/elements-in-attributes.rs new file mode 100644 index 00000000..377a87be --- /dev/null +++ b/maud/tests/warnings/elements-in-attributes.rs @@ -0,0 +1,45 @@ +use maud::html; + +fn main() { + html! { + a href={ b {} } {} + }; + + html! { + a href=.pinkie-pie {} {} + }; + + html! { + a .{ b {} } {} + }; + + html! { + a #{ b {} } {} + }; + + html! { + @if true { + } @else if true { + } @else { + a href={ b #if-else {} } {} + } + }; + + html! { + @for _ in 0..10 { + a href={ b #for {} } {} + } + }; + + html! { + @while false { + a href={ b #while {} } {} + } + }; + + html! { + @match () { + () => a href={ b #match {} } {} + } + }; +} diff --git a/maud/tests/warnings/elements-in-attributes.stderr b/maud/tests/warnings/elements-in-attributes.stderr new file mode 100644 index 00000000..a36c9d80 --- /dev/null +++ b/maud/tests/warnings/elements-in-attributes.stderr @@ -0,0 +1,47 @@ +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:5:18 + | +5 | a href={ b {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:9:16 + | +9 | a href=.pinkie-pie {} {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:13:14 + | +13 | a .{ b {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:17:14 + | +17 | a #{ b {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:24:22 + | +24 | a href={ b #if-else {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:30:22 + | +30 | a href={ b #for {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:36:22 + | +36 | a href={ b #while {} } {} + | ^ + +error: expected one of: curly braces, literal, parentheses, `@`, `;` + --> tests/warnings/elements-in-attributes.rs:42:28 + | +42 | () => a href={ b #match {} } {} + | ^ diff --git a/maud_macros/src/ast.rs b/maud_macros/src/ast.rs index 1890e074..70e19a55 100644 --- a/maud_macros/src/ast.rs +++ b/maud_macros/src/ast.rs @@ -7,19 +7,22 @@ use syn::{ braced, bracketed, ext::IdentExt, parenthesized, - parse::{Parse, ParseStream}, + parse::{Lookahead1, Parse, ParseStream}, punctuated::{Pair, Punctuated}, spanned::Spanned, - token::{Brace, Bracket, Paren}, - Error, Expr, Ident, Lit, LitBool, LitInt, LitStr, Local, Pat, Stmt, Token, + token::{ + At, Brace, Bracket, Colon, Comma, Dot, Else, Eq, FatArrow, For, If, In, Let, Match, Minus, + Paren, Pound, Question, Semi, Slash, While, + }, + Error, Expr, Ident, Lit, LitBool, LitInt, LitStr, Local, Pat, Stmt, }; #[derive(Debug, Clone)] -pub struct Markups { - pub markups: Vec, +pub struct Markups { + pub markups: Vec>, } -impl DiagnosticParse for Markups { +impl DiagnosticParse for Markups { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -32,7 +35,7 @@ impl DiagnosticParse for Markups { } } -impl ToTokens for Markups { +impl ToTokens for Markups { fn to_tokens(&self, tokens: &mut TokenStream) { for markup in &self.markups { markup.to_tokens(tokens); @@ -41,25 +44,25 @@ impl ToTokens for Markups { } #[derive(Debug, Clone)] -pub enum Markup { - Block(Block), +pub enum Markup { + Block(Block), Lit(HtmlLit), Splice { paren_token: Paren, expr: Expr }, - Element(Element), - ControlFlow(ControlFlow), - Semi(Token![;]), + Element(E), + ControlFlow(ControlFlow), + Semi(Semi), } -impl Markup { +impl Markup { pub fn diagnostic_parse_in_block( input: ParseStream, diagnostics: &mut Vec, ) -> syn::Result { - if input.peek(Token![let]) - || input.peek(Token![if]) - || input.peek(Token![for]) - || input.peek(Token![while]) - || input.peek(Token![match]) + if input.peek(Let) + || input.peek(If) + || input.peek(For) + || input.peek(While) + || input.peek(Match) { let kw = input.call(Ident::parse_any)?; diagnostics.push( @@ -81,14 +84,11 @@ impl Markup { paren_token: parenthesized!(content in input), expr: content.parse()?, }) - } else if lookahead.peek(Ident::peek_any) - || lookahead.peek(Token![.]) - || lookahead.peek(Token![#]) - { - input.diagnostic_parse(diagnostics).map(Self::Element) - } else if lookahead.peek(Token![@]) { + } else if let Some(parse_element) = E::should_parse(&lookahead) { + parse_element(input, diagnostics).map(Self::Element) + } else if lookahead.peek(At) { input.diagnostic_parse(diagnostics).map(Self::ControlFlow) - } else if lookahead.peek(Token![;]) { + } else if lookahead.peek(Semi) { input.parse().map(Self::Semi) } else { Err(lookahead.error()) @@ -96,7 +96,7 @@ impl Markup { } } -impl DiagnosticParse for Markup { +impl DiagnosticParse for Markup { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -119,7 +119,7 @@ impl DiagnosticParse for Markup { } } -impl ToTokens for Markup { +impl ToTokens for Markup { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Self::Block(block) => block.to_tokens(tokens), @@ -136,6 +136,37 @@ impl ToTokens for Markup { } } +/// Represents a context that may or may not allow elements. +/// +/// An attribute accepts almost the same syntax as an element body, except child elements aren't +/// allowed. To enable code reuse, introduce a trait that abstracts over whether an element is +/// allowed or not. +pub trait MaybeElement: Sized + ToTokens { + /// If an element can be parsed here, returns `Some` with a parser for the rest of the element. + fn should_parse(lookahead: &Lookahead1<'_>) -> Option>; +} + +/// An implementation of `DiagnosticParse::diagnostic_parse`. +pub type DiagnosticParseFn = fn(ParseStream, &mut Vec) -> syn::Result; + +/// Represents an attribute context, where elements are disallowed. +#[derive(Debug, Clone)] +pub enum NoElement {} + +impl MaybeElement for NoElement { + fn should_parse( + _lookahead: &Lookahead1<'_>, + ) -> Option) -> syn::Result> { + None + } +} + +impl ToTokens for NoElement { + fn to_tokens(&self, _tokens: &mut TokenStream) { + match *self {} + } +} + #[derive(Debug, Clone)] pub struct Element { pub name: Option, @@ -143,6 +174,24 @@ pub struct Element { pub body: ElementBody, } +impl From for Element { + fn from(value: NoElement) -> Self { + match value {} + } +} + +impl MaybeElement for Element { + fn should_parse( + lookahead: &Lookahead1<'_>, + ) -> Option) -> syn::Result> { + if lookahead.peek(Ident::peek_any) || lookahead.peek(Dot) || lookahead.peek(Pound) { + Some(Element::diagnostic_parse) + } else { + None + } + } +} + impl DiagnosticParse for Element { fn diagnostic_parse( input: ParseStream, @@ -160,8 +209,8 @@ impl DiagnosticParse for Element { while input.peek(Ident::peek_any) || input.peek(Lit) - || input.peek(Token![.]) - || input.peek(Token![#]) + || input.peek(Dot) + || input.peek(Pound) { let attr = input.diagnostic_parse(diagnostics)?; @@ -178,16 +227,16 @@ impl DiagnosticParse for Element { attrs.push(attr); } - if !(input.peek(Brace) || input.peek(Token![;]) || input.peek(Token![/])) { + if !(input.peek(Brace) || input.peek(Semi) || input.peek(Slash)) { let lookahead = input.lookahead1(); lookahead.peek(Ident::peek_any); lookahead.peek(Lit); - lookahead.peek(Token![.]); - lookahead.peek(Token![#]); + lookahead.peek(Dot); + lookahead.peek(Pound); lookahead.peek(Brace); - lookahead.peek(Token![;]); + lookahead.peek(Semi); return Err(lookahead.error()); } @@ -213,8 +262,8 @@ impl ToTokens for Element { #[derive(Debug, Clone)] pub enum ElementBody { - Void(Token![;]), - Block(Block), + Void(Semi), + Block(Block), } impl DiagnosticParse for ElementBody { @@ -224,21 +273,21 @@ impl DiagnosticParse for ElementBody { ) -> syn::Result { let lookahead = input.lookahead1(); - if lookahead.peek(Token![;]) { + if lookahead.peek(Semi) { input.parse().map(Self::Void) } else if lookahead.peek(Brace) { input.diagnostic_parse(diagnostics).map(Self::Block) - } else if lookahead.peek(Token![/]) { + } else if lookahead.peek(Slash) { diagnostics.push( input - .parse::()? + .parse::()? .span() .error("void elements must use `;`, not `/`") .help("change this to `;`") .help("see https://github.com/lambda-fairy/maud/pull/315 for details"), ); - Ok(Self::Void(::default())) + Ok(Self::Void(::default())) } else { Err(lookahead.error()) } @@ -255,12 +304,12 @@ impl ToTokens for ElementBody { } #[derive(Debug, Clone)] -pub struct Block { +pub struct Block { pub brace_token: Brace, - pub markups: Markups, + pub markups: Markups, } -impl DiagnosticParse for Block { +impl DiagnosticParse for Block { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -273,7 +322,7 @@ impl DiagnosticParse for Block { } } -impl ToTokens for Block { +impl ToTokens for Block { fn to_tokens(&self, tokens: &mut TokenStream) { self.brace_token.surround(tokens, |tokens| { self.markups.to_tokens(tokens); @@ -284,12 +333,12 @@ impl ToTokens for Block { #[derive(Debug, Clone)] pub enum Attribute { Class { - dot_token: Token![.], + dot_token: Dot, name: AttributeName, toggler: Option, }, Id { - pound_token: Token![#], + pound_token: Pound, name: AttributeName, }, Named { @@ -305,7 +354,7 @@ impl DiagnosticParse for Attribute { ) -> syn::Result { let lookahead = input.lookahead1(); - if lookahead.peek(Token![.]) { + if lookahead.peek(Dot) { Ok(Self::Class { dot_token: input.parse()?, name: input.diagnostic_parse(diagnostics)?, @@ -319,7 +368,7 @@ impl DiagnosticParse for Attribute { } }, }) - } else if lookahead.peek(Token![#]) { + } else if lookahead.peek(Pound) { Ok(Self::Id { pound_token: input.parse()?, name: input.diagnostic_parse(diagnostics)?, @@ -334,7 +383,7 @@ impl DiagnosticParse for Attribute { attr_type: input.diagnostic_parse(diagnostics)?, }; - if fork.peek(Token![=]) && fork.peek2(LitBool) { + if fork.peek(Eq) && fork.peek2(LitBool) { diagnostics.push( attr.span() .error("attribute value must be a string") @@ -377,7 +426,7 @@ impl ToTokens for Attribute { #[derive(Debug, Clone)] pub enum AttributeName { Normal(HtmlName), - Markup(Markup), + Markup(Markup), } impl DiagnosticParse for AttributeName { @@ -391,8 +440,8 @@ impl DiagnosticParse for AttributeName { input.diagnostic_parse(diagnostics).map(Self::Markup) }; - if input.peek(Token![?]) { - input.parse::()?; + if input.peek(Question) { + input.parse::()?; } name @@ -426,11 +475,11 @@ impl Display for AttributeName { #[derive(Debug, Clone)] pub enum AttributeType { Normal { - eq_token: Token![=], - value: Markup, + eq_token: Eq, + value: Markup, }, Optional { - eq_token: Token![=], + eq_token: Eq, toggler: Toggler, }, Empty(Option), @@ -443,7 +492,7 @@ impl DiagnosticParse for AttributeType { ) -> syn::Result { let lookahead = input.lookahead1(); - if lookahead.peek(Token![=]) { + if lookahead.peek(Eq) { let eq_token = input.parse()?; if input.peek(Bracket) { @@ -502,7 +551,7 @@ impl DiagnosticParse for HtmlName { loop { punctuated.push_value(input.diagnostic_parse(diagnostics)?); - if !(input.peek(Token![-]) || input.peek(Token![:])) { + if !(input.peek(Minus) || input.peek(Colon)) { break; } @@ -564,7 +613,7 @@ impl DiagnosticParse for HtmlNameFragment { input.call(Ident::parse_any).map(Self::Ident) } else if lookahead.peek(Lit) { input.diagnostic_parse(diagnostics).map(Self::Lit) - } else if lookahead.peek(Token![-]) || lookahead.peek(Token![:]) { + } else if lookahead.peek(Minus) || lookahead.peek(Colon) { Ok(Self::Empty) } else { Err(lookahead.error()) @@ -659,17 +708,17 @@ impl Display for HtmlLit { #[derive(Debug, Clone)] pub enum HtmlNamePunct { - Colon(Token![:]), - Hyphen(Token![-]), + Colon(Colon), + Hyphen(Minus), } impl DiagnosticParse for HtmlNamePunct { fn diagnostic_parse(input: ParseStream, _: &mut Vec) -> syn::Result { let lookahead = input.lookahead1(); - if lookahead.peek(Token![:]) { + if lookahead.peek(Colon) { input.parse().map(Self::Colon) - } else if lookahead.peek(Token![-]) { + } else if lookahead.peek(Minus) { input.parse().map(Self::Hyphen) } else { Err(lookahead.error()) @@ -720,12 +769,12 @@ impl ToTokens for Toggler { } #[derive(Debug, Clone)] -pub struct ControlFlow { - pub at_token: Token![@], - pub kind: ControlFlowKind, +pub struct ControlFlow { + pub at_token: At, + pub kind: ControlFlowKind, } -impl DiagnosticParse for ControlFlow { +impl DiagnosticParse for ControlFlow { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -735,15 +784,15 @@ impl DiagnosticParse for ControlFlow { kind: { let lookahead = input.lookahead1(); - if lookahead.peek(Token![if]) { + if lookahead.peek(If) { ControlFlowKind::If(input.diagnostic_parse(diagnostics)?) - } else if lookahead.peek(Token![for]) { + } else if lookahead.peek(For) { ControlFlowKind::For(input.diagnostic_parse(diagnostics)?) - } else if lookahead.peek(Token![while]) { + } else if lookahead.peek(While) { ControlFlowKind::While(input.diagnostic_parse(diagnostics)?) - } else if lookahead.peek(Token![match]) { + } else if lookahead.peek(Match) { ControlFlowKind::Match(input.diagnostic_parse(diagnostics)?) - } else if lookahead.peek(Token![let]) { + } else if lookahead.peek(Let) { let Stmt::Local(local) = input.parse()? else { unreachable!() }; @@ -757,7 +806,7 @@ impl DiagnosticParse for ControlFlow { } } -impl ToTokens for ControlFlow { +impl ToTokens for ControlFlow { fn to_tokens(&self, tokens: &mut TokenStream) { self.at_token.to_tokens(tokens); match &self.kind { @@ -771,23 +820,23 @@ impl ToTokens for ControlFlow { } #[derive(Debug, Clone)] -pub enum ControlFlowKind { +pub enum ControlFlowKind { Let(Local), - If(If), - For(For), - While(While), - Match(Match), + If(IfExpr), + For(ForExpr), + While(WhileExpr), + Match(MatchExpr), } #[derive(Debug, Clone)] -pub struct If { - pub if_token: Token![if], +pub struct IfExpr { + pub if_token: If, pub cond: Expr, - pub then_branch: Block, - pub else_branch: Option<(Token![@], Token![else], Box)>, + pub then_branch: Block, + pub else_branch: Option<(At, Else, Box>)>, } -impl DiagnosticParse for If { +impl DiagnosticParse for IfExpr { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -797,7 +846,7 @@ impl DiagnosticParse for If { cond: input.call(Expr::parse_without_eager_brace)?, then_branch: input.diagnostic_parse(diagnostics)?, else_branch: { - if input.peek(Token![@]) && input.peek2(Token![else]) { + if input.peek(At) && input.peek2(Else) { Some(( input.parse()?, input.parse()?, @@ -811,7 +860,7 @@ impl DiagnosticParse for If { } } -impl ToTokens for If { +impl ToTokens for IfExpr { fn to_tokens(&self, tokens: &mut TokenStream) { self.if_token.to_tokens(tokens); self.cond.to_tokens(tokens); @@ -825,19 +874,19 @@ impl ToTokens for If { } #[derive(Debug, Clone)] -pub enum IfOrBlock { - If(If), - Block(Block), +pub enum IfOrBlock { + If(IfExpr), + Block(Block), } -impl DiagnosticParse for IfOrBlock { +impl DiagnosticParse for IfOrBlock { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, ) -> syn::Result { let lookahead = input.lookahead1(); - if lookahead.peek(Token![if]) { + if lookahead.peek(If) { input.diagnostic_parse(diagnostics).map(Self::If) } else if lookahead.peek(Brace) { input.diagnostic_parse(diagnostics).map(Self::Block) @@ -847,7 +896,7 @@ impl DiagnosticParse for IfOrBlock { } } -impl ToTokens for IfOrBlock { +impl ToTokens for IfOrBlock { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Self::If(if_) => if_.to_tokens(tokens), @@ -857,15 +906,15 @@ impl ToTokens for IfOrBlock { } #[derive(Debug, Clone)] -pub struct For { - pub for_token: Token![for], +pub struct ForExpr { + pub for_token: For, pub pat: Pat, - pub in_token: Token![in], + pub in_token: In, pub expr: Expr, - pub body: Block, + pub body: Block, } -impl DiagnosticParse for For { +impl DiagnosticParse for ForExpr { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -880,7 +929,7 @@ impl DiagnosticParse for For { } } -impl ToTokens for For { +impl ToTokens for ForExpr { fn to_tokens(&self, tokens: &mut TokenStream) { self.for_token.to_tokens(tokens); self.pat.to_tokens(tokens); @@ -891,13 +940,13 @@ impl ToTokens for For { } #[derive(Debug, Clone)] -pub struct While { - pub while_token: Token![while], +pub struct WhileExpr { + pub while_token: While, pub cond: Expr, - pub body: Block, + pub body: Block, } -impl DiagnosticParse for While { +impl DiagnosticParse for WhileExpr { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -910,7 +959,7 @@ impl DiagnosticParse for While { } } -impl ToTokens for While { +impl ToTokens for WhileExpr { fn to_tokens(&self, tokens: &mut TokenStream) { self.while_token.to_tokens(tokens); self.cond.to_tokens(tokens); @@ -919,14 +968,14 @@ impl ToTokens for While { } #[derive(Debug, Clone)] -pub struct Match { - pub match_token: Token![match], +pub struct MatchExpr { + pub match_token: Match, pub expr: Expr, pub brace_token: Brace, - pub arms: Vec, + pub arms: Vec>, } -impl DiagnosticParse for Match { +impl DiagnosticParse for MatchExpr { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -951,7 +1000,7 @@ impl DiagnosticParse for Match { } } -impl ToTokens for Match { +impl ToTokens for MatchExpr { fn to_tokens(&self, tokens: &mut TokenStream) { self.match_token.to_tokens(tokens); self.expr.to_tokens(tokens); @@ -964,15 +1013,15 @@ impl ToTokens for Match { } #[derive(Debug, Clone)] -pub struct MatchArm { +pub struct MatchArm { pub pat: Pat, - pub guard: Option<(Token![if], Expr)>, - pub fat_arrow_token: Token![=>], - pub body: Markup, - pub comma_token: Option, + pub guard: Option<(If, Expr)>, + pub fat_arrow_token: FatArrow, + pub body: Markup, + pub comma_token: Option, } -impl DiagnosticParse for MatchArm { +impl DiagnosticParse for MatchArm { fn diagnostic_parse( input: ParseStream, diagnostics: &mut Vec, @@ -980,7 +1029,7 @@ impl DiagnosticParse for MatchArm { Ok(Self { pat: Pat::parse_multi_with_leading_vert(input)?, guard: { - if input.peek(Token![if]) { + if input.peek(If) { Some((input.parse()?, input.parse()?)) } else { None @@ -988,7 +1037,7 @@ impl DiagnosticParse for MatchArm { }, fat_arrow_token: input.parse()?, body: Markup::diagnostic_parse_in_block(input, diagnostics)?, - comma_token: if input.peek(Token![,]) { + comma_token: if input.peek(Comma) { Some(input.parse()?) } else { None @@ -997,7 +1046,7 @@ impl DiagnosticParse for MatchArm { } } -impl ToTokens for MatchArm { +impl ToTokens for MatchArm { fn to_tokens(&self, tokens: &mut TokenStream) { self.pat.to_tokens(tokens); if let Some((if_token, guard)) = &self.guard { diff --git a/maud_macros/src/generate.rs b/maud_macros/src/generate.rs index 966c8cbd..303bda69 100644 --- a/maud_macros/src/generate.rs +++ b/maud_macros/src/generate.rs @@ -4,7 +4,7 @@ use syn::{parse_quote, token::Brace, Expr, Local}; use crate::{ast::*, escape}; -pub fn generate(markups: Markups, output_ident: Ident) -> TokenStream { +pub fn generate(markups: Markups, output_ident: Ident) -> TokenStream { let mut build = Builder::new(output_ident.clone()); Generator::new(output_ident).markups(markups, &mut build); build.finish() @@ -23,13 +23,13 @@ impl Generator { Builder::new(self.output_ident.clone()) } - fn markups(&self, markups: Markups, build: &mut Builder) { + fn markups>(&self, markups: Markups, build: &mut Builder) { for markup in markups.markups { self.markup(markup, build); } } - fn markup(&self, markup: Markup, build: &mut Builder) { + fn markup>(&self, markup: Markup, build: &mut Builder) { match markup { Markup::Block(block) => { if block.markups.markups.iter().any(|markup| { @@ -48,13 +48,13 @@ impl Generator { } Markup::Lit(lit) => build.push_escaped(&lit.to_string()), Markup::Splice { expr, .. } => self.splice(expr, build), - Markup::Element(element) => self.element(element, build), + Markup::Element(element) => self.element(element.into(), build), Markup::ControlFlow(control_flow) => self.control_flow(control_flow, build), Markup::Semi(_) => {} } } - fn block(&self, block: Block, build: &mut Builder) { + fn block>(&self, block: Block, build: &mut Builder) { let markups = { let mut build = self.builder(); self.markups(block.markups, &mut build); @@ -184,7 +184,7 @@ impl Generator { } } - fn control_flow(&self, control_flow: ControlFlow, build: &mut Builder) { + fn control_flow>(&self, control_flow: ControlFlow, build: &mut Builder) { match control_flow.kind { ControlFlowKind::If(if_) => self.control_flow_if(if_, build), ControlFlowKind::Let(let_) => self.control_flow_let(let_, build), @@ -194,14 +194,14 @@ impl Generator { } } - fn control_flow_if( + fn control_flow_if>( &self, - If { + IfExpr { if_token, cond, then_branch, else_branch, - }: If, + }: IfExpr, build: &mut Builder, ) { build.push_tokens(quote!(#if_token #cond)); @@ -213,7 +213,11 @@ impl Generator { } } - fn control_flow_if_or_block(&self, if_or_block: IfOrBlock, build: &mut Builder) { + fn control_flow_if_or_block>( + &self, + if_or_block: IfOrBlock, + build: &mut Builder, + ) { match if_or_block { IfOrBlock::If(if_) => self.control_flow_if(if_, build), IfOrBlock::Block(block) => self.block(block, build), @@ -224,42 +228,42 @@ impl Generator { build.push_tokens(let_.to_token_stream()); } - fn control_flow_for( + fn control_flow_for>( &self, - For { + ForExpr { for_token, pat, in_token, expr, body, - }: For, + }: ForExpr, build: &mut Builder, ) { build.push_tokens(quote!(#for_token #pat #in_token (#expr))); self.block(body, build); } - fn control_flow_while( + fn control_flow_while>( &self, - While { + WhileExpr { while_token, cond, body, - }: While, + }: WhileExpr, build: &mut Builder, ) { build.push_tokens(quote!(#while_token #cond)); self.block(body, build); } - fn control_flow_match( + fn control_flow_match>( &self, - Match { + MatchExpr { match_token, expr, brace_token, arms, - }: Match, + }: MatchExpr, build: &mut Builder, ) { let arms = {