1mod error;
2mod lexer;
3mod parser;
4
5use crate::lexer::Lexer;
6use crate::parser::{Def, Parser};
7use proc_macro::TokenStream;
8use quote::{format_ident, quote};
9use std::fs;
10use std::path::PathBuf;
11
12#[proc_macro]
14pub fn include_sidl(input: TokenStream) -> TokenStream {
15 let input_path_str = input.to_string().trim_matches('"').to_string();
16
17 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
19 let path = PathBuf::from(manifest_dir).join(&input_path_str);
20
21 let sidl_content = match fs::read_to_string(&path) {
22 Ok(content) => content,
23 Err(e) => {
24 return syn::Error::new(
25 proc_macro2::Span::call_site(),
26 format!("Failed to read SIDL file {:?}: {}", path, e),
27 )
28 .to_compile_error()
29 .into();
30 }
31 };
32
33 let lexer = Lexer::new(&sidl_content);
34 let mut parser = match Parser::new(lexer) {
35 Ok(p) => p,
36 Err(e) => {
37 return syn::Error::new(
38 proc_macro2::Span::call_site(),
39 format!("SIDL Parser Init Error: {}", e),
40 )
41 .to_compile_error()
42 .into();
43 }
44 };
45
46 let defs = match parser.parse() {
47 Ok(d) => d,
48 Err(e) => {
49 return syn::Error::new(
50 proc_macro2::Span::call_site(),
51 format!("SIDL Parse Error: {}", e),
52 )
53 .to_compile_error()
54 .into();
55 }
56 };
57
58 let mut expanded_tokens = proc_macro2::TokenStream::new();
59
60 for def in defs {
61 match def {
62 Def::Struct(s) => {
63 let name = format_ident!("{}", s.name);
64 let fields = s.fields.iter().map(|(n, t)| {
65 let field_name = format_ident!("{}", n);
66 let field_type = format_ident!("{}", t);
67 quote! { pub #field_name: #field_type, }
68 });
69
70 expanded_tokens.extend(quote! {
71 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Diplomat)]
72 pub struct #name {
73 #(#fields)*
74 }
75 });
76 }
77 Def::Service(s) => {
78 let name = format_ident!("{}", s.name);
79 let methods = s.methods.iter().map(|m| {
80 let method_name = format_ident!("{}", m.name);
81 let arg_name = format_ident!("{}", m.arg_name);
82 let arg_type = format_ident!("{}", m.arg_type);
83 let ret_type = format_ident!("{}", m.ret_type);
84
85 quote! {
86 async fn #method_name(&self, #arg_name: #arg_type) -> #ret_type;
87 }
88 });
89
90 expanded_tokens.extend(quote! {
91 #[async_trait::async_trait]
92 pub trait #name {
93 #(#methods)*
94 }
95 });
96 }
97 }
98 }
99
100 TokenStream::from(expanded_tokens)
101}
102
103#[proc_macro_derive(Diplomat)]
105pub fn derive_diplomat(input: TokenStream) -> TokenStream {
106 let input = syn::parse_macro_input!(input as syn::DeriveInput);
107 let name = input.ident;
108
109 let expanded = quote! {
110 impl praborrow_diplomacy::Diplomat for #name {}
111 };
112 TokenStream::from(expanded)
113}