1use std::collections::{HashMap, VecDeque};
2use std::path::Path;
3use crate::compiler::binary::{HelixBinary, Value};
4use crate::error::{RuntimeError, RuntimeErrorKind};
5use crate::types::HelixConfig;
6pub struct HelixVM {
7 stack: Vec<Value>,
8 memory: HashMap<u32, Value>,
9 registers: VMRegisters,
10 config: HelixConfig,
11 call_stack: VecDeque<CallFrame>,
12 execution_state: ExecutionState,
13 debug_mode: bool,
14 breakpoints: HashMap<usize, Breakpoint>,
15}
16#[derive(Debug, Default)]
17pub struct VMRegisters {
18 pub program_counter: usize,
19 pub stack_pointer: usize,
20 pub frame_pointer: usize,
21 pub return_address: usize,
22 pub flags: VMFlags,
23}
24#[derive(Debug, Default)]
25pub struct VMFlags {
26 pub zero: bool,
27 pub overflow: bool,
28 pub error: bool,
29 pub halted: bool,
30}
31#[derive(Debug)]
32pub struct CallFrame {
33 pub return_address: usize,
34 pub frame_pointer: usize,
35 pub local_vars: HashMap<u32, Value>,
36}
37#[derive(Debug, PartialEq)]
38pub enum ExecutionState {
39 Ready,
40 Running,
41 Paused,
42 Halted,
43 Error(String),
44}
45#[derive(Debug)]
46pub struct Breakpoint {
47 pub active: bool,
48 pub condition: Option<String>,
49 pub hit_count: usize,
50}
51pub type VMResult<T> = Result<T, RuntimeError>;
52impl HelixVM {
53 pub fn new() -> Self {
54 Self {
55 stack: Vec::new(),
56 memory: HashMap::new(),
57 registers: VMRegisters::default(),
58 config: HelixConfig::default(),
59 call_stack: VecDeque::new(),
60 execution_state: ExecutionState::Ready,
61 debug_mode: false,
62 breakpoints: HashMap::new(),
63 }
64 }
65 pub fn with_debug(mut self) -> Self {
66 self.debug_mode = true;
67 self
68 }
69 pub fn execute_binary(&mut self, binary: &HelixBinary) -> VMResult<HelixConfig> {
70 let serializer = crate::compiler::serializer::BinarySerializer::new(false);
71 let ir = serializer
72 .deserialize_to_ir(binary)
73 .map_err(|e| RuntimeError {
74 kind: RuntimeErrorKind::InvalidInstruction,
75 message: format!("Failed to deserialize binary: {}", e),
76 stack_trace: vec![],
77 })?;
78 self.execution_state = ExecutionState::Running;
79 self.registers.program_counter = 0;
80 while self.registers.program_counter < ir.instructions.len()
81 && self.execution_state == ExecutionState::Running
82 {
83 if self.debug_mode {
84 if let Some(bp) = self
85 .breakpoints
86 .get_mut(&self.registers.program_counter)
87 {
88 if bp.active {
89 bp.hit_count += 1;
90 self.execution_state = ExecutionState::Paused;
91 break;
92 }
93 }
94 }
95 let instruction = &ir.instructions[self.registers.program_counter];
96 self.execute_instruction(instruction)?;
97 }
98 Ok(self.config.clone())
99 }
100 fn execute_instruction(
101 &mut self,
102 instruction: &crate::codegen::Instruction,
103 ) -> VMResult<()> {
104 use crate::codegen::Instruction as IR;
105 match instruction {
106 IR::DeclareAgent(id) => {
107 self.declare_agent(*id)?;
108 }
109 IR::DeclareWorkflow(id) => {
110 self.declare_workflow(*id)?;
111 }
112 IR::DeclareContext(id) => {
113 self.declare_context(*id)?;
114 }
115 IR::DeclareCrew(id) => {
116 self.declare_crew(*id)?;
117 }
118 IR::SetProperty { target, key, value } => {
119 self.set_property(*target, *key, value)?;
120 }
121 IR::SetCapability { agent, capability } => {
122 self.set_capability(*agent, *capability)?;
123 }
124 IR::SetSecret { context, key, secret } => {
125 self.set_secret(*context, *key, secret)?;
126 }
127 IR::DefineStep { workflow, step } => {
128 self.define_step(*workflow, step)?;
129 }
130 IR::DefinePipeline { workflow, nodes } => {
131 self.define_pipeline(*workflow, nodes)?;
132 }
133 IR::ResolveReference { ref_type, index } => {
134 self.resolve_reference(ref_type, *index)?;
135 }
136 IR::SetMetadata { key, value } => {
137 self.set_metadata(*key, *value)?;
138 }
139 }
140 self.registers.program_counter += 1;
141 Ok(())
142 }
143 fn declare_agent(&mut self, _id: u32) -> VMResult<()> {
144 Ok(())
145 }
146 fn declare_workflow(&mut self, _id: u32) -> VMResult<()> {
147 Ok(())
148 }
149 fn declare_context(&mut self, _id: u32) -> VMResult<()> {
150 Ok(())
151 }
152 fn declare_crew(&mut self, _id: u32) -> VMResult<()> {
153 Ok(())
154 }
155 fn set_property(
156 &mut self,
157 _target: u32,
158 _key: u32,
159 _value: &crate::codegen::ConstantValue,
160 ) -> VMResult<()> {
161 Ok(())
162 }
163 fn set_capability(&mut self, _agent: u32, _capability: u32) -> VMResult<()> {
164 Ok(())
165 }
166 fn set_secret(
167 &mut self,
168 _context: u32,
169 _key: u32,
170 _secret: &crate::codegen::SecretType,
171 ) -> VMResult<()> {
172 Ok(())
173 }
174 fn define_step(
175 &mut self,
176 _workflow: u32,
177 _step: &crate::codegen::StepDefinition,
178 ) -> VMResult<()> {
179 Ok(())
180 }
181 fn define_pipeline(
182 &mut self,
183 _workflow: u32,
184 _nodes: &[crate::codegen::PipelineNodeIR],
185 ) -> VMResult<()> {
186 Ok(())
187 }
188 fn resolve_reference(
189 &mut self,
190 _ref_type: &crate::codegen::ReferenceType,
191 _index: u32,
192 ) -> VMResult<()> {
193 Ok(())
194 }
195 fn set_metadata(&mut self, _key: u32, _value: u32) -> VMResult<()> {
196 Ok(())
197 }
198 pub fn push(&mut self, value: Value) -> VMResult<()> {
199 if self.stack.len() >= 1024 {
200 return Err(RuntimeError {
201 kind: RuntimeErrorKind::StackOverflow,
202 message: "Stack overflow".to_string(),
203 stack_trace: self.get_stack_trace(),
204 });
205 }
206 self.stack.push(value);
207 self.registers.stack_pointer += 1;
208 Ok(())
209 }
210 pub fn pop(&mut self) -> VMResult<Value> {
211 if self.stack.is_empty() {
212 return Err(RuntimeError {
213 kind: RuntimeErrorKind::StackUnderflow,
214 message: "Stack underflow".to_string(),
215 stack_trace: self.get_stack_trace(),
216 });
217 }
218 self.registers.stack_pointer -= 1;
219 Ok(self.stack.pop().unwrap())
220 }
221 pub fn load_memory(&self, address: u32) -> VMResult<&Value> {
222 self.memory
223 .get(&address)
224 .ok_or_else(|| RuntimeError {
225 kind: RuntimeErrorKind::MemoryAccessViolation,
226 message: format!("Invalid memory access at address {}", address),
227 stack_trace: self.get_stack_trace(),
228 })
229 }
230 pub fn store_memory(&mut self, address: u32, value: Value) -> VMResult<()> {
231 self.memory.insert(address, value);
232 Ok(())
233 }
234 pub fn set_breakpoint(&mut self, address: usize) {
235 self.breakpoints
236 .insert(
237 address,
238 Breakpoint {
239 active: true,
240 condition: None,
241 hit_count: 0,
242 },
243 );
244 }
245 pub fn remove_breakpoint(&mut self, address: usize) {
246 self.breakpoints.remove(&address);
247 }
248 pub fn continue_execution(&mut self) {
249 if self.execution_state == ExecutionState::Paused {
250 self.execution_state = ExecutionState::Running;
251 }
252 }
253 pub fn step(&mut self) {
254 if self.execution_state == ExecutionState::Paused {
255 self.execution_state = ExecutionState::Running;
256 }
257 }
258 pub fn state(&self) -> &ExecutionState {
259 &self.execution_state
260 }
261 fn get_stack_trace(&self) -> Vec<String> {
262 let mut trace = Vec::new();
263 trace.push(format!("PC: {}", self.registers.program_counter));
264 for (i, frame) in self.call_stack.iter().enumerate() {
265 trace.push(format!("Frame {}: return address {}", i, frame.return_address));
266 }
267 trace
268 }
269 pub fn stats(&self) -> VMStats {
270 VMStats {
271 instructions_executed: self.registers.program_counter,
272 stack_size: self.stack.len(),
273 memory_usage: self.memory.len(),
274 call_depth: self.call_stack.len(),
275 }
276 }
277}
278#[derive(Debug)]
279pub struct VMStats {
280 pub instructions_executed: usize,
281 pub stack_size: usize,
282 pub memory_usage: usize,
283 pub call_depth: usize,
284}
285impl Default for HelixVM {
286 fn default() -> Self {
287 Self::new()
288 }
289}
290pub struct VMExecutor {
291 vm: HelixVM,
292}
293impl VMExecutor {
294 pub fn new() -> Self {
295 Self { vm: HelixVM::new() }
296 }
297 pub fn execute_file<P: AsRef<Path>>(&mut self, path: P) -> VMResult<HelixConfig> {
298 let loader = crate::compiler::loader::BinaryLoader::new();
299 let binary = loader
300 .load_file(path)
301 .map_err(|e| RuntimeError {
302 kind: RuntimeErrorKind::ResourceNotFound,
303 message: format!("Failed to load binary: {}", e),
304 stack_trace: vec![],
305 })?;
306 self.vm.execute_binary(&binary)
307 }
308 pub fn execute_with_debug<P: AsRef<Path>>(
309 &mut self,
310 path: P,
311 ) -> VMResult<HelixConfig> {
312 self.vm = HelixVM::new().with_debug();
313 self.execute_file(path)
314 }
315 pub fn vm(&mut self) -> &mut HelixVM {
316 &mut self.vm
317 }
318}
319impl Default for VMExecutor {
320 fn default() -> Self {
321 Self::new()
322 }
323}
324pub struct VMConfig {
325 pub max_stack_size: usize,
326 pub max_memory: usize,
327 pub max_call_depth: usize,
328 pub enable_gc: bool,
329 pub gc_threshold: usize,
330}
331impl Default for VMConfig {
332 fn default() -> Self {
333 Self {
334 max_stack_size: 1024,
335 max_memory: 65536,
336 max_call_depth: 256,
337 enable_gc: false,
338 gc_threshold: 1000,
339 }
340 }
341}
342#[cfg(test)]
343mod tests {
344 use super::*;
345 #[test]
346 fn test_vm_creation() {
347 let vm = HelixVM::new();
348 assert_eq!(vm.execution_state, ExecutionState::Ready);
349 assert!(vm.stack.is_empty());
350 assert!(vm.memory.is_empty());
351 }
352 #[test]
353 fn test_stack_operations() {
354 let mut vm = HelixVM::new();
355 vm.push(Value::Int(42)).unwrap();
356 assert_eq!(vm.stack.len(), 1);
357 assert_eq!(vm.registers.stack_pointer, 1);
358 let value = vm.pop().unwrap();
359 match value {
360 Value::Int(42) => {}
361 _ => panic!("Expected Int(42)"),
362 }
363 assert!(vm.stack.is_empty());
364 assert_eq!(vm.registers.stack_pointer, 0);
365 }
366 #[test]
367 fn test_memory_operations() {
368 let mut vm = HelixVM::new();
369 vm.store_memory(100, Value::Bool(true)).unwrap();
370 let value = vm.load_memory(100).unwrap();
371 match value {
372 Value::Bool(true) => {}
373 _ => panic!("Expected Bool(true)"),
374 }
375 }
376 #[test]
377 fn test_stack_overflow() {
378 let mut vm = HelixVM::new();
379 for _ in 0..1024 {
380 vm.push(Value::Int(1)).unwrap();
381 }
382 let result = vm.push(Value::Int(2));
383 assert!(result.is_err());
384 if let Err(e) = result {
385 assert_eq!(e.kind, RuntimeErrorKind::StackOverflow);
386 }
387 }
388 #[test]
389 fn test_stack_underflow() {
390 let mut vm = HelixVM::new();
391 let result = vm.pop();
392 assert!(result.is_err());
393 if let Err(e) = result {
394 assert_eq!(e.kind, RuntimeErrorKind::StackUnderflow);
395 }
396 }
397 #[test]
398 fn test_breakpoints() {
399 let mut vm = HelixVM::new().with_debug();
400 vm.set_breakpoint(10);
401 assert!(vm.breakpoints.contains_key(& 10));
402 vm.remove_breakpoint(10);
403 assert!(! vm.breakpoints.contains_key(& 10));
404 }
405 #[test]
406 fn test_vm_stats() {
407 let vm = HelixVM::new();
408 let stats = vm.stats();
409 assert_eq!(stats.instructions_executed, 0);
410 assert_eq!(stats.stack_size, 0);
411 assert_eq!(stats.memory_usage, 0);
412 assert_eq!(stats.call_depth, 0);
413 }
414}