Skip to main content

sema_vm/
opcodes.rs

1/// Bytecode opcodes for the Sema VM.
2///
3/// Stack-based: operands are pushed/popped from the value stack.
4/// Variable-length encoding: opcode (1 byte) + operands (u16/u32/i32).
5#[repr(u8)]
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Op {
8    // Constants & stack
9    Const, // u16 const_index → push constants[i]
10    Nil,   // push nil
11    True,  // push #t
12    False, // push #f
13    Pop,   // discard TOS
14    Dup,   // duplicate TOS
15
16    // Locals (slot-addressed within call frame)
17    LoadLocal,  // u16 slot → push locals[slot]
18    StoreLocal, // u16 slot → locals[slot] = pop
19
20    // Upvalues (captured variables from enclosing scopes)
21    LoadUpvalue,  // u16 index → push upvalues[i].get()
22    StoreUpvalue, // u16 index → upvalues[i].set(pop)
23
24    // Globals (module-level bindings, keyed by Spur)
25    LoadGlobal,   // u32 spur → push globals[spur]
26    StoreGlobal,  // u32 spur → globals[spur] = pop
27    DefineGlobal, // u32 spur → globals[spur] = pop (define, not set!)
28
29    // Control flow
30    Jump,        // i32 relative offset
31    JumpIfFalse, // i32 relative offset (pop condition)
32    JumpIfTrue,  // i32 relative offset (pop condition)
33
34    // Function calls
35    Call,     // u16 argc → call TOS-argc with argc args
36    TailCall, // u16 argc → tail call (reuse frame)
37    Return,   // return TOS
38
39    // Closures
40    MakeClosure, // u16 func_id, u16 n_upvalues, then n * (u8 is_local, u16 idx)
41
42    // Native function calls (fast path)
43    CallNative, // u16 native_id, u16 argc
44
45    // Data constructors
46    MakeList,    // u16 n → pop n values, push list
47    MakeVector,  // u16 n → pop n values, push vector
48    MakeMap,     // u16 n_pairs → pop 2n values, push map
49    MakeHashMap, // u16 n_pairs → pop 2n values, push hashmap
50
51    // Exception handling
52    Throw, // pop value, throw as exception
53
54    // Generic arithmetic & comparison
55    Add,
56    Sub,
57    Mul,
58    Div,
59    Negate,
60    Not,
61    Eq,
62    Lt,
63    Gt,
64    Le,
65    Ge,
66
67    // Specialized int arithmetic (fast paths)
68    AddInt,
69    SubInt,
70    MulInt,
71    LtInt,
72    EqInt,
73
74    // Specialized zero-operand locals (most common slots)
75    LoadLocal0, // = 42
76    LoadLocal1, // = 43
77    LoadLocal2, // = 44
78    LoadLocal3, // = 45
79}
80
81impl Op {
82    pub fn from_u8(byte: u8) -> Option<Op> {
83        match byte {
84            0 => Some(Op::Const),
85            1 => Some(Op::Nil),
86            2 => Some(Op::True),
87            3 => Some(Op::False),
88            4 => Some(Op::Pop),
89            5 => Some(Op::Dup),
90            6 => Some(Op::LoadLocal),
91            7 => Some(Op::StoreLocal),
92            8 => Some(Op::LoadUpvalue),
93            9 => Some(Op::StoreUpvalue),
94            10 => Some(Op::LoadGlobal),
95            11 => Some(Op::StoreGlobal),
96            12 => Some(Op::DefineGlobal),
97            13 => Some(Op::Jump),
98            14 => Some(Op::JumpIfFalse),
99            15 => Some(Op::JumpIfTrue),
100            16 => Some(Op::Call),
101            17 => Some(Op::TailCall),
102            18 => Some(Op::Return),
103            19 => Some(Op::MakeClosure),
104            20 => Some(Op::CallNative),
105            21 => Some(Op::MakeList),
106            22 => Some(Op::MakeVector),
107            23 => Some(Op::MakeMap),
108            24 => Some(Op::MakeHashMap),
109            25 => Some(Op::Throw),
110            26 => Some(Op::Add),
111            27 => Some(Op::Sub),
112            28 => Some(Op::Mul),
113            29 => Some(Op::Div),
114            30 => Some(Op::Negate),
115            31 => Some(Op::Not),
116            32 => Some(Op::Eq),
117            33 => Some(Op::Lt),
118            34 => Some(Op::Gt),
119            35 => Some(Op::Le),
120            36 => Some(Op::Ge),
121            37 => Some(Op::AddInt),
122            38 => Some(Op::SubInt),
123            39 => Some(Op::MulInt),
124            40 => Some(Op::LtInt),
125            41 => Some(Op::EqInt),
126            42 => Some(Op::LoadLocal0),
127            43 => Some(Op::LoadLocal1),
128            44 => Some(Op::LoadLocal2),
129            45 => Some(Op::LoadLocal3),
130            _ => None,
131        }
132    }
133}