rune_macros/
parse.rs
1use crate::{
2 add_trait_bounds,
3 context::{Context, ParseKind, Tokens},
4};
5use proc_macro2::TokenStream;
6use quote::{quote, quote_spanned};
7use syn::spanned::Spanned as _;
8
9pub struct Derive {
11 input: syn::DeriveInput,
12}
13
14impl syn::parse::Parse for Derive {
15 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
16 Ok(Self {
17 input: input.parse()?,
18 })
19 }
20}
21
22impl Derive {
23 pub(super) fn expand(self, cx: &Context) -> Result<TokenStream, ()> {
24 let attr = cx.type_attrs(&self.input.attrs);
25 let tokens = cx.tokens_with_module(attr.module.as_ref());
26
27 let mut expander = Expander { cx, tokens };
28
29 match &self.input.data {
30 syn::Data::Struct(st) => expander.expand_struct(&self.input, st),
31 syn::Data::Enum(en) => {
32 expander.cx.error(syn::Error::new_spanned(
33 en.enum_token,
34 "not supported on enums",
35 ));
36
37 Err(())
38 }
39 syn::Data::Union(un) => {
40 expander.cx.error(syn::Error::new_spanned(
41 un.union_token,
42 "not supported on unions",
43 ));
44
45 Err(())
46 }
47 }
48 }
49}
50
51struct Expander<'cx> {
52 cx: &'cx Context,
53 tokens: Tokens,
54}
55
56impl Expander<'_> {
57 fn expand_struct(
59 &mut self,
60 input: &syn::DeriveInput,
61 st: &syn::DataStruct,
62 ) -> Result<TokenStream, ()> {
63 self.expand_struct_fields(input, &st.fields)
64 }
65
66 fn expand_struct_fields(
68 &mut self,
69 input: &syn::DeriveInput,
70 fields: &syn::Fields,
71 ) -> Result<TokenStream, ()> {
72 match fields {
73 syn::Fields::Named(named) => self.expand_struct_named(input, named),
74 syn::Fields::Unnamed(..) => {
75 self.cx.error(syn::Error::new_spanned(
76 fields,
77 "Tuple structs are not supported",
78 ));
79 Err(())
80 }
81 syn::Fields::Unit => {
82 self.cx.error(syn::Error::new_spanned(
83 fields,
84 "Unit structs are not supported",
85 ));
86 Err(())
87 }
88 }
89 }
90
91 fn expand_struct_named(
93 &mut self,
94 input: &syn::DeriveInput,
95 named: &syn::FieldsNamed,
96 ) -> Result<TokenStream, ()> {
97 let ident = &input.ident;
98 let mut fields = Vec::new();
99
100 let mut meta_args = Vec::new();
101 let mut meta_parse = Vec::new();
102 let mut meta_fields = Vec::new();
103
104 let ty_attrs = self.cx.type_attrs(&input.attrs);
105 let mut skipped = 0;
106
107 for (i, field) in named.named.iter().enumerate() {
108 let field_attrs = self.cx.field_attrs(&field.attrs);
109 let ident = self.cx.field_ident(field)?;
110
111 if field_attrs.id.is_some() {
112 fields.push(quote_spanned! { field.span() => #ident: Default::default() });
113 skipped += 1;
114 continue;
115 }
116
117 let parse_impl = if let Some(parse_with) = field_attrs.parse_with {
118 quote_spanned!(field.span() => #parse_with(parser)?)
119 } else {
120 quote_spanned!(field.span() => parser.parse()?)
121 };
122
123 if field_attrs.meta.is_none() {
124 fields.push(quote_spanned! { field.span() => #ident: #parse_impl });
125 continue;
126 }
127
128 if i - skipped != meta_fields.len() {
129 self.cx.error(syn::Error::new_spanned(
130 field,
131 "The first sequence of fields may have `#[rune(meta)]`, \
132 but field is outside of that sequence.",
133 ));
134 return Err(());
135 }
136
137 let ident = self.cx.field_ident(field)?;
138 let ty = &field.ty;
139 meta_args.push(quote_spanned!(field.span() => #ident: #ty));
140 meta_parse.push(quote_spanned!(field.span() => let #ident: #ty = #parse_impl));
141 fields.push(quote_spanned! { field.span() => #ident });
142 meta_fields.push(ident);
143 }
144
145 let parser_ident = &if fields.is_empty() {
146 quote!(_parser)
147 } else {
148 quote!(parser)
149 };
150
151 let parse = &self.tokens.parse;
152 let parser = &self.tokens.parser;
153 let compile_error = &self.tokens.compile_error;
154 let result = &self.tokens.result;
155
156 let mut generics = input.generics.clone();
157
158 add_trait_bounds(&mut generics, parse);
159
160 let (impl_generics, type_generics, where_generics) = generics.split_for_impl();
161
162 let inner = if let ParseKind::MetaOnly = ty_attrs.parse {
163 None
164 } else {
165 Some(quote_spanned! {
166 named.span() =>
167 #[automatically_derived]
168 impl #impl_generics #parse for #ident #type_generics #where_generics {
169 fn parse(parser: &mut #parser<'_>) -> #result<Self, #compile_error> {
170 #(#meta_parse;)*
171 Self::parse_with_meta(parser, #(#meta_fields,)*)
172 }
173 }
174 })
175 };
176
177 let output = if !meta_args.is_empty() {
178 quote_spanned! { named.span() =>
179 #[automatically_derived]
180 impl #ident {
181 #[doc = "Parse #ident and attach the given meta"]
182 pub fn parse_with_meta(#parser_ident: &mut #parser<'_>, #(#meta_args,)*)
183 -> #result<Self, #compile_error>
184 {
185 Ok(Self {
186 #(#fields,)*
187 })
188 }
189 }
190
191 #inner
192 }
193 } else {
194 quote_spanned! { named.span() =>
195 #[automatically_derived]
196 impl #impl_generics #parse for #ident #type_generics #where_generics {
197 fn parse(#parser_ident: &mut #parser<'_>) -> #result<Self, #compile_error> {
198 Ok(Self {
199 #(#fields,)*
200 })
201 }
202 }
203 }
204 };
205
206 Ok(output)
207 }
208}