Skip to main content

luaur_vm/functions/
lua_l_traceback.rs

1use core::ffi::{c_char, c_int, CStr};
2use std::ffi::CString;
3
4use crate::functions::lua_getinfo::lua_getinfo;
5use crate::functions::lua_l_addchar::lua_l_addchar;
6use crate::functions::lua_l_addlstring::lua_l_addlstring;
7use crate::functions::lua_l_addstring::lua_l_addstring;
8use crate::functions::lua_l_buffinit::lua_l_buffinit;
9use crate::functions::lua_l_pushresult::lua_l_pushresult;
10use crate::records::lua_debug::LuaDebug;
11use crate::records::lua_l_strbuf::LuaLStrbuf;
12use crate::type_aliases::lua_state::lua_State;
13
14/// Build a traceback string from `L1`, optionally prepending `msg`, and push
15/// the result onto `L`. Faithful 1:1 port of `luaL_traceback` from
16/// `luau/VM/src/laux.cpp:381-425`.
17#[allow(non_snake_case)]
18pub unsafe fn lua_l_traceback(
19    L: *mut lua_State,
20    L1: *mut lua_State,
21    msg: Option<&str>,
22    level: c_int,
23) {
24    debug_assert!(level >= 0);
25
26    // Helper: manually convert an int to decimal and append to the buffer.
27    unsafe fn addsignednum(buf: *mut LuaLStrbuf, n: i32) {
28        let mut line = [0 as c_char; 32];
29        let lineend = line.len();
30        let mut lineptr = lineend;
31        let mut r = n as u32;
32        while r > 0 {
33            lineptr -= 1;
34            line[lineptr] = (b'0' + (r % 10) as u8) as c_char;
35            r /= 10;
36        }
37
38        lua_l_addlstring(buf, line.as_ptr().add(lineptr), lineend - lineptr);
39    }
40
41    let mut buf = LuaLStrbuf {
42        p: core::ptr::null_mut(),
43        end: core::ptr::null_mut(),
44        L: core::ptr::null_mut(),
45        storage: core::ptr::null_mut(),
46        buffer: [0; 512],
47    };
48    lua_l_buffinit(L, &mut buf);
49
50    if let Some(msg_str) = msg {
51        let c_msg = CString::new(msg_str).unwrap_or_default();
52        lua_l_addstring(&mut buf, c_msg.as_ptr());
53        lua_l_addstring(&mut buf, c"\n".as_ptr());
54    }
55
56    let mut ar: LuaDebug = core::mem::zeroed();
57    let mut i: c_int = level;
58
59    while lua_getinfo(L1, i, c"sln".as_ptr(), &mut ar) != 0 {
60        if CStr::from_ptr(ar.what).to_bytes() == b"C" {
61            i += 1;
62            continue;
63        }
64
65        if !ar.source.is_null() {
66            lua_l_addstring(&mut buf, ar.short_src);
67        }
68
69        if ar.currentline > 0 {
70            lua_l_addchar(&mut buf, b':' as c_char);
71            addsignednum(&mut buf, ar.currentline);
72        }
73
74        if !ar.name.is_null() {
75            lua_l_addstring(&mut buf, c" function ".as_ptr());
76            lua_l_addstring(&mut buf, ar.name);
77        }
78
79        lua_l_addchar(&mut buf, b'\n' as c_char);
80
81        i += 1;
82    }
83
84    lua_l_pushresult(&mut buf);
85}