mutant_kraken_macros/
lib.rs1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::quote;
4
5#[derive(serde::Deserialize)]
6struct JsonItem {
7 r#type: String,
8 named: bool,
9}
10
11#[proc_macro]
12pub fn generate_kotlin_types_enum(_input: TokenStream) -> TokenStream {
13 const JSON_DATA: &str = tree_sitter_kotlin::NODE_TYPES;
14 let json_items: Vec<JsonItem> = serde_json::from_str(JSON_DATA).expect("Failed to parse JSON");
15
16 let mut named_types: Vec<_> = json_items
17 .iter()
18 .filter(|item| item.named)
19 .map(|item| snake_to_camel(&item.r#type))
20 .collect();
21 named_types.push("ERROR".into());
23 named_types.push("Remove".into());
24 named_types.push("RemoveOperator".into());
25 named_types.push("AnyParent".into());
26
27 let non_named_types: Vec<_> = json_items
28 .iter()
29 .filter(|item| !item.named)
30 .map(|item| &item.r#type)
31 .collect::<Vec<_>>();
32
33 let enum_variants = named_types.iter().map(|name| {
34 let variant_name = syn::Ident::new(name, proc_macro2::Span::call_site());
35 quote! {
36 #variant_name,
37 }
38 });
39
40 let display_match_arms = named_types.iter().map(|name| {
41 let variant_name = syn::Ident::new(name, proc_macro2::Span::call_site());
42 quote! {
43 KotlinTypes::#variant_name => write!(f, "{}", #name),
44 }
45 });
46
47 let convert_match_arms = named_types.iter().map(|name| {
48 let variant_name = syn::Ident::new(name, proc_macro2::Span::call_site());
49 quote! {
50 #name => KotlinTypes::#variant_name,
51 }
52 });
53
54 let expanded = quote! {
55 pub const NON_NAMED_TYPES: &[&str] = &[#(#non_named_types),*];
56 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
57 pub enum KotlinTypes {
58 #(#enum_variants)*
59 NonNamedType(String)
60 }
61
62 impl std::fmt::Display for KotlinTypes {
63 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
64 match self {
65 #(#display_match_arms)*
66 KotlinTypes::NonNamedType(s) => write!(f, "{}", s)
67 }
68 }
69 }
70
71 impl KotlinTypes {
72 pub fn new(s: &str) -> std::result::Result<KotlinTypes, String> {
73 if NON_NAMED_TYPES.contains(&s) {
74 return Ok(KotlinTypes::NonNamedType(s.to_string()))
75 }
76 let name: String = s.split('_')
77 .map(|p| {
78 if !p.is_empty() {
79 let mut v: Vec<char> = p.chars().collect();
80 v[0] = v[0].to_uppercase().next().unwrap();
81 let x: String = v.into_iter().collect();
82 x
83 } else {
84 p.to_string()
85 }
86 })
87 .collect();
88 let res = match name.as_str() {
89 #(#convert_match_arms)*
90 _ => {
91 return Err(format!("could not convert {} to kotlin type", s))
92 }
93 };
94
95 Ok(res)
96 }
97
98 pub fn as_str(&self) -> String {
99 let mut second_upper = 0;
100 let mut x = format!("{}", *self);
101 x.as_bytes().iter().enumerate().for_each(|(i, c)| {
102 if (*c as char).is_uppercase() && i != 0 {
103 second_upper = i
104 }
105 });
106 x = x.to_lowercase();
107 if second_upper != 0 {
108 x.insert(second_upper, '_');
109 }
110 x
111 }
112 }
113 };
114
115 TokenStream::from(expanded)
116}
117
118fn snake_to_camel(name: &str) -> String {
119 name.split('_')
121 .map(|p| {
122 if !p.is_empty() {
123 let mut v: Vec<char> = p.chars().collect();
124 v[0] = v[0].to_uppercase().next().unwrap();
125 let x: String = v.into_iter().collect();
126 x
127 } else {
128 p.to_string()
129 }
130 })
131 .collect()
132}