Skip to main content

luaur_require/functions/
lua_requireinternal.rs

1use crate::enums::status_require_impl::Status;
2use crate::functions::lua_requirecont::{lua_requirecont, K_REQUIRE_STACK_VALUES};
3use crate::functions::resolve_require::resolve_require;
4use crate::records::luarequire_configuration::luarequire_Configuration;
5use alloc::ffi::CString;
6use core::ffi::{c_char, c_int};
7use luaur_vm::enums::lua_status::lua_Status;
8use luaur_vm::enums::lua_type::lua_Type;
9use luaur_vm::functions::lua_error::lua_error;
10use luaur_vm::functions::lua_getfield::lua_getfield;
11use luaur_vm::functions::lua_gettop::lua_gettop;
12use luaur_vm::functions::lua_l_findtable::luaL_findtable;
13use luaur_vm::functions::lua_pushstring::lua_pushstring;
14use luaur_vm::functions::lua_remove::lua_remove;
15use luaur_vm::functions::lua_settop::lua_settop;
16use luaur_vm::functions::lua_tolightuserdata::lua_tolightuserdata;
17use luaur_vm::functions::lua_tolstring::lua_tolstring;
18use luaur_vm::functions::lua_touserdata::lua_touserdata;
19use luaur_vm::functions::lua_type::lua_type;
20use luaur_vm::functions::lua_yield::lua_yield;
21use luaur_vm::macros::lua_l_checkstring::luaL_checkstring;
22use luaur_vm::macros::lua_l_error::luaL_error;
23use luaur_vm::macros::lua_pop::lua_pop;
24use luaur_vm::macros::lua_registryindex::LUA_REGISTRYINDEX;
25use luaur_vm::macros::lua_upvalueindex::lua_upvalueindex;
26use luaur_vm::records::lua_state::lua_State;
27
28const REGISTERED_CACHE_TABLE_KEY: *const c_char = c"_REGISTEREDMODULES".as_ptr();
29
30pub fn lua_requireinternal(l: *mut lua_State, requirer_chunkname: *const c_char) -> i32 {
31    unsafe {
32        lua_settop(l, 1);
33
34        let lrc = lua_touserdata(l, lua_upvalueindex(1)) as *mut luarequire_Configuration;
35        if lrc.is_null() {
36            luaL_error!(l, "unable to find require configuration");
37            return 0;
38        }
39
40        let ctx = lua_tolightuserdata(l, lua_upvalueindex(2));
41        let path = luaL_checkstring!(l, 1);
42
43        luaL_findtable(l, LUA_REGISTRYINDEX, REGISTERED_CACHE_TABLE_KEY, 1);
44        let path_bytes = core::ffi::CStr::from_ptr(path).to_bytes();
45        let mut path_lower = path_bytes.to_vec();
46        for byte in &mut path_lower {
47            if *byte >= b'A' && *byte <= b'Z' {
48                *byte += b'a' - b'A';
49            }
50        }
51        let path_lower_c = CString::new(path_lower).unwrap();
52        lua_getfield(l, -1, path_lower_c.as_ptr());
53        if lua_type(l, -1) != lua_Type::LUA_TNIL as c_int {
54            lua_remove(l, -2);
55            return 1;
56        }
57        lua_pop(l, 2);
58
59        let path_string = core::ffi::CStr::from_ptr(path)
60            .to_string_lossy()
61            .into_owned();
62        let mut resolve_error = false;
63
64        {
65            let resolved_require = resolve_require(lrc, l, ctx, requirer_chunkname, path_string);
66
67            if resolved_require.status == Status::Cached {
68                return 1;
69            }
70
71            if resolved_require.status == Status::ErrorReported {
72                let error = CString::new(resolved_require.error.replace('\0', "")).unwrap();
73                lua_pushstring(l, error.as_ptr());
74                resolve_error = true;
75            } else {
76                let cache_key = CString::new(resolved_require.cacheKey.replace('\0', "")).unwrap();
77                let chunkname = CString::new(resolved_require.chunkname.replace('\0', "")).unwrap();
78                let loadname = CString::new(resolved_require.loadname.replace('\0', "")).unwrap();
79                lua_pushstring(l, cache_key.as_ptr());
80                lua_pushstring(l, chunkname.as_ptr());
81                lua_pushstring(l, loadname.as_ptr());
82            }
83        }
84
85        if resolve_error {
86            lua_error(l);
87        }
88
89        let stack_values = lua_gettop(l);
90        luaur_common::LUAU_ASSERT!(stack_values == K_REQUIRE_STACK_VALUES);
91
92        let chunkname = lua_tolstring(l, -2, core::ptr::null_mut());
93        let loadname = lua_tolstring(l, -1, core::ptr::null_mut());
94
95        let Some(load) = (*lrc).load else {
96            luaL_error!(
97                l,
98                "require configuration is missing required function pointer: load"
99            );
100            return 0;
101        };
102
103        let num_results = load(l as *mut core::ffi::c_void, ctx, path, chunkname, loadname);
104        if num_results == -1 {
105            if lua_gettop(l) != stack_values {
106                luaL_error!(l, "stack cannot be modified when require yields");
107                return 0;
108            }
109
110            return lua_yield(l, 0);
111        }
112
113        lua_requirecont(l, lua_Status::LUA_OK as c_int)
114    }
115}