rune/macros/
mod.rs

1//! The macro system of Rune.
2//!
3//! Macros are registered with [Module::macro_][crate::Module::macro_] and are
4//! function-like items that are expanded at compile time.
5//!
6//! Macros take token streams as arguments and are responsible for translating
7//! them into another token stream that will be embedded into the source location
8//! where the macro was invoked.
9//!
10//! The attribute macros [`rune::macro_`](crate::macro_) for function macros (`some_macro!( ... )`) and
11//! [`rune::attribute_macro`](crate::attribute_macro) for attribute macros (`#[some_macro ...]`).
12//!
13//! ```
14//! use rune::{T, Context, Diagnostics, Module, Vm};
15//! use rune::ast;
16//! use rune::compile;
17//! use rune::macros::{quote, MacroContext, TokenStream, ToTokens};
18//! use rune::parse::Parser;
19//! use rune::termcolor::{ColorChoice, StandardStream};
20//! use rune::alloc::String;
21//!
22//! use std::sync::Arc;
23//!
24//! #[rune::macro_]
25//! fn concat_idents(cx: &mut MacroContext<'_, '_, '_>, input: &TokenStream) -> compile::Result<TokenStream> {
26//!     let mut output = String::new();
27//!
28//!     let mut p = Parser::from_token_stream(input, cx.input_span());
29//!
30//!     let ident = p.parse::<ast::Ident>()?;
31//!     output.try_push_str(cx.resolve(ident)?)?;
32//!
33//!     while p.parse::<Option<T![,]>>()?.is_some() {
34//!         if p.is_eof()? {
35//!             break;
36//!         }
37//!
38//!         let ident = p.parse::<ast::Ident>()?;
39//!         output.try_push_str(cx.resolve(ident)?)?;
40//!     }
41//!
42//!     p.eof()?;
43//!
44//!     let output = cx.ident(&output)?;
45//!     Ok(quote!(#output).into_token_stream(cx)?)
46//! }
47//!
48//! #[rune::attribute_macro]
49//! fn rename(cx: &mut MacroContext<'_, '_, '_>, input: &TokenStream, item: &TokenStream) -> compile::Result<TokenStream> {
50//!     let mut parser = Parser::from_token_stream(item, cx.macro_span());
51//!     let mut fun: ast::ItemFn = parser.parse_all()?;
52//!
53//!     let mut parser = Parser::from_token_stream(input, cx.input_span());
54//!     fun.name = parser.parse_all::<ast::EqValue<_>>()?.value;
55//!
56//!     let mut tokens = TokenStream::new();
57//!     fun.to_tokens(cx, &mut tokens);
58//!     Ok(tokens)
59//! }
60//!
61//! let mut m = Module::new();
62//! m.macro_meta(concat_idents)?;
63//! m.macro_meta(rename)?;
64//!
65//! let mut context = Context::new();
66//! context.install(m)?;
67//!
68//! let runtime = Arc::new(context.runtime()?);
69//!
70//! let mut sources = rune::sources! {
71//!     entry => {
72//!         #[rename = foobar]
73//!         fn renamed() {
74//!             42
75//!         }
76//!
77//!         pub fn main() {
78//!             let foobar = foobar();
79//!             concat_idents!(foo, bar)
80//!         }
81//!     }
82//! };
83//!
84//! let mut diagnostics = Diagnostics::new();
85//!
86//! let result = rune::prepare(&mut sources)
87//!     .with_context(&context)
88//!     .with_diagnostics(&mut diagnostics)
89//!     .build();
90//!
91//! if !diagnostics.is_empty() {
92//!     let mut writer = StandardStream::stderr(ColorChoice::Always);
93//!     diagnostics.emit(&mut writer, &sources)?;
94//! }
95//!
96//! let unit = result?;
97//! let unit = Arc::new(unit);
98//!
99//! let mut vm = Vm::new(runtime, unit);
100//! let value = vm.call(["main"], ())?;
101//! let value: u32 = rune::from_value(value)?;
102//!
103//! assert_eq!(value, 42);
104//! # Ok::<_, rune::support::Error>(())
105//! ```
106
107mod format_args;
108mod into_lit;
109mod macro_compiler;
110mod macro_context;
111mod quote_fn;
112mod storage;
113mod token_stream;
114
115pub use self::format_args::FormatArgs;
116pub use self::into_lit::IntoLit;
117pub(crate) use self::macro_compiler::MacroCompiler;
118#[cfg(feature = "std")]
119pub use self::macro_context::test;
120pub use self::macro_context::MacroContext;
121pub use self::quote_fn::{quote_fn, Quote};
122pub(crate) use self::storage::Storage;
123pub use self::storage::{SyntheticId, SyntheticKind};
124pub use self::token_stream::{ToTokens, TokenStream, TokenStreamIter};
125
126/// Macro helper function for quoting the token stream as macro output.
127///
128/// Is capable of quoting everything in Rune, except for the following:
129/// * Labels, which must be created using `Label::new`.
130/// * Dynamic quoted strings and other literals, which must be created using
131///   `Lit::new`.
132///
133/// ```
134/// use rune::macros::quote;
135///
136/// quote!(hello self);
137/// ```
138///
139/// # Interpolating values
140///
141/// Values are interpolated with `#value`, or `#(value + 1)` for expressions.
142///
143/// # Iterators
144///
145/// Anything that can be used as an iterator can be iterated over with
146/// `#(iter)*`. A token can also be used to join inbetween each iteration, like
147/// `#(iter),*`.
148pub use rune_macros::quote;
149
150/// Helper derive to implement [`ToTokens`].
151pub use rune_macros::ToTokens;