helix_core/compiler/
runtime.rs

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}