starlark_derive/lib.rs
1/*
2 * Copyright 2019 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! A proc-macro for writing functions in Rust that can be called from Starlark.
19
20#[allow(unused_extern_crates)] // proc_macro is very special
21extern crate proc_macro;
22
23use proc_macro::TokenStream;
24
25mod alloc_value;
26mod any_lifetime;
27mod attrs;
28mod bc;
29mod coerce;
30mod freeze;
31mod module;
32mod serde;
33mod starlark_type_repr;
34mod starlark_value;
35mod trace;
36mod unpack_value;
37mod util;
38mod v_lifetime;
39mod visit_span;
40mod vtable;
41
42/// Write Starlark modules concisely in Rust syntax.
43///
44/// For example:
45///
46/// ```ignore
47/// #[starlark_module]
48/// fn global(builder: &mut GlobalsBuilder) {
49/// fn cc_binary(name: &str, srcs: Vec<&str>) -> String {
50/// Ok(format!("{:?} {:?}", name, srcs))
51/// }
52/// }
53/// ```
54///
55/// Parameters operate as named parameters of a given type. Each parameter will be unpacked with `UnpackValue`, unless:
56///
57/// * It is type `Option`, in which case it will be considered optional.
58/// * It is a single argument of type `Arguments`, in which case all arguments will be passed together with minimal interpretation.
59///
60/// There are a number of attributes that can be add to each parameter by writing attributes before the
61/// parameter name:
62///
63/// * `#[starlark(default = "a default")]` - provide a deafult for the parameter if it is omitted.
64/// * `#[starlark(require = pos)]` - require the parameter to be passed by position, not named.
65/// * `#[starlark(require = named)]` - require the parameter to be passed by name, not by position.
66/// * `#[starlark(args)]` - treat the argument as `*args` in Starlark, receiving all additional positional arguments as a tuple.
67/// * `#[starlark(kwargs)]` - treat the argument as `**kwargs` in Starlark, receiving all additional named arguments as a dictionary.
68///
69/// There are a number of attributes that can be applied to the entire function by writing attributes
70/// before the `fn` of the function:
71///
72/// * `#[starlark(attribute_type = "foo")]` - if the function has `.type` applied, return this string. Usually used on
73/// constructor functions so that `ctor.type` can be used in Starlark code.
74/// * `#[starlark(return_type = "foo")]` - the return type of the function used for documention.
75/// * `#[starlark(speculative_exec_safe)]` - the function
76/// is considered safe to execute speculatively: the function should have
77/// no global side effects, should not panic, and should finish in reasonable time.
78/// The evaluator may invoke such functions early to generate more efficient code.
79/// * `#[starlark(attribute)]` to turn the name into
80/// an attribute on the value. Such a function must take exactly one argument, namely a value
81/// of the type you have attached it to.
82///
83/// Multiple attributes can be specified either separately `#[starlark(require = named)] #[starlark(default = "")]` or
84/// separated with a comman `#[starlark(require = named, default = "")]`.
85///
86/// There are two special arguments, distinguished by their type, which provides access to interpreter state:
87///
88/// * `heap: &'v Heap` gives access to the Starlark heap, for allocating things.
89/// * `eval: &mut Evaluator<'v, '_, '_>` gives access to the Starlark evaluator, which can be used to look at interpreter state.
90///
91/// A module can be used to define globals (with `GlobalsBuilder`) or methods on an object (with `MethodsBuilder`).
92/// In the case of methods, the first argument to each function will be the object itself, typically named `this`.
93///
94/// All these functions interoperate properly with `dir()`, `getattr()` and `hasattr()`.
95///
96/// If a desired function name is also a Rust keyword, use the `r#` prefix, e.g. `r#type`.
97///
98/// As a more complex example:
99///
100/// ```ignore
101/// #[starlark_module]
102/// fn methods(builder: &mut MethodsBuilder) {
103/// fn r#enum<'v>(
104/// this: Value<'v>,
105/// #[starlark(require = named, default = 3)] index: i32,
106/// heap: &'v Heap,
107/// ) -> anyhow::Result<StringValue<'v>> {
108/// Ok(heap.alloc_str(&format!("{this} {index}")))
109/// }
110/// }
111/// ```
112///
113/// This defines a method such that when attached to an object `object.enum(index = 12)` will
114/// return the string of the object and the index.
115#[proc_macro_attribute]
116pub fn starlark_module(attr: TokenStream, input: TokenStream) -> TokenStream {
117 module::starlark_module(attr, input)
118}
119
120/// Stubs for Starlark bytecode interpreter.
121#[proc_macro_attribute]
122pub fn starlark_internal_bc(
123 attr: proc_macro::TokenStream,
124 input: proc_macro::TokenStream,
125) -> proc_macro::TokenStream {
126 bc::starlark_internal_bc(attr, input)
127}
128
129#[proc_macro_attribute]
130pub fn starlark_internal_vtable(
131 attr: proc_macro::TokenStream,
132 input: proc_macro::TokenStream,
133) -> proc_macro::TokenStream {
134 vtable::starlark_internal_vtable(attr, input)
135}
136
137#[proc_macro_derive(VisitSpanMut)]
138pub fn derive_visit_span_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
139 visit_span::derive_visit_span_mut(input)
140}
141
142/// Derive the `Trace` trait.
143#[proc_macro_derive(Trace, attributes(trace))]
144pub fn derive_trace(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
145 trace::derive_trace(input)
146}
147
148/// Derive the `Freeze` trait.
149#[proc_macro_derive(Freeze, attributes(freeze))]
150pub fn derive_freeze(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
151 freeze::derive_freeze(input)
152}
153
154/// Derive the `NoSerialize` trait for serde.
155#[proc_macro_derive(NoSerialize)]
156pub fn derive_no_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
157 serde::derive_no_serialize(input)
158}
159
160/// Derive the `StarlarkTypeRepr` trait.
161#[proc_macro_derive(StarlarkTypeRepr)]
162pub fn derive_starlark_type_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
163 starlark_type_repr::derive_starlark_type_repr(input)
164}
165
166/// Derive the `UnpackValue` trait.
167#[proc_macro_derive(UnpackValue)]
168pub fn derive_unpack_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
169 unpack_value::derive_unpack_value(input)
170}
171
172/// Derive the `AllocValue` trait.
173#[proc_macro_derive(AllocValue)]
174pub fn derive_alloc_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
175 alloc_value::derive_alloc_value(input)
176}
177
178/// Derive the `AllocFrozenValue` trait.
179#[proc_macro_derive(AllocFrozenValue)]
180pub fn derive_alloc_frozen_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
181 alloc_value::derive_alloc_frozen_value(input)
182}
183
184/// Derive accessor methods that are designed to be used from {has,get,dir}_attr
185/// in an `impl StarlarkValue` block. All fields in the struct that are not
186/// marked with #[starlark(skip)] are exported to Starlark code as attributes.
187/// NOTE: Any usage must also call `starlark_attrs!()` in the impl block for
188/// `StarlarkValue`, otherwise the generated attr methods will not be used.
189#[proc_macro_derive(StarlarkAttrs, attributes(starlark))]
190pub fn derive_starlark_attrs(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
191 attrs::derive_attrs(input)
192}
193
194/// Generate `{has,get,dir}_attr` in the `StarlarkValue` impl block that proxy
195/// to the ones generated by `derive(StarlarkAttrs)`
196#[proc_macro]
197pub fn starlark_attrs(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
198 attrs::starlark_attrs()
199}
200
201/// Generate missing elements of `StarlarkValue` trait when this attribute
202/// is applied to an impl block of `StarlarkValue`.
203#[proc_macro_attribute]
204pub fn starlark_value(
205 attr: proc_macro::TokenStream,
206 input: proc_macro::TokenStream,
207) -> proc_macro::TokenStream {
208 starlark_value::derive_starlark_value(attr, input)
209}
210
211/// Derive the `ProvidesStaticType` trait. Requires the type has no type arguments, no constant arguments,
212/// and at most one lifetime argument.
213#[proc_macro_derive(ProvidesStaticType)]
214pub fn derive_provides_static_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
215 any_lifetime::derive_provides_static_type(input)
216}
217
218// Derive the `Coerce` trait.
219#[proc_macro_derive(Coerce)]
220pub fn derive_coerce(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
221 coerce::derive_coerce(input)
222}