ruchy_notebook/vm/
bytecode.rs

1use serde::{Deserialize, Serialize};
2use num_derive::{FromPrimitive, ToPrimitive};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, FromPrimitive, ToPrimitive)]
5#[repr(u8)]
6pub enum OpCode {
7    // Stack operations
8    Push = 0x01,
9    Pop = 0x02,
10    Dup = 0x03,
11    Swap = 0x04,
12    
13    // Arithmetic
14    Add = 0x10,
15    Sub = 0x11,
16    Mul = 0x12,
17    Div = 0x13,
18    Mod = 0x14,
19    Neg = 0x15,
20    
21    // Comparison
22    Eq = 0x20,
23    Ne = 0x21,
24    Lt = 0x22,
25    Le = 0x23,
26    Gt = 0x24,
27    Ge = 0x25,
28    
29    // Boolean
30    And = 0x30,
31    Or = 0x31,
32    Not = 0x32,
33    
34    // Control flow
35    Jump = 0x40,
36    JumpIf = 0x41,
37    JumpIfNot = 0x42,
38    Call = 0x43,
39    Return = 0x44,
40    
41    // Variables
42    LoadLocal = 0x50,
43    StoreLocal = 0x51,
44    LoadGlobal = 0x52,
45    StoreGlobal = 0x53,
46    
47    // Data structures
48    BuildList = 0x60,
49    BuildMap = 0x61,
50    Index = 0x62,
51    SetIndex = 0x63,
52    
53    // Special
54    Print = 0x70,
55    Halt = 0xFF,
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59pub enum Value {
60    Null,
61    Bool(bool),
62    Int(i64),
63    Float(f64),
64    String(String),
65    List(Vec<Value>),
66    Map(Vec<(String, Value)>),
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Instruction {
71    pub opcode: OpCode,
72    pub operand: Option<Value>,
73}
74
75impl Instruction {
76    pub fn new(opcode: OpCode) -> Self {
77        Self { opcode, operand: None }
78    }
79    
80    pub fn with_operand(opcode: OpCode, operand: Value) -> Self {
81        Self { opcode, operand: Some(operand) }
82    }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct BytecodeModule {
87    pub instructions: Vec<Instruction>,
88    pub constants: Vec<Value>,
89    pub entry_point: usize,
90}
91
92impl BytecodeModule {
93    pub fn new() -> Self {
94        Self {
95            instructions: Vec::new(),
96            constants: Vec::new(),
97            entry_point: 0,
98        }
99    }
100    
101    pub fn add_instruction(&mut self, instruction: Instruction) -> usize {
102        let index = self.instructions.len();
103        self.instructions.push(instruction);
104        index
105    }
106    
107    pub fn add_constant(&mut self, value: Value) -> usize {
108        let index = self.constants.len();
109        self.constants.push(value);
110        index
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    
118    #[test]
119    fn test_opcode_encoding() {
120        assert_eq!(OpCode::Push as u8, 0x01);
121        assert_eq!(OpCode::Add as u8, 0x10);
122        assert_eq!(OpCode::Halt as u8, 0xFF);
123    }
124    
125    #[test]
126    fn test_instruction_creation() {
127        let inst = Instruction::new(OpCode::Add);
128        assert_eq!(inst.opcode, OpCode::Add);
129        assert_eq!(inst.operand, None);
130        
131        let inst_with_val = Instruction::with_operand(OpCode::Push, Value::Int(42));
132        assert_eq!(inst_with_val.opcode, OpCode::Push);
133        assert_eq!(inst_with_val.operand, Some(Value::Int(42)));
134    }
135    
136    #[test]
137    fn test_bytecode_module() {
138        let mut module = BytecodeModule::new();
139        
140        let const_idx = module.add_constant(Value::Int(100));
141        assert_eq!(const_idx, 0);
142        
143        let inst_idx = module.add_instruction(Instruction::new(OpCode::Push));
144        assert_eq!(inst_idx, 0);
145        
146        assert_eq!(module.instructions.len(), 1);
147        assert_eq!(module.constants.len(), 1);
148    }
149}