rune_macros/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
//! # rune-macros
//!
//! `rune-macros` is the crate that generates two proc macros for use in other parts of the `rune` architecture:
//!
//! * [`macro@defun`]: Functions hydrated to emacs lisp.
//! * [Trace](`macro@Trace`): TODO
use darling::{ast::NestedMeta, Error, FromMeta};
use proc_macro::TokenStream;
use syn::parse_macro_input;
mod defun;
mod trace;
/// ## `#[defun]`
///
/// Represents the functions that are going to be hydrated to emacs lisp, through the `rune` VM execution. As of
/// today, they are not documented with the GNU Emacs documentation, though definitely is a point of improvement.
/// Following Rust convention, `defun` names are written in `snake_case`, though if you search them in GNU Emacs,
/// you'll find them in `kebab-case`.
///
/// Arguments of the `defun`s follow the arguments on its corresponding documentation, or rather, definition on
/// the C Emacs core.
///
/// ### Examples
///
/// For the `make-vector` function, here's its signature:
///
/// > make-vector is a function defined in `alloc.c`. Signature `(make-vector LENGTH INIT)`
///
/// Its corresponding `rune` `#[defun]` signature would be:
///
/// ```ignore
/// #[defun]
/// fn make_vector(length: usize, init: GcObj) -> Vec<GcObj> {}
/// ```
///
/// The return object is interesting, as it's not so easily inferrable from the signature, but rather from documentation.
/// In this case, the `make-vector` defun returns a *newly created vector*.
#[proc_macro_attribute]
pub fn defun(attr_ts: TokenStream, fn_ts: TokenStream) -> TokenStream {
let function = parse_macro_input!(fn_ts as defun::Function);
match NestedMeta::parse_meta_list(attr_ts.into()) {
Ok(args) => match defun::Spec::from_list(&args) {
Ok(spec) => defun::expand(function, spec).into(),
Err(e) => TokenStream::from(e.write_errors()),
},
Err(e) => TokenStream::from(Error::from(e).write_errors()),
}
}
/// ## `Trace`
///
/// TODO: Document `Trace` macro.
#[proc_macro_derive(Trace, attributes(no_trace))]
pub fn trace_derive(stream: TokenStream) -> TokenStream {
let derived = parse_macro_input!(stream as syn::DeriveInput);
trace::expand(&derived).into()
}