nk
1.0.0
C++ Numerical Computing Runtime
Toggle main menu visibility
Loading...
Searching...
No Matches
debugger.hpp
1
// include/debugger.hpp
2
//
3
// Debugger infrastructure for M interpreter.
4
//
5
// Design principles:
6
// - Zero overhead when no observer is attached
7
// - Unified interface for both VM and TreeWalker backends
8
// - Read-only DebugContext (no mutation through debug API)
9
// - No coupling to UI — observer is abstract
10
// - No heap allocation for debug frames
11
// - Shared step logic — no duplication between backends
12
//
13
#pragma once
14
15
#include <nk/value/value.hpp>
16
#include <cstdint>
17
#include <string>
18
#include <unordered_map>
19
#include <vector>
20
21
namespace
nk {
22
23
class
Environment
;
24
struct
BytecodeChunk
;
25
26
// ============================================================
27
// DebugAction — returned by observer to control execution
28
// ============================================================
29
enum class
DebugAction : uint8_t {
30
Continue,
// run until next breakpoint
31
StepOver,
// next line in current scope (skip function calls)
32
StepInto,
// step into function call (break on very next line)
33
StepOut,
// run until current function returns
34
Stop
// abort execution
35
};
36
37
// ============================================================
38
// StackFrame — one entry in the call stack
39
//
40
// All data inline — no heap allocation, no void*.
41
// VM sets chunk + registers, TW sets env. Unused fields are null.
42
// ============================================================
43
struct
StackFrame
44
{
45
std::string functionName;
// "<script>" for top-level
46
uint16_t line = 0;
47
uint16_t col = 0;
48
49
// VM backend: variable access via registers
50
const
BytecodeChunk
*chunk =
nullptr
;
51
const
Value
*registers =
nullptr
;
52
53
// TW backend: variable access via Environment
54
Environment
*env =
nullptr
;
55
56
// Variable inspection (works for both backends)
57
struct
VarEntry
58
{
59
std::string name;
60
const
Value
*value;
61
};
62
std::vector<VarEntry> variables()
const
;
63
};
64
65
// ============================================================
66
// DebugContext — read-only view of execution state
67
//
68
// Passed to observer callbacks. callStack back() = current frame.
69
// ============================================================
70
struct
DebugContext
71
{
72
uint16_t line = 0;
73
uint16_t col = 0;
74
const
std::string *functionName =
nullptr
;
75
76
// Source code text for display. Available in VM backend (from BytecodeChunk).
77
// Null in TreeWalker backend (TW operates on AST, not compiled chunks).
78
const
std::string *sourceCode =
nullptr
;
79
80
// Call stack: front() = top-level, back() = current frame
81
const
std::vector<StackFrame> *callStack =
nullptr
;
82
83
const
StackFrame
*currentFrame()
const
84
{
85
return
(callStack && !callStack->empty()) ? &callStack->back() :
nullptr
;
86
}
87
88
const
Value
*getVariable(
const
std::string &name)
const
;
89
std::vector<std::string> variableNames()
const
;
90
};
91
92
// ============================================================
93
// DebugObserver — abstract interface implemented by UI/CLI
94
// ============================================================
95
class
DebugObserver
96
{
97
public
:
98
virtual
~DebugObserver
() =
default
;
99
virtual
DebugAction onLine(
const
DebugContext
&ctx) = 0;
100
virtual
DebugAction onBreakpoint(
const
DebugContext
&ctx) = 0;
101
virtual
void
onError(
const
DebugContext
&ctx,
const
std::string &msg) = 0;
102
virtual
void
onFunctionEntry(
const
DebugContext
&ctx) = 0;
103
virtual
void
onFunctionExit(
const
DebugContext
&ctx) = 0;
104
};
105
106
// ============================================================
107
// BreakpointManager — tracks line breakpoints
108
// ============================================================
109
class
BreakpointManager
110
{
111
public
:
112
struct
Breakpoint
113
{
114
int
id
= 0;
115
uint16_t line = 0;
116
bool
enabled =
true
;
117
std::string condition;
// empty = unconditional; else a boolean expr
118
};
119
120
int
addBreakpoint(uint16_t line);
121
int
addBreakpoint(uint16_t line,
const
std::string &condition);
122
void
removeBreakpoint(
int
id
);
123
void
enableBreakpoint(
int
id
,
bool
enabled);
124
void
clearAll();
125
bool
shouldBreak(uint16_t line)
const
;
126
// Condition text of the enabled breakpoint at `line` (empty if none or
127
// unconditional). The manager only stores it; the debugger evaluates it.
128
std::string conditionForLine(uint16_t line)
const
;
129
const
std::vector<Breakpoint> &breakpoints()
const
{
return
breakpoints_; }
130
131
private
:
132
std::vector<Breakpoint> breakpoints_;
133
int
nextId_ = 1;
134
mutable
std::unordered_map<uint16_t, size_t> lineIndex_;
135
mutable
bool
indexDirty_ =
true
;
136
void
rebuildIndex()
const
;
137
};
138
139
// ============================================================
140
// DebugController — shared step/breakpoint logic
141
//
142
// Both VM and TW call checkLine() on line change.
143
// Owns the call stack and step state.
144
// No backend-specific code.
145
//
146
// Lifetime: observer and bpm must outlive the controller.
147
// Do not call Engine::setDebugObserver() during execution.
148
// ============================================================
149
class
DebugController
150
{
151
public
:
152
explicit
DebugController(
DebugObserver
*observer,
BreakpointManager
*bpm)
153
: observer_(observer)
154
, bpm_(bpm)
155
{}
156
157
// Reset for new execution.
158
// Default StepInto: observer's onLine() fires on the first source line,
159
// giving it a chance to choose the execution mode (Continue, StepOver, etc).
160
// Pass Continue to skip the initial stop (breakpoints still work).
161
void
reset(DebugAction initialAction = DebugAction::StepInto);
162
163
// Called by backend on source line change.
164
// Returns false if Stop requested.
165
bool
checkLine(uint16_t line, uint16_t col,
int
callDepth);
166
167
// Call stack management
168
void
pushFrame(
StackFrame
frame);
169
void
popFrame();
170
171
// RAII guard: pushes frame on construction, pops on destruction (even on exception).
172
// Movable (for std::optional), not copyable.
173
class
FrameGuard
174
{
175
public
:
176
FrameGuard(DebugController &ctl,
StackFrame
frame)
177
: ctl_(&ctl)
178
{
179
ctl_->pushFrame(std::move(frame));
180
}
181
~FrameGuard()
182
{
183
if
(ctl_)
184
ctl_->popFrame();
185
}
186
FrameGuard(FrameGuard &&o) noexcept
187
: ctl_(o.ctl_)
188
{
189
o.ctl_ =
nullptr
;
190
}
191
FrameGuard &operator=(FrameGuard &&) =
delete
;
192
FrameGuard(
const
FrameGuard &) =
delete
;
193
FrameGuard &operator=(
const
FrameGuard &) =
delete
;
194
195
private
:
196
DebugController *ctl_;
197
};
198
199
std::vector<StackFrame> &callStack() {
return
callStack_; }
200
const
std::vector<StackFrame> &callStack()
const
{
return
callStack_; }
201
StackFrame *currentFrame() {
return
callStack_.empty() ? nullptr : &callStack_.back(); }
202
203
DebugContext makeContext(uint16_t line, uint16_t col)
const
;
204
DebugContext makeContext()
const
;
205
206
// Set action for resume after pause (called before re-entering dispatch loop)
207
void
setResumeAction(DebugAction action,
int
callDepth);
208
209
// Restore lastLine_ (used after debug eval to avoid re-triggering on the same line)
210
void
setLastLine(uint16_t line) { lastLine_ = line; }
211
212
private
:
213
DebugObserver *observer_;
214
BreakpointManager *bpm_;
215
std::vector<StackFrame> callStack_;
216
DebugAction stepAction_ = DebugAction::Continue;
217
int
stepDepth_ = 0;
218
uint16_t lastLine_ = 0;
219
220
void
applyAction(DebugAction action,
int
callDepth);
221
};
222
223
// ============================================================
224
// DebugStopException
225
// ============================================================
226
class
DebugStopException :
public
std::runtime_error
227
{
228
public
:
229
DebugStopException()
230
: std::runtime_error(
"Execution stopped by debugger"
)
231
{}
232
};
233
234
}
// namespace nk
nk::BreakpointManager
Definition
debugger.hpp:110
nk::DebugObserver
Definition
debugger.hpp:96
nk::Environment
Definition
environment.hpp:26
nk::Value
Core MATLAB-compatible multidimensional array and scalar value type.
Definition
value.hpp:61
nk::BreakpointManager::Breakpoint
Definition
debugger.hpp:113
nk::BytecodeChunk
Definition
bytecode.hpp:371
nk::DebugContext
Definition
debugger.hpp:71
nk::StackFrame::VarEntry
Definition
debugger.hpp:58
nk::StackFrame
Definition
debugger.hpp:44
src
core
include
nk
core
debugger.hpp
Generated by
1.17.0