#[derive(Debug, Clone, Copy)]
#[allow(dead_code)] pub enum Opcode {
PushNumber(i32),
PushString(usize), PushVariable(usize), Pop,
StoreVariable(usize), LoadVariable(usize),
Add,
Subtract,
Multiply,
Divide,
Concat,
Print,
Input,
JumpIfTrue(usize), JumpIfFalse(usize), Jump(usize),
Equal,
NotEqual,
Return,
Halt,
}
#[derive(Debug, Clone)]
pub struct Instruction {
pub opcode: Opcode,
#[allow(dead_code)] pub line_number: usize,
}
impl Instruction {
pub fn new(opcode: Opcode, line_number: usize) -> Self {
Self { opcode, line_number }
}
}
#[derive(Debug, Clone)]
pub struct BytecodeProgram {
pub instructions: Vec<Instruction>,
pub string_pool: Vec<String>,
pub variable_names: Vec<String>,
}
impl BytecodeProgram {
pub fn new() -> Self {
Self {
instructions: Vec::new(),
string_pool: Vec::new(),
variable_names: Vec::new(),
}
}
pub fn add_instruction(&mut self, opcode: Opcode, line_number: usize) {
self.instructions.push(Instruction::new(opcode, line_number));
}
pub fn add_string(&mut self, string: String) -> usize {
for (i, s) in self.string_pool.iter().enumerate() {
if s == &string {
return i;
}
}
let index = self.string_pool.len();
self.string_pool.push(string);
index
}
pub fn add_variable(&mut self, name: String) -> usize {
for (i, var_name) in self.variable_names.iter().enumerate() {
if var_name == &name {
return i;
}
}
let index = self.variable_names.len();
self.variable_names.push(name);
index
}
}