summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2022-02-25 23:51:51 +0000
committerAlex Orlenko <zxteam@protonmail.com>2022-03-21 01:08:47 +0000
commit3e5f8e7bb8bb2822629593ecbd316f0fda7b4de8 (patch)
treea3c671bd43c804fdf5369cd1fb25bbc4139876c6
parentcab92f4ea2eb93d86a723384d6c08e0f16d16ad9 (diff)
downloadmlua-3e5f8e7bb8bb2822629593ecbd316f0fda7b4de8.zip
Enable `Lua::inspect_stack` for Luau
-rw-r--r--src/ffi/lua51/compat.rs2
-rw-r--r--src/ffi/luau/lua.rs47
-rw-r--r--src/hook.rs79
-rw-r--r--src/lib.rs7
-rw-r--r--src/lua.rs24
-rw-r--r--src/scope.rs6
-rw-r--r--tests/tests.rs1
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;
diff --git a/src/lib.rs b/src/lib.rs
index ee851d4..57e45b0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
diff --git a/src/lua.rs b/src/lua.rs
index 90ca6d3..8a4475c 100644
--- a/src/lua.rs
+++ b/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;
+ }
+ #[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();