use mlua::{Function, Lua as Luau, MultiValue, Result as lResult, Table, Value}; use color_print::{cformat, ceprintln}; use core::fmt; use shell::Shell; use crate::{ps::Ps, vm::terminal::Terminal, MapDisplay}; mod shell; mod terminal; mod alias; trait LuauRuntimeErr { fn map_or_luau_rt_err Option>(self, f: F) -> Option; } impl LuauRuntimeErr for Result { #[inline] fn map_or_luau_rt_err Option>(self, f: F) -> Option { self.map_or_else(|luau_rt_err| { ceprintln!("====\n[!]: {luau_rt_err}\n===="); None }, f) } } trait Globals { const LIB_VERSION: &str; const CONV_ERROR: &str; fn global_warn(&self, luau_globals: &Table) -> lResult<()>; fn global_version(&self, luau_globals: &Table) -> lResult<()>; } impl Globals for LuauVm { const LIB_VERSION: &str = env!("CARGO_PKG_VERSION"); const CONV_ERROR: &str = ""; fn global_warn(&self, luau_globals: &Table) -> lResult<()> { let luau_print = luau_globals.get::("print")?; luau_globals.set("warn", self.vm.create_function(move |this, args: MultiValue| -> lResult<()> { let luau_multi_values = args.into_iter() .map(|value| cformat!("{}", value.to_string().unwrap_or(Self::CONV_ERROR.to_owned()))) .map(|arg_v| Value::String(this.create_string(arg_v).unwrap())) .collect::(); luau_print.call::<()>(luau_multi_values)?; Ok(()) })?) } fn global_version(&self, luau_globals: &Table) -> lResult<()> { let luau_info = luau_globals.get::("_VERSION")?; luau_globals.set("_VERSION", format!("{luau_info}, liblambdashell {}", Self::LIB_VERSION)) } } pub struct LuauVm { vm: Luau, ps: Ps, } impl LuauVm { pub(crate) fn new(ps: Ps) -> Self { Self { vm: Luau::new(), ps } } fn set_shell_globals(&self) -> lResult<()> { let luau_globals = self.vm.globals(); self.global_warn(&luau_globals)?; self.global_version(&luau_globals)?; self.global_terminal(&luau_globals)?; self.global_shell(&luau_globals)?; luau_globals.set("getfenv", mlua::Nil)?; luau_globals.set("setfenv", mlua::Nil)?; self.vm.sandbox(true)?; Ok(()) } pub fn exec(&self, source: String) { self.set_shell_globals().map_or_display_none(|()| self.vm.load(source).exec().map_or_luau_rt_err(Some)); } }