Skip to main content

spo_rhai/packages/
debugging.rs

1#![cfg(feature = "debugging")]
2
3use crate::def_package;
4use crate::module::ModuleFlags;
5use crate::plugin::*;
6#[cfg(feature = "no_std")]
7use std::prelude::v1::*;
8
9#[cfg(not(feature = "no_function"))]
10#[cfg(not(feature = "no_index"))]
11use crate::{Array, Dynamic, NativeCallContext};
12
13#[cfg(not(feature = "no_function"))]
14#[cfg(not(feature = "no_index"))]
15#[cfg(not(feature = "no_object"))]
16use crate::Map;
17
18def_package! {
19    /// Package of basic debugging utilities.
20    pub DebuggingPackage(lib) {
21        lib.flags |= ModuleFlags::STANDARD_LIB;
22
23        combine_with_exported_module!(lib, "debugging", debugging_functions);
24    }
25}
26
27#[export_module]
28mod debugging_functions {
29    /// Get an array of object maps containing the function calls stack.
30    ///
31    /// If there is no debugging interface registered, an empty array is returned.
32    ///
33    /// An array of strings is returned under `no_object`.
34    #[cfg(not(feature = "no_function"))]
35    #[cfg(not(feature = "no_index"))]
36    pub fn back_trace(ctx: NativeCallContext) -> Array {
37        use crate::debugger::CallStackFrame;
38
39        ctx.global_runtime_state()
40            .debugger
41            .as_ref()
42            .map_or_else(Array::new, |debugger| {
43                debugger
44                    .call_stack()
45                    .iter()
46                    .rev()
47                    .filter(|CallStackFrame { fn_name, args, .. }| {
48                        fn_name != "back_trace" || !args.is_empty()
49                    })
50                    .map(
51                        |frame @ CallStackFrame {
52                             fn_name: _fn_name,
53                             args: _args,
54                             source: _source,
55                             pos: _pos,
56                         }| {
57                            let display = frame.to_string();
58
59                            #[cfg(not(feature = "no_object"))]
60                            {
61                                use crate::INT;
62                                use std::iter::FromIterator;
63
64                                let mut map = Map::new();
65                                map.insert("display".into(), display.into());
66                                map.insert("fn_name".into(), _fn_name.into());
67                                if !_args.is_empty() {
68                                    map.insert(
69                                        "args".into(),
70                                        Dynamic::from_iter(_args.iter().cloned()),
71                                    );
72                                }
73                                if let Some(source) = _source {
74                                    map.insert("source".into(), source.into());
75                                }
76                                if !_pos.is_none() {
77                                    map.insert("line".into(), (_pos.line().unwrap() as INT).into());
78                                    map.insert(
79                                        "position".into(),
80                                        (_pos.position().unwrap_or(0) as INT).into(),
81                                    );
82                                }
83                                Dynamic::from_map(map)
84                            }
85                            #[cfg(feature = "no_object")]
86                            display.into()
87                        },
88                    )
89                    .collect()
90            })
91    }
92}