emacs_macros/
lib.rs

1//! This crate implements proc macros for the `emacs` crate. It is a dependency of `emacs` crate,
2//! and should not be listed as a direct dependency by Emacs dynamic modules.
3
4#![recursion_limit = "128"]
5
6extern crate proc_macro;
7extern crate proc_macro2;
8
9use proc_macro::TokenStream;
10
11use syn::{self, AttributeArgs, ItemFn, LitInt, parse_macro_input};
12use quote::quote;
13
14mod util;
15mod module;
16mod func;
17mod lisp_args;
18
19/// Registers a function as the initializer, to be called when Emacs loads the module. Each dynamic
20/// module must have one and only one such function.
21///
22/// # Options
23///
24/// - `name`: By default, the name of the feature provided by the module is the crate's name (with
25/// `_` replaced by `-`). There is no need to explicitly call `provide` inside the initializer. This
26/// option allows the initializer's name, or a string, to be used instead. Examples:
27/// `#[module(name(fn))]`, `#[module(name = "feature-name")]`.
28///
29/// - `defun_prefix` and `separator`: Function names in Emacs are conventionally prefixed with the
30/// feature name followed by `-`. These 2 options allow different prefix and separator to be used.
31/// Example: `#[module(name = "foo-dyn", defun_prefix = "foo", separator = "/")]`.
32///
33/// - `mod_in_name`: Whether to use Rust's `mod` path to construct function names. Default to
34/// `true`. For example, supposed that the crate is named `parser`, a #[[`defun`]] named `next_child`
35/// inside `mod cursor` will have the Lisp name of `parser-cursor-next-child`. This can also be
36/// overridden for each individual function, by an option of the same name on #[[`defun`]].
37///
38/// [`defun`]: attr.defun.html
39#[proc_macro_attribute]
40pub fn module(attr_ts: TokenStream, item_ts: TokenStream) -> TokenStream {
41    let attr_args: AttributeArgs = parse_macro_input!(attr_ts);
42    let fn_item: ItemFn = parse_macro_input!(item_ts);
43    match module::Module::parse(attr_args, fn_item) {
44        Ok(module) => module.render().into(),
45        Err(e) => e.into(),
46    }
47}
48
49/// Exports a function to the Lisp runtime. The function is bound when the module is loaded, even if
50/// it is defined inside another function which is never called.
51///
52/// # Input Parameters
53///
54/// Each parameter must be one of the following:
55///
56/// - An owned value of a type that implements [`FromLisp`]. This is for simple data types that have
57/// an equivalent in Lisp. Examples: `i64`, `String`, `bool`.
58///
59/// - A shared/mutable reference. This gives access to data structures that other module functions
60/// have created and embedded in the Lisp runtime (through `user-ptr` objects).
61///
62/// - A Lisp [`Value`], or one of its "sub-types" (e.g. [`Vector`]). This allows holding off the
63/// conversion to Rust data structures until necessary, or working with values that don't have a
64/// meaningful representation in Rust, like Lisp lambdas.
65///
66/// - An [`&Env`]. This enables interaction with the Lisp runtime. It does not appear in the
67/// function's Lisp signature. This is unnecessary if there is already another parameter with type
68/// [`Value`], which allows accessing the runtime through `Value.env`.
69///
70/// # Return Value
71///
72/// The return type must be [`Result<T>`], where `T` is one of the following:
73///
74/// - A type that implements [`IntoLisp`]. This is for simple data types that have an equivalent in
75/// Lisp. Example: `i64`, `String`, `bool`.
76///
77/// - A type that implements `Transfer`. This allows embedding a native data structure in a
78/// `user-ptr` object, for read-only use cases. It requires `user_ptr(direct)` option to be
79/// specified.
80///
81/// - An arbitrary type. This allows embedding a native data structure in a `user-ptr` object, for
82/// read-write use cases. It requires `user_ptr` option to be specified. If the data is to be shared
83/// with background Rust threads, `user_ptr(rwlock)` or `user_ptr(mutex)` must be used instead.
84///
85/// - [`Value`], or one of its "sub-types" (e.g. [`Vector`]). This is mostly useful for returning an
86/// input parameter unchanged.
87///
88/// # Naming
89///
90/// By default, the function's Lisp name has the form `<crate-prefix>[mod-prefix]<base-name>`.
91///
92/// - `crate-prefix` is the feature name followed by `-`. This can be customized by the `name`,
93/// `defun_prefix`, and `separator` options on #[[`module`]].
94///
95/// - `mod-prefix` is constructed from the function's Rust `mod` path (with `_` and `::` replaced
96/// by `-`). This can be turned off crate-wide, or for individual function, using the option
97/// `mod_in_name`.
98///
99/// - `base-name` is the function's Rust name (with `_` replaced by `-`). This can be overridden
100/// with the option `name`, e.g. `#[defun(name = "foo:bar")]`.
101///
102/// [`module`]: attr.module.html
103/// [`Result<T>`]: /emacs/*/emacs/type.Result.html
104/// [`FromLisp`]: /emacs/*/emacs/trait.FromLisp.html
105/// [`IntoLisp`]: /emacs/*/emacs/trait.IntoLisp.html
106/// [`Transfer`]: /emacs/*/emacs/trait.Transfer.html
107/// [`&Env`]: /emacs/*/emacs/struct.Env.html
108/// [`Value`]: /emacs/*/emacs/struct.Value.html
109/// [`Vector`]: /emacs/*/emacs/struct.Vector.html
110#[proc_macro_attribute]
111pub fn defun(attr_ts: TokenStream, item_ts: TokenStream) -> TokenStream {
112    let attr_args: AttributeArgs = parse_macro_input!(attr_ts);
113    let fn_item: ItemFn = parse_macro_input!(item_ts);
114    match func::LispFunc::parse(attr_args, fn_item) {
115        Ok(func) => func.render().into(),
116        Err(e) => e.into(),
117    }
118}
119
120#[doc(hidden)]
121#[proc_macro]
122pub fn impl_lisp_args_for_tuples(arity: TokenStream) -> TokenStream {
123    let arity: LitInt = parse_macro_input!(arity);
124    lisp_args::impl_for_tuples(arity.base10_parse::<usize>().unwrap()).into()
125}
126
127#[doc(hidden)]
128#[proc_macro]
129pub fn impl_lisp_args_for_arrays(length: TokenStream) -> TokenStream {
130    let length: LitInt = parse_macro_input!(length);
131    lisp_args::impl_for_arrays(length.base10_parse::<usize>().unwrap()).into()
132}
133
134/// Converts an identifier into a Lisp name, as a string literal.
135///
136/// This replaces underscores with hyphens.
137#[doc(hidden)]
138#[proc_macro]
139pub fn lisp_name(ident: TokenStream) -> TokenStream {
140    let name = util::lisp_name(&parse_macro_input!(ident));
141    quote!(#name).into()
142}