Skip to content

Commit 1b4c184

Browse files
stepanchegfacebook-github-bot
authored andcommitted
More quote! -> parse_quote!
Summary: Because if there's some missing comma, hunting for it is hard. This should be even more helpful with D63712744. Reviewed By: JakobDegen Differential Revision: D63712892 fbshipit-source-id: 31b8e297099445079a8fe3d0a1e75e7448b299d5
1 parent 11794d3 commit 1b4c184

File tree

2 files changed

+116
-92
lines changed

2 files changed

+116
-92
lines changed

starlark_derive/src/module/render.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use quote::quote;
2525
use quote::ToTokens;
2626

2727
use crate::module::render::fun::render_fun;
28+
use crate::module::render::fun::render_none;
29+
use crate::module::render::fun::render_some;
2830
use crate::module::typ::SpecialParam;
2931
use crate::module::typ::StarAttr;
3032
use crate::module::typ::StarConst;
@@ -97,9 +99,9 @@ fn render_attr(x: StarAttr) -> syn::Stmt {
9799
} = x;
98100
let name_str = ident_string(&name);
99101
let name_inner = syn::Ident::new(&format!("{}__inner", name_str), name.span());
100-
let docstring = match docstring {
101-
Some(d) => quote!(Some(#d.to_owned())),
102-
None => quote!(None),
102+
let docstring: syn::Expr = match docstring {
103+
Some(d) => render_some(syn::parse_quote! { #d.to_owned() }),
104+
None => render_none(),
103105
};
104106

105107
let let_heap = if let Some(SpecialParam { ident, ty }) = heap {
@@ -112,29 +114,36 @@ fn render_attr(x: StarAttr) -> syn::Stmt {
112114

113115
let unpack = this.render_prepare(&this.ident, &this_value);
114116

117+
let inner: syn::ItemFn = syn::parse_quote! {
118+
#( #attrs )*
119+
#[allow(non_snake_case)] // Starlark doesn't have this convention
120+
fn #name_inner<'v>(
121+
#this_value: starlark::values::Value<'v>,
122+
#[allow(unused_variables)]
123+
__heap: &'v starlark::values::Heap,
124+
) -> #return_type {
125+
#[allow(unused_variables)]
126+
#unpack
127+
#let_heap
128+
#body
129+
}
130+
};
131+
132+
let outer: syn::ItemFn = syn::parse_quote! {
133+
#[allow(non_snake_case)]
134+
fn #name<'v>(
135+
#[allow(unused_variables)]
136+
this: starlark::values::Value<'v>,
137+
heap: &'v starlark::values::Heap,
138+
) -> starlark::Result<starlark::values::Value<'v>> {
139+
Ok(heap.alloc(#name_inner(this, heap)?))
140+
}
141+
};
142+
115143
syn::parse_quote! {
116144
{
117-
#( #attrs )*
118-
#[allow(non_snake_case)] // Starlark doesn't have this convention
119-
fn #name_inner<'v>(
120-
#this_value: starlark::values::Value<'v>,
121-
#[allow(unused_variables)]
122-
__heap: &'v starlark::values::Heap,
123-
) -> #return_type {
124-
#[allow(unused_variables)]
125-
#unpack
126-
#let_heap
127-
#body
128-
}
129-
130-
#[allow(non_snake_case)]
131-
fn #name<'v>(
132-
#[allow(unused_variables)]
133-
this: starlark::values::Value<'v>,
134-
heap: &'v starlark::values::Heap,
135-
) -> starlark::Result<starlark::values::Value<'v>> {
136-
Ok(heap.alloc(#name_inner(this, heap)?))
137-
}
145+
#inner
146+
#outer
138147

139148
globals_builder.set_attribute_fn(
140149
#name_str,

starlark_derive/src/module/render/fun.rs

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ impl StarFun {
7979
}
8080

8181
/// Evaluator function parameter and call argument.
82-
fn eval_param_arg(&self) -> (Option<syn::PatType>, Option<TokenStream>) {
82+
fn eval_param_arg(&self) -> (Option<syn::PatType>, Option<syn::Expr>) {
8383
if let Some(SpecialParam { ident, ty }) = &self.eval {
8484
(
8585
Some(syn::parse_quote! {
8686
#ident: #ty
8787
}),
88-
Some(quote! {
89-
eval,
88+
Some(syn::parse_quote! {
89+
eval
9090
}),
9191
)
9292
} else {
@@ -95,14 +95,14 @@ impl StarFun {
9595
}
9696

9797
/// Heap function parameter and call argument.
98-
fn heap_param_arg(&self) -> (Option<syn::PatType>, Option<TokenStream>) {
98+
fn heap_param_arg(&self) -> (Option<syn::PatType>, Option<syn::Expr>) {
9999
if let Some(SpecialParam { ident, ty }) = &self.heap {
100100
(
101101
Some(syn::parse_quote! {
102102
#ident: #ty
103103
}),
104-
Some(quote! {
105-
eval.heap(),
104+
Some(syn::parse_quote! {
105+
eval.heap()
106106
}),
107107
)
108108
} else {
@@ -119,7 +119,7 @@ impl StarFun {
119119
// Inner function parameter.
120120
Option<syn::PatType>,
121121
Option<syn::Stmt>,
122-
Option<TokenStream>,
122+
Option<syn::Expr>,
123123
) {
124124
match &self.this {
125125
Some(this) => {
@@ -129,7 +129,7 @@ impl StarFun {
129129
Some(syn::parse_quote! { #outer_param_name: starlark::values::Value<'v> }),
130130
Some(this.reconstruct_param()),
131131
Some(this.render_prepare(&local_var, &outer_param_name)),
132-
Some(quote! { #local_var, }),
132+
Some(syn::parse_quote! { #local_var }),
133133
)
134134
}
135135
None => (None, None, None, None),
@@ -161,28 +161,28 @@ impl StarFun {
161161
}
162162

163163
/// Fields and field initializers for the struct implementing the trait.
164-
fn struct_fields(&self) -> syn::Result<(TokenStream, TokenStream)> {
164+
fn struct_fields(&self) -> syn::Result<(Vec<syn::Field>, Vec<syn::FieldValue>)> {
165165
let signature = if let StarFunSource::Signature { .. } = self.source {
166166
Some(render_signature(self)?)
167167
} else {
168168
None
169169
};
170170
if let Some(signature) = signature {
171171
Ok((
172-
quote! {
173-
signature: starlark::eval::ParametersSpec<starlark::values::FrozenValue>,
174-
},
175-
quote! {
176-
signature: #signature,
177-
},
172+
vec![syn::parse_quote! {
173+
signature: starlark::eval::ParametersSpec<starlark::values::FrozenValue>
174+
}],
175+
vec![syn::parse_quote! {
176+
signature: #signature
177+
}],
178178
))
179179
} else {
180-
Ok((TokenStream::new(), TokenStream::new()))
180+
Ok((Vec::new(), Vec::new()))
181181
}
182182
}
183183

184184
/// Globals builder call to register the function.
185-
fn builder_set(&self, struct_fields_init: TokenStream) -> syn::Result<syn::Stmt> {
185+
fn builder_set(&self, struct_fields_init: Vec<syn::FieldValue>) -> syn::Result<syn::Stmt> {
186186
let name_str = self.name_str();
187187
let components = render_native_callable_components(self)?;
188188

@@ -208,7 +208,7 @@ impl StarFun {
208208
#name_str,
209209
#components,
210210
#struct_name {
211-
#struct_fields_init
211+
#( #struct_fields_init, )*
212212
},
213213
);
214214
})
@@ -224,7 +224,7 @@ impl StarFun {
224224
#ty_custom,
225225
#special_builtin_function,
226226
#struct_name {
227-
#struct_fields_init
227+
#( #struct_fields_init, )*
228228
},
229229
);
230230
})
@@ -259,64 +259,79 @@ pub(crate) fn render_fun(x: StarFun) -> syn::Result<syn::Stmt> {
259259
.chain(heap_param)
260260
.collect();
261261

262+
let invoke_args = iter::empty()
263+
.chain(this_arg)
264+
.chain(binding_args)
265+
.chain(eval_arg)
266+
.chain(heap_arg);
267+
262268
let param_types: Vec<_> = invoke_params.iter().map(|p| &p.ty).collect();
263269

264270
let this_outer_param = this_outer_param.into_iter();
265271

266-
Ok(syn::parse_quote! {
267-
{
268-
struct #struct_name {
269-
#struct_fields
270-
}
272+
let struct_def: syn::ItemStruct = syn::parse_quote! {
273+
struct #struct_name {
274+
#( #struct_fields, )*
275+
}
276+
};
271277

272-
impl #struct_name {
273-
// TODO(nga): copy lifetime parameter from declaration,
274-
// so the warning would be precise.
275-
#[allow(clippy::extra_unused_lifetimes)]
276-
#( #attrs )*
277-
fn invoke_impl<'v>(
278-
#( #invoke_params, )*
279-
) -> #return_type {
280-
#body
281-
}
278+
let impl_struct: syn::ItemImpl = syn::parse_quote! {
279+
impl #struct_name {
280+
// TODO(nga): copy lifetime parameter from declaration,
281+
// so the warning would be precise.
282+
#[allow(clippy::extra_unused_lifetimes)]
283+
#( #attrs )*
284+
fn invoke_impl<'v>(
285+
#( #invoke_params, )*
286+
) -> #return_type {
287+
#body
288+
}
282289

283-
// When function signature declares return type as `anyhow::Result<impl AllocValue>`,
284-
// we cannot call `T::starlark_type_repr` to render documentation, because there's no T.
285-
// Future Rust will provide syntax `type ReturnType = impl AllocValue`:
286-
// https://github.com/rust-lang/rfcs/pull/2515
287-
// Until then we use this hack as a workaround.
288-
#[allow(dead_code)] // Function is not used when return type is specified explicitly.
289-
fn return_type_starlark_type_repr() -> starlark::typing::Ty {
290-
fn get_impl<'v, T: starlark::values::AllocValue<'v>, E>(
291-
_f: fn(
292-
#( #param_types, )*
293-
) -> std::result::Result<T, E>,
294-
) -> starlark::typing::Ty {
295-
<T as starlark::values::type_repr::StarlarkTypeRepr>::starlark_type_repr()
296-
}
297-
get_impl(Self::invoke_impl)
290+
// When function signature declares return type as `anyhow::Result<impl AllocValue>`,
291+
// we cannot call `T::starlark_type_repr` to render documentation, because there's no T.
292+
// Future Rust will provide syntax `type ReturnType = impl AllocValue`:
293+
// https://github.com/rust-lang/rfcs/pull/2515
294+
// Until then we use this hack as a workaround.
295+
#[allow(dead_code)] // Function is not used when return type is specified explicitly.
296+
fn return_type_starlark_type_repr() -> starlark::typing::Ty {
297+
fn get_impl<'v, T: starlark::values::AllocValue<'v>, E>(
298+
_f: fn(
299+
#( #param_types, )*
300+
) -> std::result::Result<T, E>,
301+
) -> starlark::typing::Ty {
302+
<T as starlark::values::type_repr::StarlarkTypeRepr>::starlark_type_repr()
298303
}
304+
get_impl(Self::invoke_impl)
299305
}
306+
}
307+
};
300308

301-
impl #trait_name for #struct_name {
302-
#[allow(non_snake_case)] // Starlark doesn't have this convention
303-
fn invoke<'v>(
304-
&self,
305-
eval: &mut starlark::eval::Evaluator<'v, '_, '_>,
306-
#(#this_outer_param,)*
307-
parameters: &starlark::eval::Arguments<'v, '_>,
308-
) -> starlark::Result<starlark::values::Value<'v>> {
309-
#this_prepare
310-
#prepare
311-
match Self::invoke_impl(#this_arg #( #binding_args, )* #eval_arg #heap_arg) {
312-
Ok(v) => Ok(eval.heap().alloc(v)),
313-
// The `.into()` is an `anyhow -> anyhow` conversion if the return type is `anyhow`
314-
#[allow(clippy::useless_conversion)]
315-
Err(e) => Err(e.into()),
316-
}
309+
let impl_trait: syn::ItemImpl = syn::parse_quote! {
310+
impl #trait_name for #struct_name {
311+
#[allow(non_snake_case)] // Starlark doesn't have this convention
312+
fn invoke<'v>(
313+
&self,
314+
eval: &mut starlark::eval::Evaluator<'v, '_, '_>,
315+
#(#this_outer_param,)*
316+
parameters: &starlark::eval::Arguments<'v, '_>,
317+
) -> starlark::Result<starlark::values::Value<'v>> {
318+
#this_prepare
319+
#prepare
320+
match Self::invoke_impl(#( #invoke_args, )*) {
321+
Ok(v) => Ok(eval.heap().alloc(v)),
322+
// The `.into()` is an `anyhow -> anyhow` conversion if the return type is `anyhow`
323+
#[allow(clippy::useless_conversion)]
324+
Err(e) => Err(e.into()),
317325
}
318326
}
327+
}
328+
};
319329

330+
Ok(syn::parse_quote! {
331+
{
332+
#struct_def
333+
#impl_struct
334+
#impl_trait
320335
#builder_set
321336
}
322337
})
@@ -520,15 +535,15 @@ fn render_signature(x: &StarFun) -> syn::Result<syn::Expr> {
520535
}
521536
}
522537

523-
fn render_none() -> syn::Expr {
538+
pub(crate) fn render_none() -> syn::Expr {
524539
syn::parse_quote! { std::option::Option::None }
525540
}
526541

527-
fn render_some(expr: syn::Expr) -> syn::Expr {
542+
pub(crate) fn render_some(expr: syn::Expr) -> syn::Expr {
528543
syn::parse_quote! { std::option::Option::Some(#expr) }
529544
}
530545

531-
fn render_option(expr: Option<syn::Expr>) -> syn::Expr {
546+
pub(crate) fn render_option(expr: Option<syn::Expr>) -> syn::Expr {
532547
match expr {
533548
Some(x) => render_some(x),
534549
None => render_none(),

0 commit comments

Comments
 (0)