Enable Lua::inspect_stack
for Luau
This commit is contained in:
parent
cab92f4ea2
commit
3e5f8e7bb8
|
@ -7,8 +7,8 @@ use std::mem;
|
|||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::*;
|
||||
use super::lauxlib::*;
|
||||
use super::lua::*;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
|
|
|
@ -397,6 +397,15 @@ const LUA_IDSIZE: usize = 256;
|
|||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
pub type lua_Coverage = unsafe extern "C" fn(
|
||||
context: *mut c_void,
|
||||
function: *const c_char,
|
||||
linedefined: c_int,
|
||||
depth: c_int,
|
||||
hits: *const c_int,
|
||||
size: usize,
|
||||
);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getinfo(
|
||||
L: *mut lua_State,
|
||||
|
@ -413,7 +422,14 @@ extern "C" {
|
|||
pub fn lua_singlestep(L: *mut lua_State, enabled: c_int);
|
||||
pub fn lua_breakpoint(L: *mut lua_State, funcindex: c_int, line: c_int, enabled: c_int);
|
||||
|
||||
// TODO: lua_Coverage, lua_getcoverage
|
||||
pub fn lua_getcoverage(
|
||||
L: *mut lua_State,
|
||||
funcindex: c_int,
|
||||
context: *mut c_void,
|
||||
callback: lua_Coverage,
|
||||
);
|
||||
|
||||
pub fn lua_debugtrace(L: *mut lua_State) -> *const c_char;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -435,4 +451,31 @@ pub struct lua_Debug {
|
|||
// These are shared between all coroutines.
|
||||
//
|
||||
|
||||
// TODO: lua_Callbacks, lua_callbacks
|
||||
#[repr(C)]
|
||||
pub struct lua_Callbacks {
|
||||
/// arbitrary userdata pointer that is never overwritten by Luau
|
||||
pub userdata: *mut c_void,
|
||||
|
||||
/// gets called at safepoints (loop back edges, call/ret, gc) if set
|
||||
pub interrupt: Option<unsafe extern "C" fn(L: *mut lua_State, gc: c_int)>,
|
||||
/// gets called when an unprotected error is raised (if longjmp is used)
|
||||
pub panic: Option<unsafe extern "C" fn(L: *mut lua_State, errcode: c_int)>,
|
||||
|
||||
/// gets called when L is created (LP == parent) or destroyed (LP == NULL)
|
||||
pub userthread: Option<unsafe extern "C" fn(LP: *mut lua_State, L: *mut lua_State)>,
|
||||
/// gets called when a string is created; returned atom can be retrieved via tostringatom
|
||||
pub useratom: Option<unsafe extern "C" fn(s: *const c_char, l: usize) -> i16>,
|
||||
|
||||
/// gets called when BREAK instruction is encountered
|
||||
pub debugbreak: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called after each instruction in single step mode
|
||||
pub debugstep: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called when thread execution is interrupted by break in another thread
|
||||
pub debuginterrupt: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called when protected call results in an error
|
||||
pub debugprotectederror: Option<unsafe extern "C" fn(L: *mut lua_State)>,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_callbacks(L: *mut lua_State) -> *mut lua_Callbacks;
|
||||
}
|
||||
|
|
79
src/hook.rs
79
src/hook.rs
|
@ -1,5 +1,6 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::ffi::CStr;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
use std::os::raw::{c_char, c_int};
|
||||
|
||||
|
@ -18,9 +19,12 @@ use crate::lua::Lua;
|
|||
pub struct Debug<'lua> {
|
||||
lua: &'lua Lua,
|
||||
ar: ActivationRecord,
|
||||
#[cfg(feature = "luau")]
|
||||
level: c_int,
|
||||
}
|
||||
|
||||
impl<'lua> Debug<'lua> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) fn new(lua: &'lua Lua, ar: *mut lua_Debug) -> Self {
|
||||
Debug {
|
||||
lua,
|
||||
|
@ -28,10 +32,12 @@ impl<'lua> Debug<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_owned(lua: &'lua Lua, ar: lua_Debug) -> Self {
|
||||
pub(crate) fn new_owned(lua: &'lua Lua, _level: c_int, ar: lua_Debug) -> Self {
|
||||
Debug {
|
||||
lua,
|
||||
ar: ActivationRecord::Owned(UnsafeCell::new(ar)),
|
||||
#[cfg(feature = "luau")]
|
||||
level: _level,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +47,7 @@ impl<'lua> Debug<'lua> {
|
|||
/// from a function that did a tail call.
|
||||
///
|
||||
/// [Lua 5.1]: https://www.lua.org/manual/5.1/manual.html#pdf-LUA_HOOKTAILRET
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub fn event(&self) -> DebugEvent {
|
||||
unsafe {
|
||||
match (*self.ar.get()).event {
|
||||
|
@ -57,13 +64,23 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `n` what mask.
|
||||
pub fn names(&self) -> DebugNames<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("n"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `n`"
|
||||
);
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("n"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `n`"
|
||||
);
|
||||
|
||||
DebugNames {
|
||||
name: ptr_to_str((*self.ar.get()).name),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
name_what: ptr_to_str((*self.ar.get()).namewhat),
|
||||
#[cfg(feature = "luau")]
|
||||
name_what: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,14 +88,22 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `S` what mask.
|
||||
pub fn source(&self) -> DebugSource<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("S"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `S`"
|
||||
);
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("s"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `s`"
|
||||
);
|
||||
|
||||
DebugSource {
|
||||
source: ptr_to_str((*self.ar.get()).source),
|
||||
short_src: ptr_to_str((*self.ar.get()).short_src.as_ptr()),
|
||||
line_defined: (*self.ar.get()).linedefined as i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
last_line_defined: (*self.ar.get()).lastlinedefined as i32,
|
||||
what: ptr_to_str((*self.ar.get()).what),
|
||||
}
|
||||
|
@ -88,16 +113,24 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `l` what mask. Returns the current line.
|
||||
pub fn curr_line(&self) -> i32 {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("l"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `l`"
|
||||
);
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("l"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `l`"
|
||||
);
|
||||
|
||||
(*self.ar.get()).currentline as i32
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the `t` what mask. Returns true if the hook is in a function tail call, false
|
||||
/// otherwise.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub fn is_tail_call(&self) -> bool {
|
||||
unsafe {
|
||||
mlua_assert!(
|
||||
|
@ -111,22 +144,38 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `u` what mask.
|
||||
pub fn stack(&self) -> DebugStack {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("u"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `u`"
|
||||
);
|
||||
DebugStack {
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("a"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `a`"
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let stack = DebugStack {
|
||||
num_ups: (*self.ar.get()).nups as i32,
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
num_params: (*self.ar.get()).nparams as i32,
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
is_vararg: (*self.ar.get()).isvararg != 0,
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "luau")]
|
||||
let stack = DebugStack {
|
||||
num_ups: (*self.ar.get()).nupvals as i32,
|
||||
num_params: (*self.ar.get()).nparams as i32,
|
||||
is_vararg: (*self.ar.get()).isvararg != 0,
|
||||
};
|
||||
stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ActivationRecord {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
Borrowed(*mut lua_Debug),
|
||||
Owned(UnsafeCell<lua_Debug>),
|
||||
}
|
||||
|
@ -135,6 +184,7 @@ impl ActivationRecord {
|
|||
#[inline]
|
||||
fn get(&self) -> *mut lua_Debug {
|
||||
match self {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
ActivationRecord::Borrowed(x) => *x,
|
||||
ActivationRecord::Owned(x) => x.get(),
|
||||
}
|
||||
|
@ -163,6 +213,7 @@ pub struct DebugSource<'a> {
|
|||
pub source: Option<&'a [u8]>,
|
||||
pub short_src: Option<&'a [u8]>,
|
||||
pub line_defined: i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub last_line_defined: i32,
|
||||
pub what: Option<&'a [u8]>,
|
||||
}
|
||||
|
@ -170,15 +221,26 @@ pub struct DebugSource<'a> {
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct DebugStack {
|
||||
pub num_ups: i32,
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
pub num_params: i32,
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
pub is_vararg: bool,
|
||||
}
|
||||
|
||||
/// Determines when a hook function will be called by Lua.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct HookTriggers {
|
||||
/// Before a function call.
|
||||
|
@ -196,6 +258,7 @@ pub struct HookTriggers {
|
|||
pub every_nth_instruction: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl HookTriggers {
|
||||
/// Returns a new instance of `HookTriggers` with [`on_calls`] trigger set.
|
||||
///
|
||||
|
@ -262,6 +325,7 @@ impl HookTriggers {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOr for HookTriggers {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -276,6 +340,7 @@ impl BitOr for HookTriggers {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOrAssign for HookTriggers {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = *self | rhs;
|
||||
|
|
|
@ -85,7 +85,6 @@ mod conversion;
|
|||
mod error;
|
||||
mod ffi;
|
||||
mod function;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mod hook;
|
||||
mod lua;
|
||||
mod multi;
|
||||
|
@ -105,8 +104,7 @@ pub use crate::{ffi::lua_CFunction, ffi::lua_State};
|
|||
|
||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||
pub use crate::function::Function;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack, HookTriggers};
|
||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
|
||||
pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions};
|
||||
pub use crate::multi::Variadic;
|
||||
pub use crate::scope::Scope;
|
||||
|
@ -120,6 +118,9 @@ pub use crate::userdata::{
|
|||
};
|
||||
pub use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub use crate::hook::HookTriggers;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub use crate::thread::AsyncThread;
|
||||
|
||||
|
|
24
src/lua.rs
24
src/lua.rs
|
@ -14,16 +14,15 @@ use rustc_hash::FxHashMap;
|
|||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::hook::{Debug, HookTriggers};
|
||||
use crate::hook::Debug;
|
||||
use crate::scope::Scope;
|
||||
use crate::stdlib::StdLib;
|
||||
use crate::string::String;
|
||||
use crate::table::Table;
|
||||
use crate::thread::Thread;
|
||||
use crate::types::{
|
||||
Callback, CallbackUpvalue, DestructedUserdataMT, /*HookCallback,*/ Integer, LightUserData,
|
||||
LuaRef, MaybeSend, Number, RegistryKey,
|
||||
Callback, CallbackUpvalue, DestructedUserdataMT, Integer, LightUserData, LuaRef, MaybeSend,
|
||||
Number, RegistryKey,
|
||||
};
|
||||
use crate::userdata::{
|
||||
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
||||
|
@ -36,9 +35,6 @@ use crate::util::{
|
|||
};
|
||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::types::HookCallback;
|
||||
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
use crate::util::push_userdata;
|
||||
#[cfg(feature = "lua54")]
|
||||
|
@ -47,6 +43,9 @@ use {
|
|||
std::ffi::CStr,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::{hook::HookTriggers, types::HookCallback};
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -933,14 +932,19 @@ impl Lua {
|
|||
/// function that has called level `n` (except for tail calls, which do not count in the stack).
|
||||
///
|
||||
/// [`Debug`]: crate::hook::Debug
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
|
||||
unsafe {
|
||||
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||
if ffi::lua_getstack(self.state, level as c_int, &mut ar) == 0 {
|
||||
let level = level as c_int;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if ffi::lua_getstack(self.state, level, &mut ar) == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(Debug::new_owned(self, ar))
|
||||
#[cfg(feature = "luau")]
|
||||
if ffi::lua_getinfo(self.state, level, cstr!(""), &mut ar) == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(Debug::new_owned(self, level, ar))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ use crate::userdata::{
|
|||
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
||||
};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, push_userdata,
|
||||
rawset_field, take_userdata, StackGuard,
|
||||
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, rawset_field,
|
||||
take_userdata, StackGuard,
|
||||
};
|
||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
||||
|
||||
|
@ -352,7 +352,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
})?;
|
||||
#[cfg(feature = "luau")]
|
||||
let ud_ptr = {
|
||||
push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
|
||||
crate::util::push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
|
||||
lua.state,
|
||||
UserDataCell::new(data.clone()),
|
||||
)?;
|
||||
|
|
|
@ -1169,7 +1169,6 @@ fn test_load_from_function() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[test]
|
||||
fn test_inspect_stack() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
|
Loading…
Reference in a new issue