Register with the Debugger ========================== {{#include ../../links.md}} Hooking up a debugging interface is as simple as providing closures to the [`Engine`]'s built-in debugger via `Engine::register_debugger`. ```rust use rhai::debugger::{ASTNode, DebuggerCommand}; let mut engine = Engine::new(); engine.register_debugger( // Provide a callback to initialize the debugger state |engine, mut debugger| { debugger.set_state(...); debugger }, // Provide a callback for each debugging step |context, event, node, source, pos| { ... DebuggerCommand::StepOver } ); ``` ~~~admonish tip.small "Tip: Accessing the `Debugger`" The type `debugger::Debugger` allows for manipulating [break-points], among others. The [`Engine`]'s debugger instance can be accessed via `context.global_runtime_state().debugger()` (immutable) or `context.global_runtime_state_mut().debugger_mut()` (mutable). ~~~ Callback Functions Signature ---------------------------- There are two callback functions to register for the debugger. The first is simply a function to initialize the state of the debugger with the following signature. > ```rust > Fn(&Engine, debugger::Debugger) -> debugger::Debugger > ``` The second callback is a function which will be called by the debugger during each step, with the following signature. > ```rust > Fn(context: EvalContext, event: debugger::DebuggerEvent, node: ASTNode, source: &str, pos: Position) -> Result> > ``` where: | Parameter | Type | Description | | --------- | :-------------: | ---------------------------------------------------------------------------------------------------------------------------- | | `context` | [`EvalContext`] | the current _evaluation context_ | | `event` | `DebuggerEvent` | an `enum` indicating the event that triggered the debugger | | `node` | `ASTNode` | an `enum` with two variants: `Expr` or `Stmt`, corresponding to the current expression node or statement node in the [`AST`] | | `source` | `&str` | the source of the current [`AST`], or empty if none | | `pos` | `Position` | position of the current node, same as `node.position()` | and [`EvalContext`] is a type that encapsulates the current _evaluation context_. ### Event The `event` parameter of the second closure passed to `Engine::register_debugger` contains a `debugger::DebuggerEvent` which is an `enum` with the following variants. | `DebuggerEvent` variant | Description | | -------------------------------- | ----------------------------------------------------------------------------------------------- | | `Start` | the debugger is triggered at the beginning of evaluation | | `Step` | the debugger is triggered at the next step of evaluation | | `BreakPoint(`_n_`)` | the debugger is triggered by the _n_-th [break-point] | | `FunctionExitWithValue(`_r_`)` | the debugger is triggered by a function call returning with value _r_ which is `&Dynamic` | | `FunctionExitWithError(`_err_`)` | the debugger is triggered by a function call exiting with error _err_ which is `&EvalAltResult` | | `End` | the debugger is triggered at the end of evaluation | ### Return value ```admonish tip.side.wide "Tip: Initialization" When a script starts evaluation, the debugger always stops at the very _first_ [`AST`] node with the `event` parameter set to `DebuggerStatus::Start`. This allows initialization to be done (e.g. setting up [break-points]). ``` The second closure passed to `Engine::register_debugger` will be called when stepping into or over expressions and statements, or when [break-points] are hit. The return type of the closure is `Result>`. If an error is returned, the script evaluation at that particular instance returns with that particular error. It is thus possible to _abort_ the script evaluation by returning an error that is not _catchable_, such as `EvalAltResult::ErrorTerminated`. If no error is returned, then the return `debugger::DebuggerCommand` variant determines the continued behavior of the debugger. | `DebuggerCommand` variant | Behavior | `gdb` equivalent | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | :--------------: | | `Continue` | continue with normal script evaluation | `continue` | | `StepInto` | run to the next expression or statement, diving into functions | `step` | | `StepOver` | run to the next expression or statement, skipping over functions | | | `Next` | run to the next statement, skipping over functions | `next` | | `FunctionExit` | run to the end of the current function call; debugger is triggered _before_ the function call returns and the [`Scope`] cleared | `finish` |