diff options
author | Alex Orlenko <zxteam@protonmail.com> | 2022-02-25 23:51:51 +0000 |
---|---|---|
committer | Alex Orlenko <zxteam@protonmail.com> | 2022-03-21 01:08:47 +0000 |
commit | 3e5f8e7bb8bb2822629593ecbd316f0fda7b4de8 (patch) | |
tree | a3c671bd43c804fdf5369cd1fb25bbc4139876c6 | |
parent | cab92f4ea2eb93d86a723384d6c08e0f16d16ad9 (diff) | |
download | mlua-3e5f8e7bb8bb2822629593ecbd316f0fda7b4de8.zip |
Enable `Lua::inspect_stack` for Luau
-rw-r--r-- | src/ffi/lua51/compat.rs | 2 | ||||
-rw-r--r-- | src/ffi/luau/lua.rs | 47 | ||||
-rw-r--r-- | src/hook.rs | 79 | ||||
-rw-r--r-- | src/lib.rs | 7 | ||||
-rw-r--r-- | src/lua.rs | 24 | ||||
-rw-r--r-- | src/scope.rs | 6 | ||||
-rw-r--r-- | tests/tests.rs | 1 |
7 files changed, 139 insertions, 27 deletions
diff --git a/src/ffi/lua51/compat.rs b/src/ffi/lua51/compat.rs index 99a575b..ca0379b 100644 --- a/src/ffi/lua51/compat.rs +++ b/src/ffi/lua51/compat.rs @@ -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) { diff --git a/src/ffi/luau/lua.rs b/src/ffi/luau/lua.rs index 8638ee5..9963f64 100644 --- a/src/ffi/luau/lua.rs +++ b/src/ffi/luau/lua.rs @@ -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; +} diff --git a/src/hook.rs b/src/hook.rs index bfb4873..88bfd1a 100644 --- a/src/hook.rs +++ b/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; @@ -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; + } + #[cfg(feature = "luau")] + if ffi::lua_getinfo(self.state, level, cstr!(""), &mut ar) == 0 { return None; } - Some(Debug::new_owned(self, ar)) + Some(Debug::new_owned(self, level, ar)) } } diff --git a/src/scope.rs b/src/scope.rs index ffaa400..2a3c710 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -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()), )?; diff --git a/tests/tests.rs b/tests/tests.rs index 2d99911..2f6baf8 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -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(); |