use crate as rune;
use crate::alloc::{try_format, Vec};
use crate::ast;
use crate::compile;
use crate::macros::{quote, FormatArgs, MacroContext, TokenStream};
use crate::parse::Parser;
use crate::runtime::Function;
use crate::{Any, ContextError, Module, T};
#[rune::module(::std::test)]
pub fn module() -> Result<Module, ContextError> {
let mut m = Module::from_meta(self::module_meta)?.with_unique("std::test");
m.macro_meta(assert)?;
m.macro_meta(assert_eq)?;
m.macro_meta(assert_ne)?;
m.ty::<Bencher>()?.docs(docstring! {
})?;
m.function_meta(Bencher::iter)?;
Ok(m)
}
#[derive(Default, Any)]
#[rune(module = crate, item = ::std::test)]
pub struct Bencher {
fns: Vec<Function>,
}
impl Bencher {
pub fn into_functions(self) -> Vec<Function> {
self.fns
}
#[rune::function(vm_result)]
fn iter(&mut self, f: Function) {
self.fns.try_push(f).vm?;
}
}
#[rune::macro_]
pub(crate) fn assert(
cx: &mut MacroContext<'_, '_, '_>,
stream: &TokenStream,
) -> compile::Result<TokenStream> {
use crate as rune;
let mut p = Parser::from_token_stream(stream, cx.input_span());
let expr = p.parse::<ast::Expr>()?;
let message = if p.parse::<Option<T![,]>>()?.is_some() {
p.parse_all::<Option<FormatArgs>>()?
} else {
None
};
let output = if let Some(message) = &message {
let expanded = message.expand(cx)?;
quote!(if !(#expr) {
::std::panic("assertion failed: " + (#expanded));
})
} else {
let message = try_format!("assertion failed: {}", cx.stringify(&expr)?);
let message = cx.lit(&message)?;
quote!(if !(#expr) {
::std::panic(#message);
})
};
Ok(output.into_token_stream(cx)?)
}
#[rune::macro_]
pub(crate) fn assert_eq(
cx: &mut MacroContext<'_, '_, '_>,
stream: &TokenStream,
) -> compile::Result<TokenStream> {
use crate as rune;
let mut p = Parser::from_token_stream(stream, cx.input_span());
let left = p.parse::<ast::Expr>()?;
p.parse::<T![,]>()?;
let right = p.parse::<ast::Expr>()?;
let message = if p.parse::<Option<T![,]>>()?.is_some() {
p.parse_all::<Option<FormatArgs>>()?
} else {
None
};
let output = if let Some(message) = &message {
let message = message.expand(cx)?;
quote! {{
let left = #left;
let right = #right;
if !(left == right) {
let message = #message;
message += ::std::fmt::format!("\nleft: {:?}", left);
message += ::std::fmt::format!("\nright: {:?}", right);
::std::panic("assertion failed (left == right): " + message);
}
}}
} else {
let message = cx.lit("assertion failed (left == right):")?;
quote! {{
let left = #left;
let right = #right;
if !(left == right) {
let message = ::std::string::String::from(#message);
message += ::std::fmt::format!("\nleft: {:?}", left);
message += ::std::fmt::format!("\nright: {:?}", right);
::std::panic(message);
}
}}
};
Ok(output.into_token_stream(cx)?)
}
#[rune::macro_]
pub(crate) fn assert_ne(
cx: &mut MacroContext<'_, '_, '_>,
stream: &TokenStream,
) -> compile::Result<TokenStream> {
use crate as rune;
let mut p = Parser::from_token_stream(stream, cx.input_span());
let left = p.parse::<ast::Expr>()?;
p.parse::<T![,]>()?;
let right = p.parse::<ast::Expr>()?;
let message = if p.parse::<Option<T![,]>>()?.is_some() {
p.parse_all::<Option<FormatArgs>>()?
} else {
None
};
let output = if let Some(message) = &message {
let message = message.expand(cx)?;
quote! {{
let left = #left;
let right = #right;
if !(left != right) {
let message = #message;
message += ::std::fmt::format!("\nleft: {:?}", left);
message += ::std::fmt::format!("\nright: {:?}", right);
::std::panic("assertion failed (left != right): " + message);
}
}}
} else {
let message = cx.lit("assertion failed (left != right):")?;
quote! {{
let left = #left;
let right = #right;
if !(left != right) {
let message = ::std::string::String::from(#message);
message += ::std::fmt::format!("\nleft: {:?}", left);
message += ::std::fmt::format!("\nright: {:?}", right);
::std::panic(message);
}
}}
};
Ok(output.into_token_stream(cx)?)
}