pub use futures_executor::block_on;
pub use rune::CompileError::*;
pub use rune::ParseError::*;
pub use rune::WarningKind::*;
use rune::Warnings;
pub use runestick::VmErrorKind::*;
use runestick::{Component, Item, Source, Unit};
pub use runestick::{Function, Meta, Span, Value};
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type Error = Box<dyn std::error::Error + 'static + Send + Sync>;
pub fn compile_source(
context: &runestick::Context,
source: &str,
) -> Result<(Unit, Warnings), rune::CompileError> {
let source = Source::new("main", source.to_owned());
let unit = Rc::new(RefCell::new(Unit::with_default_prelude()));
let mut warnings = Warnings::new();
rune::compile(context, &source, &unit, &mut warnings)?;
let unit = Rc::try_unwrap(unit).unwrap().into_inner();
Ok((unit, warnings))
}
pub async fn run_async<N, A, T>(function: N, args: A, source: &str) -> Result<T>
where
N: IntoIterator,
N::Item: Into<Component>,
A: runestick::Args,
T: runestick::FromValue,
{
let context = runestick::Context::with_default_modules()?;
let (unit, _) = compile_source(&context, &source)?;
let vm = runestick::Vm::new(Arc::new(context), Arc::new(unit));
let output = vm.call(Item::of(function), args)?.async_complete().await?;
Ok(T::from_value(output)?)
}
pub fn run<N, A, T>(function: N, args: A, source: &str) -> Result<T>
where
N: IntoIterator,
N::Item: Into<Component>,
A: runestick::Args,
T: runestick::FromValue,
{
block_on(run_async(function, args, source))
}
#[macro_export]
macro_rules! rune {
($ty:ty => $source:expr) => {
$crate::run::<_, (), $ty>(&["main"], (), $source).expect("program to run successfully")
};
}
#[macro_export]
macro_rules! assert_parse_error {
($source:expr, $pat:pat => $cond:expr) => {{
let context = runestick::Context::with_default_modules().unwrap();
let err = $crate::compile_source(&context, &$source).unwrap_err();
match err {
rune::CompileError::ParseError { error: $pat } => ($cond),
_ => {
panic!("expected error `{}` but was `{:?}`", stringify!($pat), err);
}
}
}};
}
#[macro_export]
macro_rules! assert_vm_error {
($source:expr, $pat:pat => $cond:expr) => {{
let e = $crate::run::<_, _, ()>(&["main"], (), $source).unwrap_err();
let e = match e.downcast_ref::<runestick::VmError>() {
Some(e) => e,
None => {
panic!("{:?}", e);
}
};
let (kind, _) = e.kind().into_unwound_ref();
match kind {
$pat => $cond,
_ => {
panic!("expected error `{}` but was `{:?}`", stringify!($pat), e);
}
}
}};
}
#[macro_export]
macro_rules! assert_parse {
($source:expr) => {{
let context = runestick::Context::with_default_modules().unwrap();
$crate::compile_source(&context, $source).unwrap()
}};
}
#[macro_export]
macro_rules! assert_compile_error {
($source:expr, $pat:pat => $cond:expr) => {{
let context = runestick::Context::with_default_modules().unwrap();
let err = $crate::compile_source(&context, $source).unwrap_err();
match err {
$pat => ($cond),
_ => {
panic!("expected error `{}` but was `{:?}`", stringify!($pat), err);
}
}
}};
}
#[macro_export]
macro_rules! assert_warnings {
($source:expr $(, $pat:pat => $cond:expr)*) => {{
let context = runestick::Context::with_default_modules().unwrap();
let (_, warnings) = $crate::compile_source(&context, $source).expect("source should compile");
assert!(!warnings.is_empty(), "no warnings produced");
let mut it = warnings.into_iter();
$(
let warning = it.next().expect("expected a warning");
match warning.kind {
$pat => ($cond),
warning => {
panic!("expected warning `{}` but was `{:?}`", stringify!($pat), warning);
}
}
)*
assert!(it.next().is_none(), "there should be no more warnings");
}};
}