use core::fmt;
use crate::alloc;
use crate::ast;
use crate::ast::Span;
use crate::compile::{self, ErrorKind, ItemMeta};
use crate::indexing::Indexer;
use crate::macros::{IntoLit, ToTokens, TokenStream};
use crate::parse::{Parse, Resolve};
use crate::runtime::Value;
use crate::{Source, SourceId};
#[cfg(feature = "std")]
#[cfg_attr(rune_docsrs, doc(cfg(feature = "std")))]
pub fn test<F, O>(f: F) -> crate::support::Result<O>
where
F: FnOnce(&mut MacroContext<'_, '_, '_>) -> crate::support::Result<O>,
{
use rust_alloc::rc::Rc;
use crate::compile::{NoopCompileVisitor, NoopSourceLoader, Pool, Prelude, UnitBuilder};
use crate::hir;
use crate::indexing::{IndexItem, Items, Scopes};
use crate::macros::Storage;
use crate::query::Query;
use crate::shared::{Consts, Gen};
use crate::support::Context as _;
use crate::{Context, Diagnostics, Item, Options, Sources};
let mut unit = UnitBuilder::default();
let prelude = Prelude::default();
let gen = Gen::default();
let const_arena = hir::Arena::new();
let mut consts = Consts::default();
let mut storage = Storage::default();
let mut sources = Sources::default();
let mut pool = Pool::new().context("Failed to allocate pool")?;
let mut visitor = NoopCompileVisitor::new();
let mut diagnostics = Diagnostics::default();
let mut source_loader = NoopSourceLoader::default();
let options = Options::from_default_env()?;
let context = Context::default();
let mut inner = Default::default();
let mut query = Query::new(
&mut unit,
&prelude,
&const_arena,
&mut consts,
&mut storage,
&mut sources,
&mut pool,
&mut visitor,
&mut diagnostics,
&mut source_loader,
&options,
&gen,
&context,
&mut inner,
);
let source_id = SourceId::empty();
let (root_id, root_mod_id) = query
.insert_root_mod(source_id, Span::empty())
.context("Failed to inserted root module")?;
let item_meta = query
.item_for("root item", root_id)
.context("Just inserted item meta does not exist")?;
let tree = Rc::default();
let mut idx = Indexer {
q: query.borrow(),
source_id,
items: Items::new(Item::new()).context("Failed to construct items")?,
scopes: Scopes::new().context("Failed to build indexer scopes")?,
item: IndexItem::new(root_mod_id, root_id),
nested_item: None,
macro_depth: 0,
root: None,
queue: None,
loaded: None,
tree: &tree,
};
let mut cx = MacroContext {
macro_span: Span::empty(),
input_span: Span::empty(),
item_meta,
idx: &mut idx,
};
f(&mut cx)
}
pub struct MacroContext<'a, 'b, 'arena> {
pub(crate) macro_span: Span,
pub(crate) input_span: Span,
pub(crate) item_meta: ItemMeta,
pub(crate) idx: &'a mut Indexer<'b, 'arena>,
}
impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> {
pub fn eval(&mut self, target: &ast::Expr) -> compile::Result<Value> {
target.eval(self)
}
pub fn lit<T>(&mut self, lit: T) -> alloc::Result<ast::Lit>
where
T: IntoLit,
{
T::into_lit(lit, self)
}
pub fn ident(&mut self, ident: &str) -> alloc::Result<ast::Ident> {
let span = self.macro_span();
let id = self.idx.q.storage.insert_str(ident)?;
let source = ast::LitSource::Synthetic(id);
Ok(ast::Ident { span, source })
}
pub fn label(&mut self, label: &str) -> alloc::Result<ast::Label> {
let span = self.macro_span();
let id = self.idx.q.storage.insert_str(label)?;
let source = ast::LitSource::Synthetic(id);
Ok(ast::Label { span, source })
}
pub fn stringify<T>(&mut self, tokens: &T) -> alloc::Result<Stringify<'_, 'a, 'b, 'arena>>
where
T: ToTokens,
{
let mut stream = TokenStream::new();
tokens.to_tokens(self, &mut stream)?;
Ok(Stringify { cx: self, stream })
}
pub fn resolve<'r, T>(&'r self, item: T) -> compile::Result<T::Output>
where
T: Resolve<'r>,
{
item.resolve(resolve_context!(self.idx.q))
}
pub(crate) fn literal_source(&self, source: ast::LitSource, span: Span) -> Option<&str> {
match source {
ast::LitSource::Text(source_id) => self.idx.q.sources.source(source_id, span),
ast::LitSource::Synthetic(id) => self.idx.q.storage.get_string(id),
ast::LitSource::BuiltIn(builtin) => Some(builtin.as_str()),
}
}
pub fn insert_source(&mut self, name: &str, source: &str) -> alloc::Result<SourceId> {
self.idx.q.sources.insert(Source::new(name, source)?)
}
pub fn parse_source<T>(&self, id: SourceId) -> compile::Result<T>
where
T: Parse,
{
let source = self.idx.q.sources.get(id).ok_or_else(|| {
compile::Error::new(Span::empty(), ErrorKind::MissingSourceId { source_id: id })
})?;
crate::parse::parse_all(source.as_str(), id, false)
}
pub fn macro_span(&self) -> Span {
self.macro_span
}
pub fn input_span(&self) -> Span {
self.input_span
}
}
pub struct Stringify<'cx, 'a, 'b, 'arena> {
cx: &'cx MacroContext<'a, 'b, 'arena>,
stream: TokenStream,
}
impl fmt::Display for Stringify<'_, '_, '_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut it = self.stream.iter();
let last = it.next_back();
for token in it {
token.token_fmt(self.cx, f)?;
write!(f, " ")?;
}
if let Some(last) = last {
last.token_fmt(self.cx, f)?;
}
Ok(())
}
}