diff options
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),*) |