glyph_runtime/
vm.rs

1//! Virtual Machine implementation for Glyph
2
3use crate::{
4    frame::Frame, memory::MemoryManager, stack::Stack, CapabilitySet, Instruction, RuntimeError,
5};
6use glyph_intrinsics::IntrinsicRegistry;
7use glyph_types::Value;
8use std::collections::HashMap;
9use std::sync::Arc;
10use thiserror::Error;
11
12#[derive(Debug, Error)]
13pub enum VMError {
14    #[error("Runtime error: {0}")]
15    Runtime(#[from] RuntimeError),
16
17    #[error("Invalid bytecode")]
18    InvalidBytecode,
19
20    #[error("Execution limit exceeded")]
21    ExecutionLimitExceeded,
22}
23
24/// VM configuration
25#[derive(Debug, Clone)]
26pub struct VMConfig {
27    /// Maximum stack size
28    pub max_stack_size: usize,
29    /// Maximum call depth
30    pub max_call_depth: usize,
31    /// Maximum execution steps
32    pub max_execution_steps: usize,
33    /// Granted capabilities
34    pub capabilities: CapabilitySet,
35}
36
37impl Default for VMConfig {
38    fn default() -> Self {
39        Self {
40            max_stack_size: 10_000,
41            max_call_depth: 1_000,
42            max_execution_steps: 1_000_000,
43            capabilities: CapabilitySet::new(),
44        }
45    }
46}
47
48/// Glyph Virtual Machine
49///
50/// Immutable-first execution model:
51/// - All values are immutable
52/// - Bindings are immutable (no reassignment)
53/// - Collections operations create new collections
54/// - Side effects only through capability-controlled intrinsics
55pub struct VM {
56    /// VM configuration
57    config: VMConfig,
58    /// Execution stack
59    stack: Stack,
60    /// Call frames
61    frames: Vec<Frame>,
62    /// Global immutable bindings
63    globals: HashMap<String, Value>,
64    /// Current instruction pointer
65    ip: usize,
66    /// Current function index
67    current_function: usize,
68    /// Execution step counter
69    steps: usize,
70    /// Memory manager
71    memory: Arc<MemoryManager>,
72    /// Program bytecode
73    bytecode: Vec<Vec<Instruction>>,
74    /// Telemetry data
75    telemetry: Vec<(String, Value)>,
76
77    /// Intrinsic function registry
78    intrinsics: Arc<IntrinsicRegistry>,
79}
80
81impl VM {
82    /// Create a new VM with the given configuration
83    pub fn new(config: VMConfig) -> Self {
84        let memory = Arc::new(MemoryManager::new(
85            config
86                .capabilities
87                .iter()
88                .find_map(|cap| match cap {
89                    crate::Capability::MemoryLimited(limit) => Some(*limit),
90                    crate::Capability::MemoryUnlimited => Some(usize::MAX),
91                    _ => None,
92                })
93                .unwrap_or(10 * 1024 * 1024), // Default 10MB
94        ));
95
96        Self {
97            stack: Stack::new(config.max_stack_size),
98            frames: Vec::new(),
99            globals: HashMap::new(),
100            ip: 0,
101            current_function: 0,
102            steps: 0,
103            memory,
104            bytecode: Vec::new(),
105            telemetry: Vec::new(),
106            config,
107            intrinsics: Arc::new(IntrinsicRegistry::new()),
108        }
109    }
110
111    /// Load bytecode into the VM
112    pub fn load_bytecode(&mut self, bytecode: Vec<Vec<Instruction>>) {
113        self.bytecode = bytecode;
114    }
115
116    /// Execute the loaded program
117    pub fn execute(&mut self) -> Result<Value, VMError> {
118        // Initialize execution with main function (index 0)
119        self.current_function = 0;
120        self.ip = 0;
121        self.steps = 0;
122
123        // Create initial frame if needed
124        if self.frames.is_empty() {
125            self.frames.push(Frame::new(0, 0));
126        }
127
128        // Main execution loop
129        loop {
130            // Check execution limits
131            if self.steps >= self.config.max_execution_steps {
132                return Err(VMError::ExecutionLimitExceeded);
133            }
134            self.steps += 1;
135
136            // Get current instruction
137            let instruction = self.fetch_instruction()?;
138
139            eprintln!("[VM] Executing instruction: {instruction:?}");
140
141            // Execute instruction
142            match self.execute_instruction(instruction)? {
143                ExecutionResult::Continue => {}
144                ExecutionResult::Halt(value) => {
145                    eprintln!("[VM] Halting with value: {value:?}");
146                    return Ok(value);
147                }
148            }
149        }
150    }
151
152    /// Fetch the next instruction
153    fn fetch_instruction(&mut self) -> Result<Instruction, VMError> {
154        let function = self
155            .bytecode
156            .get(self.current_function)
157            .ok_or(VMError::Runtime(RuntimeError::FunctionNotFound(
158                self.current_function,
159            )))?;
160
161        let instruction = function
162            .get(self.ip)
163            .ok_or(VMError::InvalidBytecode)?
164            .clone();
165
166        self.ip += 1;
167        Ok(instruction)
168    }
169
170    /// Execute a single instruction
171    fn execute_instruction(
172        &mut self,
173        instruction: Instruction,
174    ) -> Result<ExecutionResult, VMError> {
175        use Instruction::*;
176
177        match instruction {
178            // Stack operations
179            Push(value) => self.push(value)?,
180            Pop => {
181                self.pop()?;
182            }
183            Dup => self
184                .stack
185                .dup()
186                .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))?,
187            Swap => self
188                .stack
189                .swap()
190                .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))?,
191            Rot3 => self.rotate_three()?,
192
193            // Arithmetic (immutable operations)
194            Add => self.binary_op(|a, b| match (a, b) {
195                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
196                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
197                (Value::Str(x), Value::Str(y)) => Ok(Value::Str(x + &y)),
198                _ => Err(RuntimeError::TypeError(
199                    "Invalid types for addition".to_string(),
200                )),
201            })?,
202
203            Sub => self.binary_op(|a, b| match (a, b) {
204                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
205                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
206                _ => Err(RuntimeError::TypeError(
207                    "Invalid types for subtraction".to_string(),
208                )),
209            })?,
210
211            Mul => self.binary_op(|a, b| match (a, b) {
212                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
213                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
214                _ => Err(RuntimeError::TypeError(
215                    "Invalid types for multiplication".to_string(),
216                )),
217            })?,
218
219            Div => self.binary_op(|a, b| match (a, b) {
220                (Value::Int(x), Value::Int(y)) => {
221                    if y == 0 {
222                        return Err(RuntimeError::DivisionByZero);
223                    }
224                    Ok(Value::Int(x / y))
225                }
226                (Value::Float(x), Value::Float(y)) => {
227                    if y == 0.0 {
228                        return Err(RuntimeError::DivisionByZero);
229                    }
230                    Ok(Value::Float(x / y))
231                }
232                _ => Err(RuntimeError::TypeError(
233                    "Invalid types for division".to_string(),
234                )),
235            })?,
236
237            // Comparison operations
238            Eq => self.binary_op(|a, b| Ok(Value::Bool(a == b)))?,
239            Ne => self.binary_op(|a, b| Ok(Value::Bool(a != b)))?,
240
241            Lt => self.binary_op(|a, b| match (a, b) {
242                (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x < y)),
243                (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x < y)),
244                _ => Err(RuntimeError::TypeError(
245                    "Invalid types for less than".to_string(),
246                )),
247            })?,
248
249            Le => self.binary_op(|a, b| match (a, b) {
250                (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x <= y)),
251                (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x <= y)),
252                _ => Err(RuntimeError::TypeError(
253                    "Invalid types for less than or equal".to_string(),
254                )),
255            })?,
256
257            Gt => self.binary_op(|a, b| match (a, b) {
258                (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x > y)),
259                (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x > y)),
260                _ => Err(RuntimeError::TypeError(
261                    "Invalid types for greater than".to_string(),
262                )),
263            })?,
264
265            Ge => self.binary_op(|a, b| match (a, b) {
266                (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x >= y)),
267                (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x >= y)),
268                _ => Err(RuntimeError::TypeError(
269                    "Invalid types for greater than or equal".to_string(),
270                )),
271            })?,
272
273            // Control flow
274            Jump(target) => {
275                self.ip = target;
276            }
277            JumpIf(target) => {
278                let condition = self.pop()?;
279                if condition.is_truthy() {
280                    self.ip = target;
281                }
282            }
283            JumpIfNot(target) => {
284                let condition = self.pop()?;
285                if !condition.is_truthy() {
286                    self.ip = target;
287                }
288            }
289
290            // Immutable bindings
291            BindLocal(name) => {
292                let value = self.pop()?;
293                let frame = self
294                    .frames
295                    .last_mut()
296                    .ok_or(VMError::Runtime(RuntimeError::StackUnderflow))?;
297                frame.set_local(name, value);
298            }
299
300            LoadLocal(name) => {
301                let value = self
302                    .frames
303                    .last()
304                    .and_then(|f| f.get_local(&name))
305                    .cloned()
306                    .ok_or(VMError::Runtime(RuntimeError::UndefinedVariable(name)))?;
307                self.push(value)?;
308            }
309
310            LoadGlobal(name) => {
311                let value = self
312                    .globals
313                    .get(&name)
314                    .cloned()
315                    .ok_or(VMError::Runtime(RuntimeError::UndefinedVariable(name)))?;
316                self.push(value)?;
317            }
318
319            // Collection creation (immutable)
320            MakeList(count) => {
321                let items = self
322                    .stack
323                    .pop_n(count)
324                    .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))?;
325                self.push(Value::List(items))?;
326            }
327
328            MakeDict(count) => {
329                let pairs = self
330                    .stack
331                    .pop_n(count * 2)
332                    .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))?;
333                let mut dict = HashMap::new();
334                for chunk in pairs.chunks(2) {
335                    if let (Value::Str(key), value) = (&chunk[0], &chunk[1]) {
336                        dict.insert(key.clone(), value.clone());
337                    } else {
338                        return Err(VMError::Runtime(RuntimeError::TypeError(
339                            "Dict keys must be strings".to_string(),
340                        )));
341                    }
342                }
343                self.push(Value::Dict(dict))?;
344            }
345
346            // Capability checks
347            RequireCapability(cap) => {
348                self.check_capability(&cap)?;
349            }
350
351            CheckCapability(cap) => {
352                let has_cap = self.config.capabilities.has_by_name(&cap);
353                self.push(Value::Bool(has_cap))?;
354            }
355
356            // Telemetry
357            TraceValue(label) => {
358                let value = self
359                    .stack
360                    .peek()
361                    .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))?
362                    .clone();
363                self.telemetry.push((label, value));
364            }
365
366            RecordTelemetry(event) => {
367                self.telemetry.push((event, Value::None));
368            }
369
370            // Control instructions
371            Return => {
372                if let Some(frame) = self.frames.pop() {
373                    if let (Some(ret_ip), Some(ret_fn)) = (frame.return_ip, frame.return_function) {
374                        self.ip = ret_ip;
375                        self.current_function = ret_fn;
376                        // Clean up stack to frame base
377                        self.stack.truncate(frame.bp);
378                    } else {
379                        // Returning from main
380                        let result = self.pop().unwrap_or(Value::None);
381                        eprintln!("[VM] Return from main with result: {result:?}");
382                        return Ok(ExecutionResult::Halt(result));
383                    }
384                } else {
385                    // No frames, halt with top of stack
386                    let result = self.pop().unwrap_or(Value::None);
387                    eprintln!("[VM] Return with no frames, result: {result:?}");
388                    return Ok(ExecutionResult::Halt(result));
389                }
390            }
391
392            Halt => {
393                let result = self.pop().unwrap_or(Value::None);
394                return Ok(ExecutionResult::Halt(result));
395            }
396
397            Nop => {}
398
399            // Logical operations
400            And => self.binary_op(|a, b| match (a, b) {
401                (Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x && y)),
402                _ => Err(RuntimeError::TypeError("Invalid types for AND".to_string())),
403            })?,
404
405            Or => self.binary_op(|a, b| match (a, b) {
406                (Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x || y)),
407                _ => Err(RuntimeError::TypeError("Invalid types for OR".to_string())),
408            })?,
409
410            Not => {
411                let value = self.pop()?;
412                match value {
413                    Value::Bool(b) => self.push(Value::Bool(!b))?,
414                    _ => {
415                        return Err(VMError::Runtime(RuntimeError::TypeError(
416                            "NOT requires boolean".to_string(),
417                        )))
418                    }
419                }
420            }
421
422            // List operations (immutable)
423            ListAppend => {
424                let item = self.pop()?;
425                let list = self.pop()?;
426                match list {
427                    Value::List(mut items) => {
428                        items.push(item);
429                        self.push(Value::List(items))?;
430                    }
431                    _ => {
432                        return Err(VMError::Runtime(RuntimeError::TypeError(
433                            "ListAppend requires a list".to_string(),
434                        )))
435                    }
436                }
437            }
438
439            ListConcat => self.binary_op(|a, b| match (a, b) {
440                (Value::List(mut list1), Value::List(list2)) => {
441                    list1.extend(list2);
442                    Ok(Value::List(list1))
443                }
444                _ => Err(RuntimeError::TypeError(
445                    "ListConcat requires two lists".to_string(),
446                )),
447            })?,
448
449            // Dict operations (immutable)
450            DictInsert => {
451                let value = self.pop()?;
452                let key = self.pop()?;
453                let dict = self.pop()?;
454                match (dict, key) {
455                    (Value::Dict(mut map), Value::Str(key_str)) => {
456                        map.insert(key_str, value);
457                        self.push(Value::Dict(map))?;
458                    }
459                    _ => {
460                        return Err(VMError::Runtime(RuntimeError::TypeError(
461                            "DictInsert requires dict and string key".to_string(),
462                        )))
463                    }
464                }
465            }
466
467            DictMerge => self.binary_op(|a, b| match (a, b) {
468                (Value::Dict(mut dict1), Value::Dict(dict2)) => {
469                    dict1.extend(dict2);
470                    Ok(Value::Dict(dict1))
471                }
472                _ => Err(RuntimeError::TypeError(
473                    "DictMerge requires two dicts".to_string(),
474                )),
475            })?,
476
477            // Function calls
478            Call(function_idx) => {
479                // Check call depth
480                if self.frames.len() >= self.config.max_call_depth {
481                    return Err(VMError::Runtime(RuntimeError::StackOverflow));
482                }
483
484                // Create new frame
485                let frame = Frame::with_return(
486                    function_idx,
487                    self.stack.depth(),
488                    self.ip,
489                    self.current_function,
490                );
491                self.frames.push(frame);
492
493                // Jump to function
494                self.current_function = function_idx;
495                self.ip = 0;
496            }
497
498            // Get index operation
499            GetIndex => {
500                let index = self.pop()?;
501                let collection = self.pop()?;
502                match (&collection, &index) {
503                    (Value::List(items), Value::Int(idx)) => {
504                        if *idx < 0 || *idx as usize >= items.len() {
505                            return Err(VMError::Runtime(RuntimeError::IndexOutOfBounds {
506                                index: *idx,
507                                length: items.len(),
508                            }));
509                        }
510                        self.push(items[*idx as usize].clone())?;
511                    }
512                    (Value::Str(s), Value::Int(idx)) => {
513                        if *idx < 0 || *idx as usize >= s.len() {
514                            return Err(VMError::Runtime(RuntimeError::IndexOutOfBounds {
515                                index: *idx,
516                                length: s.len(),
517                            }));
518                        }
519                        // Get character at index as a string
520                        let ch = s.chars().nth(*idx as usize).unwrap();
521                        self.push(Value::Str(ch.to_string()))?;
522                    }
523                    (Value::Dict(map), Value::Str(key)) => match map.get(key) {
524                        Some(value) => self.push(value.clone())?,
525                        None => {
526                            return Err(VMError::Runtime(RuntimeError::KeyNotFound(key.clone())))
527                        }
528                    },
529                    _ => {
530                        return Err(VMError::Runtime(RuntimeError::TypeError(format!(
531                            "Invalid types for indexing: {collection:?}[{index:?}]"
532                        ))))
533                    }
534                }
535            }
536
537            // Native function calls
538            CallNative(name) => match name.as_str() {
539                "len" => {
540                    let value = self.pop()?;
541                    let length = match value {
542                        Value::List(ref items) => items.len() as i64,
543                        Value::Str(ref s) => s.len() as i64,
544                        Value::Dict(ref map) => map.len() as i64,
545                        _ => {
546                            return Err(VMError::Runtime(RuntimeError::TypeError(format!(
547                                "len() not supported for {value:?}"
548                            ))))
549                        }
550                    };
551                    self.push(Value::Int(length))?;
552                }
553                _ => {
554                    return Err(VMError::Runtime(RuntimeError::NativeFunctionError(
555                        format!("Unknown native function: {name}"),
556                    )))
557                }
558            },
559
560            // Intrinsic function calls
561            CallIntrinsic { name, capability } => {
562                // Check capability if specified
563                if let Some(cap) = capability {
564                    self.check_capability(&cap)?;
565                }
566
567                // Debug: Check if intrinsic exists
568                eprintln!("[VM] Looking for intrinsic: {name}");
569                eprintln!("[VM] Available intrinsics: {:?}", self.intrinsics.names());
570
571                // Get the intrinsic
572                let intrinsic = self.intrinsics.get(&name).ok_or(
573                    VMError::Runtime(RuntimeError::NativeFunctionError(format!(
574                        "Unknown intrinsic: {name}"
575                    )))
576                )?;
577
578                // Pop arguments - for now we'll handle simple cases
579                // TODO: Handle keyword arguments properly
580                let args = match name.as_str() {
581                    "voice.speak" => {
582                        // voice.speak(text: str)
583                        vec![self.pop()?]
584                    }
585                    "display.chart" | "display.image" => {
586                        // display.chart(data, title: str)
587                        let title = self.pop()?;
588                        let data = self.pop()?;
589                        vec![data, title]
590                    }
591                    "net.fetch" => {
592                        // net.fetch(url: str)
593                        vec![self.pop()?]
594                    }
595                    "wait.confirm" => {
596                        // wait.confirm(message: str)
597                        vec![self.pop()?]
598                    }
599                    _ => {
600                        // Unknown intrinsic - shouldn't happen if registry is correct
601                        return Err(VMError::Runtime(RuntimeError::NativeFunctionError(
602                            format!("No argument handling for intrinsic: {name}"),
603                        )));
604                    }
605                };
606
607                eprintln!("[VM] Executing intrinsic {name} with args: {args:?}");
608
609                // Execute the intrinsic (blocking for now - TODO: handle async properly)
610                let result = tokio::task::block_in_place(|| {
611                    tokio::runtime::Handle::current()
612                        .block_on(async { intrinsic.execute(args).await })
613                })
614                .map_err(|e| {
615                    VMError::Runtime(RuntimeError::NativeFunctionError(format!(
616                        "Intrinsic error: {e}"
617                    )))
618                })?;
619
620                eprintln!("[VM] Intrinsic result: {result:?}");
621
622                // Push result
623                self.push(result)?;
624            }
625
626            // Remaining instructions not yet implemented
627            _ => {
628                return Err(VMError::Runtime(RuntimeError::NativeFunctionError(
629                    format!("Instruction {instruction:?} not yet implemented"),
630                )))
631            }
632        }
633
634        Ok(ExecutionResult::Continue)
635    }
636
637    /// Push a value onto the stack
638    pub fn push(&mut self, value: Value) -> Result<(), VMError> {
639        self.stack
640            .push(value)
641            .map_err(|_| VMError::Runtime(RuntimeError::StackOverflow))
642    }
643
644    /// Pop a value from the stack
645    pub fn pop(&mut self) -> Result<Value, VMError> {
646        self.stack
647            .pop()
648            .map_err(|_| VMError::Runtime(RuntimeError::StackUnderflow))
649    }
650
651    /// Check if a capability is granted
652    pub fn check_capability(&self, capability: &str) -> Result<(), VMError> {
653        if self.config.capabilities.has_by_name(capability) {
654            Ok(())
655        } else {
656            Err(VMError::Runtime(RuntimeError::CapabilityError(format!(
657                "Capability '{capability}' not granted"
658            ))))
659        }
660    }
661
662    /// Execute a binary operation
663    fn binary_op<F>(&mut self, op: F) -> Result<(), VMError>
664    where
665        F: FnOnce(Value, Value) -> Result<Value, RuntimeError>,
666    {
667        let b = self.pop()?;
668        let a = self.pop()?;
669        let result = op(a, b).map_err(VMError::Runtime)?;
670        self.push(result)
671    }
672
673    /// Rotate top three stack values
674    fn rotate_three(&mut self) -> Result<(), VMError> {
675        let c = self.pop()?;
676        let b = self.pop()?;
677        let a = self.pop()?;
678        self.push(b)?;
679        self.push(c)?;
680        self.push(a)?;
681        Ok(())
682    }
683
684    /// Get telemetry data
685    pub fn telemetry(&self) -> &[(String, Value)] {
686        &self.telemetry
687    }
688
689    /// Clear telemetry data
690    pub fn clear_telemetry(&mut self) {
691        self.telemetry.clear();
692    }
693
694    /// Get current memory usage
695    pub fn memory_usage(&self) -> usize {
696        self.memory.current_usage()
697    }
698
699    /// Get memory usage percentage
700    pub fn memory_usage_percentage(&self) -> f64 {
701        self.memory.usage_percentage()
702    }
703}
704
705/// Result of executing an instruction
706enum ExecutionResult {
707    /// Continue execution
708    Continue,
709    /// Halt execution with a value
710    Halt(Value),
711}
712
713#[cfg(test)]
714mod tests {
715    use super::*;
716    use crate::Capability;
717
718    fn create_test_vm() -> VM {
719        let config = VMConfig {
720            max_stack_size: 1000,
721            max_call_depth: 100,
722            max_execution_steps: 10000,
723            capabilities: CapabilitySet::new(),
724        };
725        VM::new(config)
726    }
727
728    #[test]
729    fn test_arithmetic_operations() {
730        let mut vm = create_test_vm();
731
732        // Test addition
733        vm.load_bytecode(vec![vec![
734            Instruction::Push(Value::Int(5)),
735            Instruction::Push(Value::Int(3)),
736            Instruction::Add,
737            Instruction::Halt,
738        ]]);
739
740        let result = vm.execute().unwrap();
741        assert_eq!(result, Value::Int(8));
742    }
743
744    #[test]
745    fn test_immutable_bindings() {
746        let mut vm = create_test_vm();
747
748        // Create a frame for local bindings
749        vm.frames.push(Frame::new(0, 0));
750
751        vm.load_bytecode(vec![vec![
752            Instruction::Push(Value::Int(42)),
753            Instruction::BindLocal("x".to_string()),
754            Instruction::LoadLocal("x".to_string()),
755            Instruction::Push(Value::Int(10)),
756            Instruction::Add,
757            Instruction::Halt,
758        ]]);
759
760        let result = vm.execute().unwrap();
761        assert_eq!(result, Value::Int(52));
762    }
763
764    #[test]
765    fn test_list_operations() {
766        let mut vm = create_test_vm();
767
768        vm.load_bytecode(vec![vec![
769            Instruction::Push(Value::Int(1)),
770            Instruction::Push(Value::Int(2)),
771            Instruction::Push(Value::Int(3)),
772            Instruction::MakeList(3),
773            Instruction::Halt,
774        ]]);
775
776        let result = vm.execute().unwrap();
777        match result {
778            Value::List(items) => {
779                assert_eq!(items.len(), 3);
780                assert_eq!(items[0], Value::Int(1));
781                assert_eq!(items[1], Value::Int(2));
782                assert_eq!(items[2], Value::Int(3));
783            }
784            _ => panic!("Expected list"),
785        }
786    }
787
788    #[test]
789    fn test_dict_operations() {
790        let mut vm = create_test_vm();
791
792        vm.load_bytecode(vec![vec![
793            Instruction::Push(Value::Str("key1".to_string())),
794            Instruction::Push(Value::Int(100)),
795            Instruction::Push(Value::Str("key2".to_string())),
796            Instruction::Push(Value::Str("value2".to_string())),
797            Instruction::MakeDict(2),
798            Instruction::Halt,
799        ]]);
800
801        let result = vm.execute().unwrap();
802        match result {
803            Value::Dict(map) => {
804                assert_eq!(map.len(), 2);
805                assert_eq!(map.get("key1"), Some(&Value::Int(100)));
806                assert_eq!(map.get("key2"), Some(&Value::Str("value2".to_string())));
807            }
808            _ => panic!("Expected dict"),
809        }
810    }
811
812    #[test]
813    fn test_capability_check() {
814        let mut config = VMConfig::default();
815        config.capabilities.grant(Capability::AudioSpeak);
816        let mut vm = VM::new(config);
817
818        vm.load_bytecode(vec![vec![
819            Instruction::CheckCapability("audio.speak".to_string()),
820            Instruction::Halt,
821        ]]);
822
823        let result = vm.execute().unwrap();
824        assert_eq!(result, Value::Bool(true));
825    }
826
827    #[test]
828    fn test_capability_requirement_failure() {
829        let mut vm = create_test_vm();
830
831        vm.load_bytecode(vec![vec![
832            Instruction::RequireCapability("network.fetch".to_string()),
833            Instruction::Halt,
834        ]]);
835
836        let result = vm.execute();
837        assert!(matches!(
838            result,
839            Err(VMError::Runtime(RuntimeError::CapabilityError(_)))
840        ));
841    }
842
843    #[test]
844    fn test_control_flow() {
845        let mut vm = create_test_vm();
846
847        vm.load_bytecode(vec![vec![
848            Instruction::Push(Value::Bool(true)),
849            Instruction::JumpIf(3),
850            Instruction::Push(Value::Int(1)), // Should be skipped
851            Instruction::Push(Value::Int(2)), // Target of jump
852            Instruction::Halt,
853        ]]);
854
855        let result = vm.execute().unwrap();
856        assert_eq!(result, Value::Int(2));
857    }
858
859    #[test]
860    fn test_execution_limit() {
861        let config = VMConfig {
862            max_execution_steps: 5,
863            ..Default::default()
864        };
865        let mut vm = VM::new(config);
866
867        // Infinite loop
868        vm.load_bytecode(vec![vec![
869            Instruction::Push(Value::Int(1)),
870            Instruction::Jump(0),
871        ]]);
872
873        let result = vm.execute();
874        assert!(matches!(result, Err(VMError::ExecutionLimitExceeded)));
875    }
876
877    #[test]
878    fn test_telemetry() {
879        let mut vm = create_test_vm();
880
881        vm.load_bytecode(vec![vec![
882            Instruction::Push(Value::Int(42)),
883            Instruction::TraceValue("debug_value".to_string()),
884            Instruction::RecordTelemetry("test_event".to_string()),
885            Instruction::Halt,
886        ]]);
887
888        vm.execute().unwrap();
889
890        let telemetry = vm.telemetry();
891        assert_eq!(telemetry.len(), 2);
892        assert_eq!(telemetry[0].0, "debug_value");
893        assert_eq!(telemetry[0].1, Value::Int(42));
894        assert_eq!(telemetry[1].0, "test_event");
895    }
896}