diff options
author | Griffin Smith <root@gws.fyi> | 2022-11-06T15·46-0500 |
---|---|---|
committer | grfn <grfn@gws.fyi> | 2022-11-08T13·42+0000 |
commit | 76d7671c8a7fa624947e3523d635f0608aae2d07 (patch) | |
tree | dd4eac7f0075a540198765d2e279d673f40e93d9 /tvix/eval/builtin-macros/src | |
parent | a1015ba1d7c2228224847f1931118da473815de3 (diff) |
feat(tvix/eval): Add docstrings as documentation for builtins r/5269
Add a new `documentation: Option<&'static str>` field to Builtin, and populate it in the `#[builtins]` macro with the docstring of the builtin function, if any. Change-Id: Ic68fdf9b314d15a780731974234e2ae43f6a44b0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7205 Tested-by: BuildkiteCI Reviewed-by: tazjin <tazjin@tvl.su>
Diffstat (limited to 'tvix/eval/builtin-macros/src')
-rw-r--r-- | tvix/eval/builtin-macros/src/lib.rs | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/tvix/eval/builtin-macros/src/lib.rs b/tvix/eval/builtin-macros/src/lib.rs index 8276e421c5d8..e815749ec62c 100644 --- a/tvix/eval/builtin-macros/src/lib.rs +++ b/tvix/eval/builtin-macros/src/lib.rs @@ -2,11 +2,12 @@ extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::Span; -use quote::{quote_spanned, ToTokens}; +use quote::{quote, quote_spanned, ToTokens}; use syn::parse::Parse; use syn::spanned::Spanned; use syn::{ - parse_macro_input, parse_quote, FnArg, Ident, Item, ItemMod, LitStr, Pat, PatIdent, PatType, + parse2, parse_macro_input, parse_quote, Attribute, FnArg, Ident, Item, ItemMod, LitStr, Pat, + PatIdent, PatType, Token, }; struct BuiltinArgs { @@ -21,6 +22,35 @@ impl Parse for BuiltinArgs { } } +fn extract_docstring(attrs: &[Attribute]) -> Option<LitStr> { + // Rust docstrings are transparently written pre-macro expansion into an attribute that looks + // like: + // + // #[doc = "docstring here"] + + #[allow(dead_code)] + #[derive(Debug)] + struct Docstring { + eq: Token![=], + doc: LitStr, + } + + impl Parse for Docstring { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + Ok(Self { + eq: input.parse()?, + doc: input.parse()?, + }) + } + } + + attrs + .iter() + .filter(|attr| attr.path.get_ident().into_iter().any(|id| id == "doc")) + .find_map(|attr| parse2::<Docstring>(attr.tokens.clone()).ok()) + .map(|docstring| docstring.doc) +} + /// Mark the annotated module as a module for defining Nix builtins. /// /// A function `fn builtins() -> Vec<Builtin>` will be defined within the annotated module, @@ -144,10 +174,16 @@ pub fn builtins(_args: TokenStream, item: TokenStream) -> TokenStream { let mut reversed_args = args.clone(); reversed_args.reverse(); + let docstring = match extract_docstring(&f.attrs) { + Some(docs) => quote!(Some(#docs)), + None => quote!(None), + }; + builtins.push(quote_spanned! { builtin_attr.span() => { crate::internal::Builtin::new( #name, &[#(#builtin_arguments),*], + #docstring, |mut args: Vec<crate::Value>, vm: &mut crate::internal::VM| { #(let #reversed_args = args.pop().unwrap();)* #fn_name(vm, #(#args),*) |