Skip to main content

luaur_repl_cli/functions/
load.rs

1use alloc::string::String;
2use core::ffi::{c_char, c_void, CStr};
3
4use luaur_ast::records::parse_options::ParseOptions;
5use luaur_bytecode::records::bytecode_encoder::BytecodeEncoder;
6use luaur_cli_lib::functions::read_file::read_file;
7use luaur_code_gen::functions::luau_codegen_compile::luau_codegen_compile;
8use luaur_compiler::functions::compile::compile;
9use luaur_vm::enums::lua_status::lua_Status;
10use luaur_vm::functions::lua_gettop::lua_gettop;
11use luaur_vm::functions::lua_isstring::lua_isstring;
12use luaur_vm::functions::lua_l_sandboxthread::lua_l_sandboxthread;
13use luaur_vm::functions::lua_mainthread::lua_mainthread;
14use luaur_vm::functions::lua_newthread::lua_newthread;
15use luaur_vm::functions::lua_remove::lua_remove;
16use luaur_vm::functions::lua_resume::lua_resume;
17use luaur_vm::functions::lua_xmove::lua_xmove;
18use luaur_vm::functions::luau_load::luau_load;
19use luaur_vm::macros::lua_l_error::luaL_error;
20use luaur_vm::macros::lua_tostring::lua_tostring;
21use luaur_vm::type_aliases::lua_state::lua_State;
22
23use crate::records::repl_requirer::ReplRequirer;
24
25pub unsafe fn load(
26    l: *mut lua_State,
27    ctx: *mut c_void,
28    _path: *const c_char,
29    chunkname: *const c_char,
30    loadname: *const c_char,
31) -> i32 {
32    let req = &*(ctx as *const ReplRequirer);
33
34    // module needs to run in a new thread, isolated from the rest
35    // note: we create ML on main thread so that it doesn't inherit environment of L
36    let gl = lua_mainthread(l);
37    let ml = lua_newthread(gl);
38    lua_xmove(gl, l, 1);
39
40    // new thread needs to have the globals sandboxed
41    lua_l_sandboxthread(ml);
42
43    let loadname_str = CStr::from_ptr(loadname).to_string_lossy();
44
45    let contents = read_file(&loadname_str);
46    let had_contents = contents.is_some();
47    let mut status: i32 = lua_Status::LUA_OK as i32;
48
49    if let Some(ref source) = contents {
50        // now we can compile & run module on the new thread
51        struct NoopEncoder;
52        impl BytecodeEncoder for NoopEncoder {
53            fn encode(&mut self, _data: &mut [u32]) {}
54        }
55        let options = (req.copts.unwrap())();
56        let parse_options = ParseOptions::default();
57        let mut encoder = NoopEncoder;
58        let source_owned: String = source.clone();
59        let bytecode = compile(
60            &source_owned,
61            &options,
62            &parse_options,
63            &mut encoder as *mut dyn BytecodeEncoder,
64        );
65        status = luau_load(
66            ml,
67            chunkname,
68            bytecode.as_ptr() as *const c_char,
69            bytecode.len(),
70            0,
71        );
72    }
73
74    if !had_contents {
75        luaL_error!(l, "could not read file '{}'", loadname_str);
76    }
77
78    if status == 0 {
79        if (req.codegenEnabled.unwrap())() {
80            // The Rust codegen port exposes `luau_codegen_compile(L, idx)`; the
81            // native CompilationOptions (CodeGen_ColdFunctions / recordCounters)
82            // are not threaded through the public Rust API.
83            luau_codegen_compile(ml, -1);
84        }
85
86        if (req.coverageActive.unwrap())() {
87            (req.coverageTrack.unwrap())(ml as *mut c_void, -1);
88        }
89
90        if (req.countersActive.unwrap())() {
91            (req.countersTrack.unwrap())(ml as *mut c_void, -1);
92        }
93
94        let status = lua_resume(ml, l, 0);
95
96        if status == 0 {
97            if lua_gettop(ml) != 1 {
98                luaL_error!(l, "module must return a single value");
99            }
100        } else if status == lua_Status::LUA_YIELD as i32 {
101            luaL_error!(l, "module can not yield");
102        } else if lua_isstring(ml, -1) == 0 {
103            luaL_error!(l, "unknown error while running module");
104        } else {
105            let msg = lua_tostring!(ml, -1);
106            let msg = CStr::from_ptr(msg).to_string_lossy();
107            luaL_error!(l, "error while running module: {}", msg);
108        }
109    }
110
111    // add ML result to L stack
112    lua_xmove(ml, l, 1);
113
114    // remove ML thread from L stack
115    lua_remove(l, -2);
116
117    // added one value to L stack: module result
118    1
119}