use std::io::Read;
use std::process::exit;
use luaur_compiler::functions::luau_compile::luau_compile;
use luaur_vm::functions::lua_debugtrace::lua_debugtrace;
use luaur_vm::functions::lua_l_newstate::lua_l_newstate;
use luaur_vm::functions::lua_l_openlibs::lua_l_openlibs;
use luaur_vm::functions::lua_newthread::lua_newthread;
use luaur_vm::functions::lua_resume::lua_resume;
use luaur_vm::functions::lua_tolstring::lua_tolstring;
use luaur_vm::functions::luau_load::luau_load;
unsafe fn stack_string(t: *mut luaur_vm::type_aliases::lua_state::lua_State) -> String {
let mut len = 0usize;
let s = lua_tolstring(t, -1, &mut len);
if s.is_null() {
return "<non-string error>".to_string();
}
let bytes = std::slice::from_raw_parts(s as *const u8, len);
String::from_utf8_lossy(bytes).into_owned()
}
fn main() {
std::panic::set_hook(Box::new(|_| {}));
let path = std::env::args().nth(1).unwrap_or_else(|| {
eprintln!("usage: run_luau <script.luau>");
exit(2);
});
let mut src = Vec::new();
std::fs::File::open(&path)
.unwrap_or_else(|e| {
eprintln!("run_luau: cannot open {path}: {e}");
exit(2);
})
.read_to_end(&mut src)
.unwrap_or_else(|e| {
eprintln!("run_luau: cannot read {path}: {e}");
exit(2);
});
luaur_common::set_all_flags(true);
let chunkname = std::ffi::CString::new(format!("@{path}")).expect("path has NUL");
unsafe {
let mut outsize: usize = 0;
let bc = luau_compile(
src.as_ptr() as *const core::ffi::c_char,
src.len(),
core::ptr::null_mut(),
&mut outsize,
);
if bc.is_null() || outsize == 0 {
eprintln!("run_luau: compilation produced no bytecode");
exit(1);
}
let l = lua_l_newstate();
assert!(!l.is_null(), "lua_l_newstate returned null");
lua_l_openlibs(l);
let t = lua_newthread(l);
assert!(!t.is_null(), "lua_newthread returned null");
let rc = luau_load(
t,
chunkname.as_ptr(),
bc as *const core::ffi::c_char,
outsize,
0,
);
if rc != 0 {
eprintln!("{}", stack_string(t));
exit(1);
}
let status = lua_resume(t, core::ptr::null_mut(), 0);
if status != 0 {
eprintln!("{}", stack_string(t));
let tb = lua_debugtrace(t);
if !tb.is_null() {
let trace = std::ffi::CStr::from_ptr(tb).to_string_lossy();
if !trace.trim().is_empty() {
eprintln!("stack traceback:\n{}", trace);
}
}
exit(1);
}
}
}