From 9bd607d6bc015eb26cf716f481bebf2878a2eeba Mon Sep 17 00:00:00 2001 From: RedPhoenixQ Date: Fri, 20 Oct 2023 00:25:22 +0200 Subject: [PATCH 1/3] Accept literals in attribute names --- maud/tests/basic_syntax.rs | 9 +++++++++ maud_macros/src/ast.rs | 10 +++++++++- maud_macros/src/parse.rs | 13 +++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/maud/tests/basic_syntax.rs b/maud/tests/basic_syntax.rs index b84f7951..b0fd4806 100644 --- a/maud/tests/basic_syntax.rs +++ b/maud/tests/basic_syntax.rs @@ -181,6 +181,15 @@ fn hyphens_in_attribute_names() { ); } +#[test] +fn string_literals_in_attribute_names() { + let result = html! { this "@sentence:-is.not"="false" of-course {} }; + assert_eq!( + result.into_string(), + r#""# + ); +} + #[test] fn class_shorthand() { let result = html! { p { "Hi, " span.name { "Lyra" } "!" } }; diff --git a/maud_macros/src/ast.rs b/maud_macros/src/ast.rs index cd8a2cef..c8779767 100644 --- a/maud_macros/src/ast.rs +++ b/maud_macros/src/ast.rs @@ -217,5 +217,13 @@ pub fn join_ranges>(ranges: I) -> SpanRange { } pub fn name_to_string(name: TokenStream) -> String { - name.into_iter().map(|token| token.to_string()).collect() + name.into_iter() + .map(|token| { + if let TokenTree::Literal(literal) = token { + literal.to_string().trim_matches('"').to_string() + } else { + token.to_string() + } + }) + .collect() } diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 3521ce42..662b8309 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -702,12 +702,13 @@ impl Parser { /// Parses an identifier, without dealing with namespaces. fn try_name(&mut self) -> Option { let mut result = Vec::new(); - if let Some(token @ TokenTree::Ident(_)) = self.peek() { - self.advance(); - result.push(token); - } else { - return None; - } + match self.peek() { + Some(token @ TokenTree::Ident(_)) | Some(token @ TokenTree::Literal(_)) => { + self.advance(); + result.push(token); + } + _ => return None, + }; let mut expect_ident = false; loop { expect_ident = match self.peek() { From 54ebfd862351af265b93075ba9e078a190f85e9d Mon Sep 17 00:00:00 2001 From: RedPhoenixQ Date: Sun, 5 Nov 2023 13:13:44 +0100 Subject: [PATCH 2/3] Accept literals in attribute names --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1d91020..60f636d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ [#377](https://github.com/lambda-fairy/maud/pull/377) - Implement `Render` for `Arc` [#380](https://github.com/lambda-fairy/maud/pull/380) +- Accept literals in attribute names + [#396](https://github.com/lambda-fairy/maud/pull/396) ## [0.25.0] - 2023-04-16 From c33ee62d87f7d0d2840c0b124ac424f1c311d353 Mon Sep 17 00:00:00 2001 From: RedPhoenixQ Date: Mon, 6 Nov 2023 11:31:13 +0100 Subject: [PATCH 3/3] Propper handling of literals in name_to_string() --- maud/tests/basic_syntax.rs | 19 +++++++++++++++++++ maud_macros/src/ast.rs | 11 ++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/maud/tests/basic_syntax.rs b/maud/tests/basic_syntax.rs index b0fd4806..96e0235e 100644 --- a/maud/tests/basic_syntax.rs +++ b/maud/tests/basic_syntax.rs @@ -190,6 +190,25 @@ fn string_literals_in_attribute_names() { ); } +#[test] +fn raw_string_literals_in_attribute_names() { + let result = html! { this r#"@sentence:-is.not"#="false" of-course {} }; + assert_eq!( + result.into_string(), + r#""# + ); +} + +#[test] +fn other_literals_in_attribute_names() { + let result = + html! { this b"byte_string"="false" 123="123" 2.5 true 'a'="a" b'b'="b" of-course {} }; + assert_eq!( + result.into_string(), + r#""# + ); +} + #[test] fn class_shorthand() { let result = html! { p { "Hi, " span.name { "Lyra" } "!" } }; diff --git a/maud_macros/src/ast.rs b/maud_macros/src/ast.rs index c8779767..16d228e3 100644 --- a/maud_macros/src/ast.rs +++ b/maud_macros/src/ast.rs @@ -1,5 +1,6 @@ use proc_macro2::{TokenStream, TokenTree}; use proc_macro_error::SpanRange; +use syn::Lit; #[derive(Debug)] pub enum Markup { @@ -220,7 +221,15 @@ pub fn name_to_string(name: TokenStream) -> String { name.into_iter() .map(|token| { if let TokenTree::Literal(literal) = token { - literal.to_string().trim_matches('"').to_string() + match Lit::new(literal.clone()) { + Lit::Str(str) => str.value(), + Lit::Char(char) => char.value().to_string(), + Lit::ByteStr(byte) => { + String::from_utf8(byte.value()).expect("Invalid utf8 byte") + } + Lit::Byte(byte) => (byte.value() as char).to_string(), + _ => literal.to_string(), + } } else { token.to_string() }