1use std::ffi::CStr;
6use std::os::raw::{c_char, c_int, c_void};
7use std::{mem, ptr};
8
9use super::lauxlib::*;
10use super::lua::*;
11use super::luacode::*;
12
13pub const LUA_RESUMEERROR: c_int = -1;
14
15unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
16 while a < b {
17 lua_pushvalue(L, a);
18 lua_pushvalue(L, b);
19 lua_replace(L, a);
20 lua_replace(L, b);
21 a += 1;
22 b -= 1;
23 }
24}
25
26const COMPAT53_LEVELS1: c_int = 12; const COMPAT53_LEVELS2: c_int = 10; unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
30 if level == 0 || lua_istable(L, -1) == 0 {
31 return 0; }
33
34 lua_pushnil(L); while lua_next(L, -2) != 0 {
36 if lua_type(L, -2) == LUA_TSTRING {
38 if lua_rawequal(L, objidx, -1) != 0 {
40 lua_pop(L, 1); return 1;
43 } else if compat53_findfield(L, objidx, level - 1) != 0 {
44 lua_remove(L, -2); lua_pushliteral(L, c".");
47 lua_insert(L, -2); lua_concat(L, 3);
49 return 1;
50 }
51 }
52 lua_pop(L, 1); }
54 0 }
56
57unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int {
58 let top = lua_gettop(L);
59 lua_getinfo(L, level, cstr!("f"), ar);
61 lua_pushvalue(L, LUA_GLOBALSINDEX);
62 if compat53_findfield(L, top + 1, 2) != 0 {
63 lua_copy(L, -1, top + 1); lua_pop(L, 2); 1
66 } else {
67 lua_settop(L, top); 0
69 }
70}
71
72unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
73 if !(*ar).name.is_null() {
74 lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
76 } else if compat53_pushglobalfuncname(L, level, ar) != 0 {
77 lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
78 lua_remove(L, -2); } else {
80 lua_pushliteral(L, c"?");
81 }
82}
83
84pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
89 idx = lua_absindex(L, idx);
90 if n > 0 {
91 for _ in 0..n {
93 lua_insert(L, idx);
94 }
95 return;
96 }
97 let n_elems = lua_gettop(L) - idx + 1;
98 if n < 0 {
99 n += n_elems;
100 }
101 if n > 0 && n < n_elems {
102 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
103 n = n_elems - n;
104 compat53_reverse(L, idx, idx + n - 1);
105 compat53_reverse(L, idx + n, idx + n_elems - 1);
106 compat53_reverse(L, idx, idx + n_elems - 1);
107 }
108}
109
110#[inline(always)]
111pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
112 let abs_to = lua_absindex(L, toidx);
113 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
114 lua_pushvalue(L, fromidx);
115 lua_replace(L, abs_to);
116}
117
118#[inline(always)]
119pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
120 if lua_type(L, idx) == LUA_TNUMBER {
121 let n = lua_tonumber(L, idx);
122 let i = lua_tointeger(L, idx);
123 if (n - i as lua_Number).abs() < lua_Number::EPSILON {
124 return 1;
125 }
126 }
127 0
128}
129
130#[inline(always)]
131pub unsafe fn lua_pushinteger(L: *mut lua_State, i: lua_Integer) {
132 lua_pushnumber(L, i as lua_Number);
133}
134
135#[inline(always)]
136pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
137 lua_tointegerx(L, i, ptr::null_mut())
138}
139
140pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
141 let mut ok = 0;
142 let n = lua_tonumberx(L, i, &mut ok);
143 let n_int = n as lua_Integer;
144 if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
145 if !isnum.is_null() {
146 *isnum = 1;
147 }
148 return n_int;
149 }
150 if !isnum.is_null() {
151 *isnum = 0;
152 }
153 0
154}
155
156#[inline(always)]
157pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
158 lua_objlen(L, idx)
159}
160
161#[inline(always)]
162pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
163 if l == 0 {
164 lua_pushlstring_(L, cstr!(""), 0);
165 } else {
166 lua_pushlstring_(L, s, l);
167 }
168 lua_tostring(L, -1)
169}
170
171#[inline(always)]
172pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
173 lua_pushstring_(L, s);
174 lua_tostring(L, -1)
175}
176
177#[inline(always)]
178pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
179 idx = lua_absindex(L, idx);
180 lua_pushinteger(L, n);
181 lua_gettable(L, idx)
182}
183
184#[inline(always)]
185pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
186 let n = n.try_into().expect("cannot convert index from lua_Integer");
187 lua_rawgeti_(L, idx, n)
188}
189
190#[inline(always)]
191pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
192 let abs_i = lua_absindex(L, idx);
193 lua_pushlightuserdata(L, p as *mut c_void);
194 lua_rawget(L, abs_i)
195}
196
197#[inline(always)]
198pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
199 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
200 idx = lua_absindex(L, idx);
201 lua_pushliteral(L, c"__mlua_uservalues");
202 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
203 return LUA_TNIL;
204 }
205 lua_pushvalue(L, idx);
206 lua_rawget(L, -2);
207 lua_remove(L, -2);
208 lua_type(L, -1)
209}
210
211#[inline(always)]
212pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
213 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
214 idx = lua_absindex(L, idx);
215 lua_pushinteger(L, n);
216 lua_insert(L, -2);
217 lua_settable(L, idx);
218}
219
220#[inline(always)]
221pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
222 let n = n.try_into().expect("cannot convert index from lua_Integer");
223 lua_rawseti_(L, idx, n)
224}
225
226#[inline(always)]
227pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
228 let abs_i = lua_absindex(L, idx);
229 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
230 lua_pushlightuserdata(L, p as *mut c_void);
231 lua_insert(L, -2);
232 lua_rawset(L, abs_i);
233}
234
235#[inline(always)]
236pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
237 luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
238 idx = lua_absindex(L, idx);
239 lua_pushliteral(L, c"__mlua_uservalues");
240 lua_pushvalue(L, -1);
241 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
242 lua_pop(L, 1);
243 lua_createtable(L, 0, 2); lua_createtable(L, 0, 1); lua_pushliteral(L, c"k");
246 lua_setfield(L, -2, cstr!("__mode"));
247 lua_setmetatable(L, -2);
248 lua_pushvalue(L, -2);
249 lua_pushvalue(L, -2);
250 lua_rawset(L, LUA_REGISTRYINDEX);
251 }
252 lua_replace(L, -2);
253 lua_pushvalue(L, idx);
254 lua_pushvalue(L, -3);
255 lua_remove(L, -4);
256 lua_rawset(L, -3);
257 lua_pop(L, 1);
258}
259
260#[inline(always)]
261pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
262 match lua_type(L, idx) {
263 LUA_TSTRING => {
264 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
265 }
266 LUA_TTABLE => {
267 if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
268 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
269 }
270 }
271 LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
272 _ => {
273 luaL_error(
274 L,
275 cstr!("attempt to get length of a %s value"),
276 lua_typename(L, lua_type(L, idx)),
277 );
278 }
279 }
280}
281
282#[inline(always)]
283pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
284 lua_pushvalue(L, LUA_GLOBALSINDEX);
285}
286
287#[inline(always)]
288pub unsafe fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
289 let ret = lua_resume_(L, from, narg);
290 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
291 *nres = lua_gettop(L);
292 }
293 ret
294}
295
296#[inline(always)]
297pub unsafe fn lua_resumex(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
298 let ret = if narg == LUA_RESUMEERROR {
299 lua_resumeerror(L, from)
300 } else {
301 lua_resume_(L, from, narg)
302 };
303 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
304 *nres = lua_gettop(L);
305 }
306 ret
307}
308
309#[inline(always)]
314pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
315 if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
316 if !msg.is_null() {
317 luaL_error(L, cstr!("stack overflow (%s)"), msg);
318 } else {
319 lua_pushliteral(L, c"stack overflow");
320 lua_error(L);
321 }
322 }
323}
324
325#[inline(always)]
326pub unsafe fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer {
327 let mut isnum = 0;
328 let int = lua_tointegerx(L, narg, &mut isnum);
329 if isnum == 0 {
330 luaL_typeerror(L, narg, lua_typename(L, LUA_TNUMBER));
331 }
332 int
333}
334
335pub unsafe fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer {
336 if lua_isnoneornil(L, narg) != 0 {
337 def
338 } else {
339 luaL_checkinteger(L, narg)
340 }
341}
342
343#[inline(always)]
344pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
345 if luaL_getmetafield_(L, obj, e) != 0 {
346 lua_type(L, -1)
347 } else {
348 LUA_TNIL
349 }
350}
351
352#[inline(always)]
353pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
354 if luaL_newmetatable_(L, tname) != 0 {
355 lua_pushstring(L, tname);
356 lua_setfield(L, -2, cstr!("__type"));
357 1
358 } else {
359 0
360 }
361}
362
363pub unsafe fn luaL_loadbufferenv(
364 L: *mut lua_State,
365 data: *const c_char,
366 mut size: usize,
367 name: *const c_char,
368 mode: *const c_char,
369 mut env: c_int,
370) -> c_int {
371 unsafe extern "C" {
372 fn free(p: *mut c_void);
373 }
374
375 unsafe extern "C" fn data_dtor(_: *mut lua_State, data: *mut c_void) {
376 free(*(data as *mut *mut c_char) as *mut c_void);
377 }
378
379 let chunk_is_text = size == 0 || (*data as u8) >= b'\t';
380 if !mode.is_null() {
381 let modeb = CStr::from_ptr(mode).to_bytes();
382 if !chunk_is_text && !modeb.contains(&b'b') {
383 lua_pushfstring(L, cstr!("attempt to load a binary chunk (mode is '%s')"), mode);
384 return LUA_ERRSYNTAX;
385 } else if chunk_is_text && !modeb.contains(&b't') {
386 lua_pushfstring(L, cstr!("attempt to load a text chunk (mode is '%s')"), mode);
387 return LUA_ERRSYNTAX;
388 }
389 }
390
391 let status = if chunk_is_text {
392 if env < 0 {
393 env -= 1;
394 }
395 let data_ud = lua_newuserdatadtor(L, mem::size_of::<*mut c_char>(), data_dtor) as *mut *mut c_char;
396 let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
397 ptr::write(data_ud, data);
398 let status = luau_load(L, name, data, size, env);
401 lua_replace(L, -2); status
403 } else {
404 luau_load(L, name, data, size, env)
405 };
406
407 if status != 0 {
408 if lua_isstring(L, -1) != 0 && CStr::from_ptr(lua_tostring(L, -1)) == c"not enough memory" {
409 return LUA_ERRMEM;
411 }
412 return LUA_ERRSYNTAX;
413 }
414
415 LUA_OK
416}
417
418#[inline(always)]
419pub unsafe fn luaL_loadbufferx(
420 L: *mut lua_State,
421 data: *const c_char,
422 size: usize,
423 name: *const c_char,
424 mode: *const c_char,
425) -> c_int {
426 luaL_loadbufferenv(L, data, size, name, mode, 0)
427}
428
429#[inline(always)]
430pub unsafe fn luaL_loadbuffer(
431 L: *mut lua_State,
432 data: *const c_char,
433 size: usize,
434 name: *const c_char,
435) -> c_int {
436 luaL_loadbufferenv(L, data, size, name, ptr::null(), 0)
437}
438
439#[inline(always)]
440pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
441 let mut isnum = 0;
442 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
443 lua_len(L, idx);
444 let res = lua_tointegerx(L, -1, &mut isnum);
445 lua_pop(L, 1);
446 if isnum == 0 {
447 luaL_error(L, cstr!("object length is not an integer"));
448 }
449 res
450}
451
452pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, mut level: c_int) {
453 let mut ar: lua_Debug = mem::zeroed();
454 let top = lua_gettop(L);
455 let numlevels = lua_stackdepth(L);
456 let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
457 COMPAT53_LEVELS1
458 } else {
459 0
460 };
461
462 if !msg.is_null() {
463 lua_pushfstring(L, cstr!("%s\n"), msg);
464 }
465 lua_pushliteral(L, c"stack traceback:");
466 while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
467 if level + 1 == mark {
468 lua_pushliteral(L, c"\n\t..."); level = numlevels - COMPAT53_LEVELS2; } else {
472 lua_getinfo(L1, level, cstr!("sln"), &mut ar);
473 lua_pushfstring(L, cstr!("\n\t%s:"), ar.short_src);
474 if ar.currentline > 0 {
475 lua_pushfstring(L, cstr!("%d:"), ar.currentline);
476 }
477 lua_pushliteral(L, c" in ");
478 compat53_pushfuncname(L, level, &mut ar);
479 lua_concat(L, lua_gettop(L) - top);
480 }
481 level += 1;
482 }
483 lua_concat(L, lua_gettop(L) - top);
484}
485
486pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
487 idx = lua_absindex(L, idx);
488 if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
489 match lua_type(L, idx) {
490 LUA_TNIL => {
491 lua_pushliteral(L, c"nil");
492 }
493 LUA_TSTRING | LUA_TNUMBER => {
494 lua_pushvalue(L, idx);
495 }
496 LUA_TBOOLEAN => {
497 if lua_toboolean(L, idx) == 0 {
498 lua_pushliteral(L, c"false");
499 } else {
500 lua_pushliteral(L, c"true");
501 }
502 }
503 t => {
504 let tt = luaL_getmetafield(L, idx, cstr!("__type"));
505 let name = if tt == LUA_TSTRING {
506 lua_tostring(L, -1)
507 } else {
508 lua_typename(L, t)
509 };
510 lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
511 if tt != LUA_TNIL {
512 lua_replace(L, -2); }
514 }
515 };
516 } else if lua_isstring(L, -1) == 0 {
517 luaL_error(L, cstr!("'__tostring' must return a string"));
518 }
519 lua_tolstring(L, -1, len)
520}
521
522#[inline(always)]
523pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
524 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
525 luaL_getmetatable(L, tname);
526 lua_setmetatable(L, -2);
527}
528
529pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
530 let abs_i = lua_absindex(L, idx);
531 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
532 lua_pushstring_(L, fname);
533 if lua_gettable(L, abs_i) == LUA_TTABLE {
534 return 1;
535 }
536 lua_pop(L, 1);
537 lua_newtable(L);
538 lua_pushstring_(L, fname);
539 lua_pushvalue(L, -2);
540 lua_settable(L, abs_i);
541 0
542}
543
544pub unsafe fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int) {
545 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
546 luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
547 if lua_getfield(L, -1, modname) == LUA_TNIL {
548 lua_pop(L, 1);
549 lua_pushcfunction(L, openf);
550 lua_pushstring(L, modname);
551 lua_call(L, 1, 1);
552 lua_pushvalue(L, -1);
553 lua_setfield(L, -3, modname);
554 }
555 if glb != 0 {
556 lua_pushvalue(L, -1);
557 lua_setglobal(L, modname);
558 } else {
559 lua_pushnil(L);
560 lua_setglobal(L, modname);
561 }
562 lua_replace(L, -2);
563}