rune/macros/
macro_compiler.rs
1use crate::alloc::prelude::*;
4use crate::ast;
5use crate::ast::Spanned;
6use crate::compile::{self, ErrorKind, ItemMeta};
7use crate::indexing::Indexer;
8use crate::macros::{MacroContext, ToTokens};
9use crate::parse::{Parse, Parser};
10
11use super::TokenStream;
12
13pub(crate) struct MacroCompiler<'a, 'b, 'arena> {
14 pub(crate) item_meta: ItemMeta,
15 pub(crate) idx: &'a mut Indexer<'b, 'arena>,
16}
17
18impl MacroCompiler<'_, '_, '_> {
19 pub(crate) fn eval_macro<T>(&mut self, macro_call: &ast::MacroCall) -> compile::Result<T>
21 where
22 T: Parse,
23 {
24 let span = macro_call.span();
25
26 if !self.idx.q.options.macros {
27 return Err(compile::Error::msg(
28 span,
29 "macros must be enabled with `-O macros=true`",
30 ));
31 }
32
33 let named = self.idx.q.convert_path(¯o_call.path)?;
34 let hash = self.idx.q.pool.item_type_hash(named.item);
35
36 let Some(handler) = self.idx.q.context.lookup_macro(hash) else {
37 return Err(compile::Error::new(
38 span,
39 ErrorKind::MissingMacro {
40 item: self.idx.q.pool.item(named.item).try_to_owned()?,
41 },
42 ));
43 };
44
45 let input_stream = ¯o_call.input;
46
47 let token_stream = {
48 let mut macro_context = MacroContext {
49 macro_span: span,
50 input_span: macro_call.input_span(),
51 item_meta: self.item_meta,
52 idx: self.idx,
53 };
54
55 handler(&mut macro_context, input_stream)?
56 };
57
58 let mut parser = Parser::from_token_stream(&token_stream, span);
59 let output = parser.parse::<T>()?;
60 parser.eof()?;
61
62 Ok(output)
63 }
64
65 pub(crate) fn eval_attribute_macro<T>(
67 &mut self,
68 attribute: &ast::Attribute,
69 item: &ast::Item,
70 ) -> compile::Result<Option<T>>
71 where
72 T: Parse,
73 {
74 let span = attribute.span();
75
76 if !self.idx.q.options.macros {
77 return Ok(None);
78 }
79
80 let named = self.idx.q.convert_path(&attribute.path)?;
81
82 let hash = self.idx.q.pool.item_type_hash(named.item);
83
84 let handler = match self.idx.q.context.lookup_attribute_macro(hash) {
85 Some(handler) => handler,
86 None => {
87 return Ok(None);
88 }
89 };
90
91 let input_stream = &attribute.input;
92
93 let token_stream = {
94 let mut macro_context = MacroContext {
95 macro_span: attribute.span(),
96 input_span: attribute.input_span(),
97 item_meta: self.item_meta,
98 idx: self.idx,
99 };
100
101 let mut item_stream = TokenStream::new();
102 item.to_tokens(&mut macro_context, &mut item_stream)?;
103
104 handler(&mut macro_context, input_stream, &item_stream)?
105 };
106
107 let mut parser = Parser::from_token_stream(&token_stream, span);
108
109 parser.parse_all().map(Some)
110 }
111}