pub mod builtins;
pub mod engine;
use rhai::{Engine, Module, Scope};
pub fn eval(engine: &Engine, scope: &mut Scope<'_>, source: &str) -> Result<(), Failure> {
engine.run_with_scope(scope, source).map_err(Failure::from)
}
pub enum Failure {
Shlane(crate::error::ShlaneError),
Script(String),
}
impl From<Box<rhai::EvalAltResult>> for Failure {
fn from(err: Box<rhai::EvalAltResult>) -> Self {
match unwrap_shlane(*err) {
Ok(inner) => Self::Shlane(inner),
Err(message) => Self::Script(message),
}
}
}
fn unwrap_shlane(err: rhai::EvalAltResult) -> Result<crate::error::ShlaneError, String> {
use rhai::EvalAltResult;
match err {
EvalAltResult::ErrorSystem(_, boxed) => match boxed.downcast::<crate::error::ShlaneError>()
{
Ok(inner) => Ok(*inner),
Err(other) => Err(other.to_string()),
},
EvalAltResult::ErrorInFunctionCall(name, _, inner, _) => {
unwrap_shlane(*inner).map_err(|message| if message.is_empty() { name } else { message })
}
other => Err(other.to_string()),
}
}
pub fn condition(engine: &Engine, scope: &mut Scope<'_>, source: &str) -> Result<bool, String> {
engine
.eval_expression_with_scope::<bool>(scope, source.trim())
.map_err(|err| match err.to_string() {
message if message.contains("Output type incorrect") => {
format!("`if` must evaluate to true or false: {message}")
}
message => message,
})
}
pub fn load_shared(engine: &mut Engine, scope: &mut Scope<'_>, source: &str) -> Result<(), String> {
let ast = engine.compile(source).map_err(|err| err.to_string())?;
engine
.run_ast_with_scope(scope, &ast)
.map_err(|err| err.to_string())?;
let mut functions = ast.clone();
functions.clear_statements();
let module =
Module::eval_ast_as_new(Scope::new(), &functions, engine).map_err(|err| err.to_string())?;
engine.register_global_module(module.into());
Ok(())
}