use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
use quick_xml::events::{Event, BytesStart};
use quick_xml::Reader;
use std::str;
mod codegen;
use codegen::*;
#[proc_macro]
pub fn xaml(input: TokenStream) -> TokenStream {
let input_str = parse_macro_input!(input as LitStr);
let xaml_content = input_str.value();
match parse_xaml(&xaml_content) {
Ok(code) => code.into(),
Err(e) => {
let error_msg = format!("XAML parse error: {}", e);
quote! {
compile_error!(#error_msg)
}
.into()
}
}
}
fn parse_xaml(xaml: &str) -> Result<proc_macro2::TokenStream, String> {
let mut reader = Reader::from_str(xaml);
reader.config_mut().trim_text(true);
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) | Ok(Event::Empty(e)) => {
let name_bytes = e.name();
let element_name = str::from_utf8(name_bytes.as_ref())
.map_err(|e| format!("Invalid UTF-8: {}", e))?;
return generate_code_for_element(&e, element_name);
}
Ok(Event::Eof) => break,
Err(e) => return Err(format!("XML parse error: {}", e)),
_ => (),
}
buf.clear();
}
Err("No root element found".to_string())
}
fn generate_code_for_element(
element: &BytesStart,
element_name: &str,
) -> Result<proc_macro2::TokenStream, String> {
match element_name {
"Button" => generate_button_code(element),
"TextBlock" => generate_textblock_code(element),
"TextBox" => generate_textbox_code(element),
"StackPanel" => generate_stackpanel_code(element),
"Grid" => generate_grid_code(element),
"ScrollViewer" => generate_scrollviewer_code(element),
_ => Err(format!("Unsupported XAML element: {}", element_name)),
}
}