Add DebuggingPackage.

This commit is contained in:
Stephen Chung 2022-01-25 14:32:42 +08:00
parent 0e5f62574d
commit aee35e5f20
5 changed files with 121 additions and 0 deletions

View File

@ -9,6 +9,7 @@ New features
* A debugging interface is added.
* A new bin tool, `rhai-dbg` (aka _The Rhai Debugger_), is added to showcase the debugging interface.
* A new package, `DebuggingPackage`, is added which contains the `stack_trace` function to get the current call stack anywhere in a script.
Version 1.4.2

80
src/packages/debugging.rs Normal file
View File

@ -0,0 +1,80 @@
#![cfg(feature = "debugging")]
use crate::def_package;
use crate::plugin::*;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[cfg(not(feature = "no_function"))]
use crate::{Dynamic, NativeCallContext, INT};
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
use crate::Array;
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_object"))]
use crate::Map;
def_package! {
/// Package of basic debugging utilities.
crate::DebuggingPackage => |lib| {
lib.standard = true;
combine_with_exported_module!(lib, "debugging", debugging_functions);
}
}
#[export_module]
mod debugging_functions {
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
pub fn stack_trace(ctx: NativeCallContext) -> Array {
if let Some(global) = ctx.global_runtime_state() {
global
.debugger
.call_stack()
.iter()
.rev()
.map(
|frame @ crate::debugger::CallStackFrame {
fn_name,
args,
source,
pos,
}| {
let call = frame.to_string();
#[cfg(not(feature = "no_object"))]
{
let mut map = Map::new();
map.insert("call".into(), call.into());
map.insert("fn_name".into(), fn_name.into());
if !args.is_empty() {
map.insert(
"args".into(),
Dynamic::from_array(args.clone().to_vec()),
);
}
if !source.is_empty() {
map.insert("source".into(), source.into());
}
if !pos.is_none() {
map.insert("line".into(), (pos.line().unwrap() as INT).into());
map.insert(
"pos".into(),
(pos.position().unwrap_or(0) as INT).into(),
);
}
Dynamic::from_map(map)
}
#[cfg(feature = "no_object")]
call.into()
},
)
.collect()
} else {
Array::new()
}
}
}

View File

@ -6,6 +6,7 @@ pub(crate) mod arithmetic;
pub(crate) mod array_basic;
mod bit_field;
pub(crate) mod blob_basic;
mod debugging;
mod fn_basic;
mod iter_basic;
mod lang_core;
@ -24,6 +25,8 @@ pub use array_basic::BasicArrayPackage;
pub use bit_field::BitFieldPackage;
#[cfg(not(feature = "no_index"))]
pub use blob_basic::BasicBlobPackage;
#[cfg(feature = "debugging")]
pub use debugging::DebuggingPackage;
pub use fn_basic::BasicFnPackage;
pub use iter_basic::BasicIteratorPackage;
pub use lang_core::LanguageCorePackage;

View File

@ -13,6 +13,7 @@ def_package! {
/// * [`BasicStringPackage`][super::BasicStringPackage]
/// * [`BasicIteratorPackage`][super::BasicIteratorPackage]
/// * [`BasicFnPackage`][super::BasicFnPackage]
/// * [`DebuggingPackage`][super::DebuggingPackage]
crate::CorePackage => |lib| {
lib.standard = true;
@ -21,5 +22,7 @@ def_package! {
super::BasicStringPackage::init(lib);
super::BasicIteratorPackage::init(lib);
super::BasicFnPackage::init(lib);
#[cfg(feature = "debugging")]
super::DebuggingPackage::init(lib);
}
}

34
tests/debugging.rs Normal file
View File

@ -0,0 +1,34 @@
#![cfg(feature = "debugging")]
use rhai::{Engine, EvalAltResult, INT};
#[cfg(not(feature = "no_index"))]
use rhai::Array;
#[test]
fn test_debugging() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
{
let r = engine.eval::<Array>(
"
fn foo(x) {
if x >= 5 {
stack_trace()
} else {
foo(x+1)
}
}
foo(0)
",
)?;
assert_eq!(r.len(), 6);
assert_eq!(engine.eval::<INT>("len(stack_trace())")?, 0);
}
Ok(())
}