shape_vm/executor/
debugger_integration.rs1use crate::debugger::VMDebugger;
12use shape_value::{ExternalValue, ValueWord};
13
14pub trait DebuggerIntegration {
16 fn trace_state(&self);
18
19 fn debug_break(&self);
21
22 fn instruction_pointer(&self) -> usize;
24
25 fn stack_size(&self) -> usize;
27
28 fn stack_top(&self) -> Option<ExternalValue>;
30
31 fn stack_values_vec(&self) -> Vec<ExternalValue>;
33
34 fn call_stack_depth(&self) -> usize;
36
37 fn call_frames(&self) -> &[super::CallFrame];
39
40 fn local_values_vec(&self) -> Vec<ExternalValue>;
42
43 fn module_binding_values(&self) -> Vec<ValueWord>;
45
46 fn set_module_binding(&mut self, index: usize, value: ValueWord);
48
49 fn set_trace_mode(&mut self, enabled: bool);
51
52 fn debugger_mut(&mut self) -> Option<&mut VMDebugger>;
54
55 fn has_debugger(&self) -> bool;
57}
58
59impl DebuggerIntegration for super::VirtualMachine {
60 fn trace_state(&self) {
61 let schemas = &self.program.type_schema_registry;
62 let stack_vals: Vec<_> = self.stack[..self.sp]
63 .iter()
64 .map(|nb| shape_value::nb_to_external(nb, schemas))
65 .collect();
66 println!("IP: {}, Stack: {:?}", self.ip, stack_vals);
67 if self.ip < self.program.instructions.len() {
68 println!("Next: {:?}", self.program.instructions[self.ip]);
69 }
70 }
71
72 fn debug_break(&self) {
73 let schemas = &self.program.type_schema_registry;
74 println!("=== DEBUG BREAK ===");
75 println!("IP: {}, SP: {}", self.ip, self.sp);
76 let stack_vals: Vec<_> = self.stack[..self.sp]
77 .iter()
78 .map(|nb| shape_value::nb_to_external(nb, schemas))
79 .collect();
80 println!("Stack: {:?}", stack_vals);
81 if let Some(frame) = self.call_stack.last() {
82 let bp = frame.base_pointer;
83 let end = (bp + frame.locals_count).min(self.sp);
84 let locals: Vec<_> = self.stack[bp..end]
85 .iter()
86 .map(|nb| shape_value::nb_to_external(nb, schemas))
87 .collect();
88 println!("Locals (bp={}): {:?}", bp, locals);
89 }
90 let module_bindings: Vec<_> = self
91 .module_bindings
92 .iter()
93 .map(|nb| shape_value::nb_to_external(nb, schemas))
94 .collect();
95 println!("Globals: {:?}", module_bindings);
96 println!("Call stack depth: {}", self.call_stack.len());
97 }
98
99 fn instruction_pointer(&self) -> usize {
102 self.ip
103 }
104
105 fn stack_size(&self) -> usize {
106 self.sp
107 }
108
109 fn stack_top(&self) -> Option<ExternalValue> {
110 if self.sp > 0 {
111 let schemas = &self.program.type_schema_registry;
112 Some(shape_value::nb_to_external(
113 &self.stack[self.sp - 1],
114 schemas,
115 ))
116 } else {
117 None
118 }
119 }
120
121 fn stack_values_vec(&self) -> Vec<ExternalValue> {
122 let schemas = &self.program.type_schema_registry;
123 self.stack[..self.sp]
124 .iter()
125 .map(|nb| shape_value::nb_to_external(nb, schemas))
126 .collect()
127 }
128
129 fn call_stack_depth(&self) -> usize {
130 self.call_stack.len()
131 }
132
133 fn call_frames(&self) -> &[super::CallFrame] {
134 &self.call_stack
135 }
136
137 fn local_values_vec(&self) -> Vec<ExternalValue> {
138 let schemas = &self.program.type_schema_registry;
139 if let Some(frame) = self.call_stack.last() {
140 let bp = frame.base_pointer;
141 let end = (bp + frame.locals_count).min(self.sp);
142 self.stack[bp..end]
143 .iter()
144 .map(|nb| shape_value::nb_to_external(nb, schemas))
145 .collect()
146 } else {
147 vec![]
148 }
149 }
150
151 fn module_binding_values(&self) -> Vec<ValueWord> {
152 self.module_bindings.iter().map(|nb| nb.clone()).collect()
153 }
154
155 fn set_module_binding(&mut self, index: usize, value: ValueWord) {
156 use shape_value::ValueWord;
157 if index < self.module_bindings.len() {
158 self.module_bindings[index] = value;
160 } else {
161 self.module_bindings.resize_with(index + 1, ValueWord::none);
162 self.module_bindings[index] = value;
164 }
165 }
166
167 fn set_trace_mode(&mut self, enabled: bool) {
168 self.config.trace_execution = enabled;
169 if let Some(ref mut debugger) = self.debugger {
170 debugger.set_trace_mode(enabled);
171 }
172 }
173
174 fn debugger_mut(&mut self) -> Option<&mut VMDebugger> {
175 self.debugger.as_mut()
176 }
177
178 fn has_debugger(&self) -> bool {
179 self.debugger.is_some()
180 }
181}