First commit

This commit is contained in:
2026-03-02 22:45:57 +01:00
commit 7b6eba8ca5
7 changed files with 227 additions and 0 deletions

97
src/lib.rs Normal file
View File

@@ -0,0 +1,97 @@
extern crate proc_macro;
use paste::paste;
use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::{Expr, Ident, Token, parse_macro_input};
macro_rules! generate_headings {
($($v:expr),*) => {
$(
paste! {
#[proc_macro]
pub fn [<heading$v>](item: TokenStream) -> TokenStream {
heading(stringify!($v), item)
}
}
)*
};
}
generate_headings!(1, 2, 3, 4, 5, 6);
struct Property {
name: Ident,
value: Expr,
}
impl Parse for Property {
fn parse(input: ParseStream) -> Result<Self> {
let name: Ident = input.parse()?;
input.parse::<Token![=]>()?;
let value: Expr = input.parse()?;
Ok(Property { name, value })
}
}
struct Argument {
value: Option<Ident>,
}
impl Parse for Argument {
fn parse(input: ParseStream) -> Result<Self> {
let value: Option<Ident> =
if input.peek(Ident) && input.peek2(Token![:]) && !input.peek3(Token![:]) {
let val = input.parse()?;
input.parse::<Token![:]>()?;
val
} else {
None
};
Ok(Argument { value })
}
}
struct BaseElement {
value: Expr,
params: Punctuated<Property, Token![,]>,
}
impl Parse for BaseElement {
fn parse(input: ParseStream) -> Result<Self> {
let value: Expr = input.parse()?;
let _ = input.parse::<Token![,]>();
let params: Punctuated<Property, Token![,]> = Punctuated::parse_terminated(input)?;
Ok(BaseElement { value, params })
}
}
fn heading(level: &str, item: TokenStream) -> TokenStream {
let BaseElement { value, params } = parse_macro_input!(item as BaseElement);
let expanded = match params.is_empty() {
false => {
let mut values = Vec::new();
let formated_names = params
.iter()
.map(|x| format!("{}=\"{{}}\"", x.name))
.collect::<Vec<String>>()
.join(" ");
let format_string = format!("<h{} {formated_names}>{{}}</h{}>", level, level);
for property in params {
values.push(property.value);
}
quote!(format!(#format_string, #(#values), *, #value))
}
true => {
let format_string = format!("<h{}>{{}}</h{}>", level, level);
quote!(format!(#format_string, #value))
}
};
TokenStream::from(expanded)
}