cao_lang/
instruction.rs

1use std::mem::size_of;
2
3use crate::{prelude::Handle, VariableId};
4
5/// Single instruction of the interpreter
6#[derive(Debug, Clone, Copy, Eq, PartialEq, num_enum::TryFromPrimitive)]
7#[repr(u8)]
8pub(crate) enum Instruction {
9    /// Add two numbers
10    Add,
11    /// Subtract two numbers
12    Sub,
13    /// Multiply two numbers
14    Mul,
15    /// Divide the first number by the second
16    Div,
17    /// Call a function provided by the runtime
18    /// Requires function name as a string as input
19    CallNative,
20    /// Push an int onto the stack
21    ScalarInt,
22    /// Push a float onto the stack
23    ScalarFloat,
24    /// Push a `nil` value onto the stack
25    ScalarNil,
26    /// Writes the strings followed by the instruction to memory and pushes the pointer pointing to
27    /// it onto the stack
28    StringLiteral,
29    /// Clones the last element on the stack
30    /// Does nothing if no elements are on the stack
31    CopyLast,
32    /// Quit the program
33    Exit,
34    /// Read bytecode position and Function arity from the program and perform a jump there.
35    CallFunction,
36    /// Compares two scalars
37    Equals,
38    /// Compares two scalars
39    NotEquals,
40    /// Is the first param less than the second?
41    Less,
42    /// Is the first param less than or equal to the second?
43    LessOrEq,
44    /// Pops the top of the stack and discards it
45    Pop,
46    /// Sets the variable at the top of the stack to the value of the second item on the stack
47    SetGlobalVar,
48    /// Reads the variable and pushes its value onto the stack
49    ReadGlobalVar,
50    /// Set the value in position given by the instruction to the value on top of the stack
51    SetLocalVar,
52    /// Read the value in position given by the instruction
53    ReadLocalVar,
54    /// Clears the last callframe's stack
55    ClearStack,
56    /// Returns to right-after-the-last-call-instruction
57    /// Also clears the stack until the last call frame
58    ///
59    /// Pops the stack and pushes the value back after clearing.
60    Return,
61    /// Swaps the last two values on the stack
62    SwapLast,
63    And,
64    Or,
65    Xor,
66    Not,
67    /// Read bytecode position and move there
68    Goto,
69    /// Pop a scalar from the stack and `goto` there if the value was
70    /// truthy
71    GotoIfTrue,
72    /// Pop a scalar from the stack and `goto` there if the value was
73    /// falsy
74    GotoIfFalse,
75    /// Creates a new Cao-Lang Table and pushes it onto the stack
76    InitTable,
77    /// Pops an Object instance from the stack, get's its value at the encoded key and pushes it's value to the stack
78    GetProperty,
79    /// Pops: `key`, `object`, `value`
80    /// Sets the value of the given `key` on the `object` to `value`
81    ///
82    /// The reason `value` is the first to be pushed is the read/setvar shorthands
83    SetProperty,
84    /// Pushes the length of the topmost table to the stack
85    /// Errors if the top Value is not a Table
86    Len,
87
88    BeginForEach,
89    ForEach,
90
91    FunctionPointer,
92    NativeFunctionPointer,
93
94    /// Get the given row in a Table
95    NthRow,
96
97    /// Append the given value to the Table
98    AppendTable,
99    /// Pop the last row from the Table
100    PopTable,
101    Closure,
102    SetUpvalue,
103    ReadUpvalue,
104    RegisterUpvalue,
105    CloseUpvalue,
106}
107
108impl Instruction {
109    /// Returns the span of this instruction in bytecode
110    #[allow(unused)]
111    pub fn span(self) -> usize {
112        let data_span = match self {
113            Instruction::CallFunction
114            | Instruction::Sub
115            | Instruction::Mul
116            | Instruction::Div
117            | Instruction::ScalarNil
118            | Instruction::CopyLast
119            | Instruction::Exit
120            | Instruction::Equals
121            | Instruction::NotEquals
122            | Instruction::Less
123            | Instruction::LessOrEq
124            | Instruction::Pop
125            | Instruction::ClearStack
126            | Instruction::Return
127            | Instruction::SwapLast
128            | Instruction::And
129            | Instruction::Or
130            | Instruction::Xor
131            | Instruction::Not
132            | Instruction::InitTable
133            | Instruction::GetProperty
134            | Instruction::SetProperty
135            | Instruction::Len
136            | Instruction::NthRow
137            | Instruction::AppendTable
138            | Instruction::PopTable
139            | Instruction::CloseUpvalue
140            | Instruction::Add => 0,
141            Instruction::CallNative => size_of::<Handle>(),
142            Instruction::ScalarInt => size_of::<i64>(),
143            Instruction::ScalarFloat => size_of::<f64>(),
144            Instruction::StringLiteral => size_of::<u32>(),
145            Instruction::NativeFunctionPointer => Instruction::StringLiteral.span(),
146            Instruction::SetGlobalVar => size_of::<VariableId>(),
147            Instruction::ReadGlobalVar => size_of::<VariableId>(),
148            Instruction::SetLocalVar
149            | Instruction::SetUpvalue
150            | Instruction::ReadUpvalue
151            | Instruction::ReadLocalVar => size_of::<u32>(),
152            Instruction::Goto | Instruction::GotoIfTrue | Instruction::GotoIfFalse => {
153                size_of::<i32>()
154            }
155            Instruction::BeginForEach => size_of::<u32>() * 5,
156            Instruction::ForEach => size_of::<u32>() * 5,
157            Instruction::FunctionPointer => size_of::<Handle>() + size_of::<u32>(),
158            Instruction::Closure => size_of::<Handle>() + size_of::<u32>(),
159            Instruction::RegisterUpvalue => size_of::<u8>() * 2,
160        };
161        1 + data_span
162    }
163}