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