1use proc_macro::TokenStream;
7use quote::quote;
8use syn::{parse_macro_input, LitStr};
9use quick_xml::events::{Event, BytesStart};
10use quick_xml::Reader;
11use std::str;
12
13mod codegen;
14use codegen::*;
15
16#[proc_macro]
50pub fn xaml(input: TokenStream) -> TokenStream {
51 let input_str = parse_macro_input!(input as LitStr);
52 let xaml_content = input_str.value();
53
54 match parse_xaml(&xaml_content) {
56 Ok(code) => code.into(),
57 Err(e) => {
58 let error_msg = format!("XAML parse error: {}", e);
59 quote! {
60 compile_error!(#error_msg)
61 }
62 .into()
63 }
64 }
65}
66
67fn parse_xaml(xaml: &str) -> Result<proc_macro2::TokenStream, String> {
69 let mut reader = Reader::from_str(xaml);
70 reader.config_mut().trim_text(true);
71
72 let mut buf = Vec::new();
73
74 loop {
75 match reader.read_event_into(&mut buf) {
76 Ok(Event::Start(e)) | Ok(Event::Empty(e)) => {
77 let name_bytes = e.name();
78 let element_name = str::from_utf8(name_bytes.as_ref())
79 .map_err(|e| format!("Invalid UTF-8: {}", e))?;
80
81 return generate_code_for_element(&e, element_name);
82 }
83 Ok(Event::Eof) => break,
84 Err(e) => return Err(format!("XML parse error: {}", e)),
85 _ => (),
86 }
87 buf.clear();
88 }
89
90 Err("No root element found".to_string())
91}
92
93fn generate_code_for_element(
95 element: &BytesStart,
96 element_name: &str,
97) -> Result<proc_macro2::TokenStream, String> {
98 match element_name {
99 "Button" => generate_button_code(element),
100 "TextBlock" => generate_textblock_code(element),
101 "TextBox" => generate_textbox_code(element),
102 "StackPanel" => generate_stackpanel_code(element),
103 "Grid" => generate_grid_code(element),
104 "ScrollViewer" => generate_scrollviewer_code(element),
105 _ => Err(format!("Unsupported XAML element: {}", element_name)),
106 }
107}