Compare commits

...

3 Commits

4 changed files with 86 additions and 15 deletions

View File

@@ -3,7 +3,6 @@ use paste::paste;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::parse::{Parse, ParseStream, Result}; use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::{Expr, Ident, Token, parse_macro_input}; use syn::{Expr, Ident, Token, parse_macro_input};
macro_rules! generate_headings { macro_rules! generate_headings {
@@ -54,25 +53,54 @@ impl Parse for Argument {
} }
struct BaseElement { struct BaseElement {
value: Expr, values: Vec<Expr>,
params: Punctuated<Property, Token![,]>, params: Vec<Property>,
} }
impl Parse for BaseElement { impl Parse for BaseElement {
fn parse(input: ParseStream) -> Result<Self> { fn parse(input: ParseStream) -> Result<Self> {
let mut values = Vec::new();
let mut params = Vec::new();
while !input.is_empty() {
if input.peek(Ident) && input.peek2(Token![=]) {
let property: Property = input.parse()?;
params.push(property);
} else {
let value: Expr = input.parse()?; let value: Expr = input.parse()?;
let _ = input.parse::<Token![,]>(); values.push(value);
let params: Punctuated<Property, Token![,]> = Punctuated::parse_terminated(input)?; }
Ok(BaseElement { value, params }) if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
}
Ok(BaseElement { values, params })
} }
} }
fn heading(level: &str, item: TokenStream) -> TokenStream { #[proc_macro]
let BaseElement { value, params } = parse_macro_input!(item as BaseElement); pub fn paragraph(input: TokenStream) -> TokenStream {
base("p", input)
}
#[proc_macro]
pub fn division(input: TokenStream) -> TokenStream {
base("div", input)
}
fn base(elem: &str, item: TokenStream) -> TokenStream {
let BaseElement { values, params } = parse_macro_input!(item as BaseElement);
let values = values.iter();
let formated_values = if values.len() > 1 {
let mut s = "\n".to_string();
s.push_str("{}\n".repeat(values.len()).as_str());
s
} else {
"{}".to_string()
};
let expanded = match params.is_empty() { let expanded = match params.is_empty() {
false => { false => {
let mut values = Vec::new(); let mut options_values = Vec::new();
let formated_names = params let formated_names = params
.iter() .iter()
@@ -80,18 +108,23 @@ fn heading(level: &str, item: TokenStream) -> TokenStream {
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(" "); .join(" ");
let format_string = format!("<h{} {formated_names}>{{}}</h{}>", level, level); let format_string =
format!("<{} {formated_names}>{}</{}>", elem, formated_values, elem);
for property in params { for property in params {
values.push(property.value); options_values.push(property.value);
} }
quote!(format!(#format_string, #(#values), *, #value)) quote!(format!(#format_string, #(#options_values), *, #(#values), *))
} }
true => { true => {
let format_string = format!("<h{}>{{}}</h{}>", level, level); let format_string = format!("<{}>{}</{}>", elem, formated_values, elem);
quote!(format!(#format_string, #value)) quote!(format!(#format_string, #(#values), *))
} }
}; };
TokenStream::from(expanded) TokenStream::from(expanded)
} }
fn heading(level: &str, item: TokenStream) -> TokenStream {
base(format!("h{level}").as_str(), item)
}

25
tests/tests_divisions.rs Normal file
View File

@@ -0,0 +1,25 @@
#[cfg(test)]
mod tests {
use web_macro::{division, heading1};
#[test]
fn test_base() {
assert_eq!("<div>test</div>", division!("test"))
}
#[test]
fn test_multiple_elements() {
assert_eq!(
"<div>\n<h1>one</h1>\n<h1>two</h1>\n</div>",
division!(heading1!("one"), heading1!("two"))
)
}
#[test]
fn test_multiple_elements_with_options() {
assert_eq!(
"<div id=\"division_id\">\n<h1>one</h1>\n<h1 class=\"tiny\">two</h1>\n</div>",
division!(heading1!("one"), heading1!("two", class="tiny"), id="division_id")
)
}
}

13
tests/tests_paragraphs.rs Normal file
View File

@@ -0,0 +1,13 @@
#[cfg(test)]
mod tests {
use web_macro::paragraph;
#[test]
fn test_base() {
assert_eq!("<p>test</p>", paragraph!("test"))
}
#[test]
fn test_params() {
assert_eq!("<p id=\"oui\">test</p>", paragraph!("test", id = "oui"))
}
}