use alloc::string::String;
use alloc::string::ToString;
use core::cell::RefCell;
use core::ffi::c_char;
use core::ffi::c_int;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::functions::check_script::check_script;
use crate::functions::run_code::run_code;
use luaur_common::set_luau_bool_flags;
use luaur_vm::functions::lua_close::lua_close;
use luaur_vm::functions::lua_gettop::lua_gettop;
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_l_sandbox::lua_l_sandbox;
use luaur_vm::functions::lua_l_sandboxthread::lua_l_sandboxthread;
use luaur_vm::functions::lua_l_tolstring::lua_l_tolstring;
use luaur_vm::functions::lua_pushcclosurek::lua_pushcclosurek;
use luaur_vm::macros::lua_pop::lua_pop;
use luaur_vm::macros::lua_setglobal::lua_setglobal;
use luaur_vm::type_aliases::lua_state::lua_State;
#[wasm_bindgen(start)]
pub fn wasm_start() {
console_error_panic_hook::set_once();
}
thread_local! {
static PRINT_BUFFER: RefCell<String> = const { RefCell::new(String::new()) };
}
unsafe fn capturing_print(l: *mut lua_State) -> c_int {
let n = lua_gettop(l);
let mut line = String::new();
for i in 1..=n {
let mut len: usize = 0;
let s = lua_l_tolstring(l, i, &mut len);
if i > 1 {
line.push('\t');
}
if !s.is_null() {
let bytes = core::slice::from_raw_parts(s as *const u8, len);
line.push_str(&String::from_utf8_lossy(bytes));
}
lua_pop(l, 1);
}
line.push('\n');
PRINT_BUFFER.with(|b| b.borrow_mut().push_str(&line));
0
}
#[wasm_bindgen]
pub fn run(source: &str) -> String {
set_luau_bool_flags(true);
unsafe {
let l: *mut lua_State = lua_l_newstate();
lua_l_openlibs(l);
lua_pushcclosurek(l, Some(capturing_print), c"print".as_ptr(), 0, None);
lua_setglobal(l, c"print".as_ptr());
lua_l_sandbox(l);
lua_l_sandboxthread(l);
PRINT_BUFFER.with(|b| b.borrow_mut().clear());
let error = run_code(l, source);
lua_close(l);
let mut out = PRINT_BUFFER.with(|b| core::mem::take(&mut *b.borrow_mut()));
if !error.is_empty() {
if !out.is_empty() && !out.ends_with('\n') {
out.push('\n');
}
out.push_str(&error);
}
out
}
}
#[wasm_bindgen]
pub fn check(source: &str) -> String {
let c_source = match alloc::ffi::CString::new(source) {
Ok(s) => s,
Err(_) => return "error: source contains an interior NUL byte".to_string(),
};
let result_ptr = unsafe { check_script(c_source.as_ptr() as *const c_char, 0) };
if result_ptr.is_null() {
return "No errors.".to_string();
}
unsafe {
core::ffi::CStr::from_ptr(result_ptr)
.to_string_lossy()
.into_owned()
}
}