1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, Data, DeriveInput, Fields};
6
7#[proc_macro_derive(AstNode)]
8pub fn ast_node_derive(input: TokenStream) -> TokenStream {
9 let input = parse_macro_input!(input as DeriveInput);
10
11 let struct_name = input.ident;
12 match &input.data {
13 Data::Struct(data) => {
14 let fields = match &data.fields {
15 Fields::Named(fields) => &fields.named,
16 _ => unimplemented!(),
17 };
18 let field_names: Vec<_> = fields
19 .iter()
20 .filter_map(|f| {
21 if f.ident.as_ref().unwrap() != "span" {
22 Some(f.ident.as_ref().unwrap())
23 } else {
24 None
25 }
26 })
27 .collect();
28
29 let gen = quote! {
30 impl AstNode for #struct_name {
31 fn span(&self) -> Span {
32 self.span
33 }
34
35 fn print(&self, indent: usize) -> String {
36 let indent_str = " ".repeat(indent);
37 let mut result = format!("{}{}\n", indent_str, stringify!(#struct_name));
38 #(
39 let field_name = stringify!(#field_names);
40 let field_value = self.#field_names.print_ast(indent + 2);
41 result.push_str(&format!("{} {}{}\n", indent_str, field_name, field_value));
42 )*
43 result
44 }
45 }
46 };
47
48 gen.into()
49 }
50 Data::Enum(e) => {
51 let cases: Vec<_> = e.variants.iter().map(|v| v.ident.clone()).collect();
52 let gen = quote! {
53 impl AstNode for #struct_name {
54 fn print(&self, indent: usize) -> String {
55 use #struct_name::*;
56 match self {
57 #(
58 #cases(c) => c.print(indent),
59 )*
60 }
61 }
62
63 fn span(&self) -> Span {
64 use #struct_name::*;
65 match self {
66 #(
67 #cases(c) => c.span(),
68 )*
69 }
70 }
71 }
72 };
73
74 gen.into()
75 }
76 Data::Union(_) => panic!("Not allowed on unions!"),
77 }
78}
79
80#[proc_macro_derive(PrintAst)]
81pub fn print_ast_derive(input: TokenStream) -> TokenStream {
82 let input = parse_macro_input!(input as DeriveInput);
83
84 let struct_name = input.ident;
85 match &input.data {
86 Data::Struct(data) => {
87 let fields = match &data.fields {
88 Fields::Named(fields) => &fields.named,
89 _ => unimplemented!(),
90 };
91 let field_names: Vec<_> = fields
92 .iter()
93 .filter_map(|f| {
94 if f.ident.as_ref().unwrap() != "span" {
95 Some(f.ident.as_ref().unwrap())
96 } else {
97 None
98 }
99 })
100 .collect();
101
102 let gen = quote! {
103 impl PrintAst for #struct_name {
104 fn print_ast(&self, indent: usize) -> String {
105 let indent_str = " ".repeat(indent);
106 let mut result = format!("{}{}\n", indent_str, stringify!(#struct_name));
107 #(
108 let field_name = stringify!(#field_names);
109 let field_value = self.#field_names.print_ast(indent + 2);
110 result.push_str(&format!("{} {}{}\n", indent_str, field_name, field_value));
111 )*
112 result
113 }
114 }
115 };
116
117 gen.into()
118 }
119 Data::Enum(e) => {
120 let cases: Vec<_> = e.variants.iter().map(|v| v.ident.clone()).collect();
121
122 let gen = quote! {
123 impl PrintAst for #struct_name {
124 fn print_ast(&self, indent: usize) -> String {
125 use #struct_name::*;
126 match self {
127 #(
128 #cases(c) => c.print_ast(indent),
129 )*
130 }
131 }
132 }
133 };
134
135 gen.into()
136 }
137 Data::Union(_) => panic!("Not allowed on unions!"),
138 }
139}