use quote::format_ident; use syn::{bracketed, parenthesized, parse::{Parse, ParseStream}, Expr, Ident, LitStr, Token, Type}; use crate::form::{ParsedChild, ParsedInput, ParsedOnSubmit, SelectOptions}; macro_rules! parse_key_value { ($input:expr, $name:ident as $ty:ty) => {{ let key = $input.parse::()?; $input.parse::()?; let value = $input.parse::<$ty>()?; if key != format_ident!(stringify!($name)) { panic!("Expected key name to be {}, but found: {key}", stringify!($name)); } if $input.peek(Token![,]) { $input.parse::()?; } value }}; } impl Parse for SelectOptions { fn parse(input: ParseStream) -> syn::Result { let content; bracketed!(content in input); let inner = content.parse_terminated( |arg| { let paren; parenthesized!(paren in arg); let lit = paren.parse::()?; paren.parse::()?; let expr = paren.parse::()?; Ok((lit, expr)) }, Token![,], )?; Ok(Self(inner.into_iter().collect())) } } impl Parse for ParsedInput { fn parse(input: ParseStream) -> syn::Result { let on_submit = input.parse::()?; if on_submit != format_ident!("on_submit") { panic!("Did not find correct `on_submit`: {on_submit}") } input.parse::()?; let on_submit = input.parse::()?; let mut children = Vec::new(); while !input.is_empty() { children.push(input.parse::()?); } Ok(Self { on_submit, children, }) } } impl Parse for ParsedChild { fn parse(input: ParseStream) -> syn::Result { input.parse::()?; let variant = input.parse::()?; let output = match variant { variant if variant == format_ident!("Input") => { let name = parse_key_value!(input, name as Ident); let rust_type = parse_key_value!(input, rust_type as Type); let html_type = parse_key_value!(input, html_type as LitStr); let label = parse_key_value!(input, label as LitStr); ParsedChild::Input { name, rust_type, html_type, label, } } variant if variant == format_ident!("Select") => { let name = parse_key_value!(input, name as Ident); let rust_type = parse_key_value!(input, rust_type as Type); let label = parse_key_value!(input, label as LitStr); let options = parse_key_value!(input, options as SelectOptions); ParsedChild::Select { name, label, options, rust_type, } } _ => panic!("Unkown form child variant: {variant}"), }; input.parse::()?; input.parse::]>()?; Ok(output) } } impl Parse for ParsedOnSubmit { fn parse(input: ParseStream) -> syn::Result { let mut inputs = Vec::new(); input.parse::()?; while !input.peek(Token![|]) { inputs.push(input.parse::()?); if input.peek(Token![,]) { input.parse::()?; } } input.parse::()?; let block = input.parse::()?; input.parse::()?; Ok(Self { inputs, block }) } }