rune/macros/
macro_compiler.rsuse crate::alloc::prelude::*;
use crate::ast;
use crate::ast::Spanned;
use crate::compile::{self, ErrorKind, ItemMeta};
use crate::indexing::Indexer;
use crate::macros::{MacroContext, ToTokens};
use crate::parse::{Parse, Parser};
use super::TokenStream;
pub(crate) struct MacroCompiler<'a, 'b, 'arena> {
pub(crate) item_meta: ItemMeta,
pub(crate) idx: &'a mut Indexer<'b, 'arena>,
}
impl MacroCompiler<'_, '_, '_> {
pub(crate) fn eval_macro<T>(&mut self, macro_call: &ast::MacroCall) -> compile::Result<T>
where
T: Parse,
{
let span = macro_call.span();
if !self.idx.q.options.macros {
return Err(compile::Error::msg(
span,
"macros must be enabled with `-O macros=true`",
));
}
let named = self.idx.q.convert_path(¯o_call.path)?;
let hash = self.idx.q.pool.item_type_hash(named.item);
let Some(handler) = self.idx.q.context.lookup_macro(hash) else {
return Err(compile::Error::new(
span,
ErrorKind::MissingMacro {
item: self.idx.q.pool.item(named.item).try_to_owned()?,
},
));
};
let input_stream = ¯o_call.input;
let token_stream = {
let mut macro_context = MacroContext {
macro_span: span,
input_span: macro_call.input_span(),
item_meta: self.item_meta,
idx: self.idx,
};
handler(&mut macro_context, input_stream)?
};
let mut parser = Parser::from_token_stream(&token_stream, span);
let output = parser.parse::<T>()?;
parser.eof()?;
Ok(output)
}
pub(crate) fn eval_attribute_macro<T>(
&mut self,
attribute: &ast::Attribute,
item: &ast::Item,
) -> compile::Result<Option<T>>
where
T: Parse,
{
let span = attribute.span();
if !self.idx.q.options.macros {
return Ok(None);
}
let named = self.idx.q.convert_path(&attribute.path)?;
let hash = self.idx.q.pool.item_type_hash(named.item);
let handler = match self.idx.q.context.lookup_attribute_macro(hash) {
Some(handler) => handler,
None => {
return Ok(None);
}
};
let input_stream = &attribute.input;
let token_stream = {
let mut macro_context = MacroContext {
macro_span: attribute.span(),
input_span: attribute.input_span(),
item_meta: self.item_meta,
idx: self.idx,
};
let mut item_stream = TokenStream::new();
item.to_tokens(&mut macro_context, &mut item_stream)?;
handler(&mut macro_context, input_stream, &item_stream)?
};
let mut parser = Parser::from_token_stream(&token_stream, span);
parser.parse_all().map(Some)
}
}