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