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}