2024-09-10 03:24:22 +00:00
|
|
|
use std::fmt::{self, Display, Formatter};
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
2024-09-10 22:19:59 +00:00
|
|
|
use crate::{Chunk, Span};
|
2024-09-10 03:24:22 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum Instruction {
|
|
|
|
Constant = 0,
|
|
|
|
Return = 1,
|
|
|
|
Pop = 2,
|
|
|
|
|
|
|
|
// Variables
|
2024-09-11 07:10:12 +00:00
|
|
|
DeclareVariable = 3,
|
2024-09-10 22:19:59 +00:00
|
|
|
GetVariable = 4,
|
|
|
|
SetVariable = 5,
|
2024-09-10 03:24:22 +00:00
|
|
|
|
|
|
|
// Unary
|
2024-09-10 22:19:59 +00:00
|
|
|
Negate = 6,
|
|
|
|
Not = 7,
|
2024-09-10 03:24:22 +00:00
|
|
|
|
|
|
|
// Binary
|
2024-09-10 22:19:59 +00:00
|
|
|
Add = 8,
|
|
|
|
Subtract = 9,
|
|
|
|
Multiply = 10,
|
|
|
|
Divide = 11,
|
|
|
|
Greater = 12,
|
|
|
|
Less = 13,
|
|
|
|
GreaterEqual = 14,
|
|
|
|
LessEqual = 15,
|
|
|
|
Equal = 16,
|
|
|
|
NotEqual = 17,
|
|
|
|
And = 18,
|
|
|
|
Or = 19,
|
2024-09-10 03:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Instruction {
|
|
|
|
pub fn from_byte(byte: u8) -> Option<Self> {
|
|
|
|
match byte {
|
|
|
|
0 => Some(Instruction::Constant),
|
|
|
|
1 => Some(Instruction::Return),
|
|
|
|
2 => Some(Instruction::Pop),
|
2024-09-11 07:10:12 +00:00
|
|
|
3 => Some(Instruction::DeclareVariable),
|
2024-09-10 22:19:59 +00:00
|
|
|
4 => Some(Instruction::GetVariable),
|
|
|
|
5 => Some(Instruction::SetVariable),
|
|
|
|
6 => Some(Instruction::Negate),
|
|
|
|
7 => Some(Instruction::Not),
|
|
|
|
8 => Some(Instruction::Add),
|
|
|
|
9 => Some(Instruction::Subtract),
|
|
|
|
10 => Some(Instruction::Multiply),
|
|
|
|
11 => Some(Instruction::Divide),
|
|
|
|
12 => Some(Instruction::Greater),
|
|
|
|
13 => Some(Instruction::Less),
|
|
|
|
14 => Some(Instruction::GreaterEqual),
|
|
|
|
15 => Some(Instruction::LessEqual),
|
|
|
|
16 => Some(Instruction::Equal),
|
|
|
|
17 => Some(Instruction::NotEqual),
|
|
|
|
18 => Some(Instruction::And),
|
|
|
|
19 => Some(Instruction::Or),
|
2024-09-10 03:24:22 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
|
2024-09-10 22:19:59 +00:00
|
|
|
let dummy_position = Span(0, 0);
|
|
|
|
|
2024-09-10 03:24:22 +00:00
|
|
|
match self {
|
|
|
|
Instruction::Constant => {
|
2024-09-10 22:19:59 +00:00
|
|
|
let (argument, position) = *chunk.get_code(offset + 1, dummy_position).unwrap();
|
2024-09-10 13:26:05 +00:00
|
|
|
let value_display = chunk
|
2024-09-10 22:19:59 +00:00
|
|
|
.get_constant(argument, position)
|
2024-09-10 13:26:05 +00:00
|
|
|
.map(|value| value.to_string())
|
2024-09-11 07:10:12 +00:00
|
|
|
.unwrap_or_else(|error| format!("{error:?}"));
|
2024-09-10 13:26:05 +00:00
|
|
|
|
2024-09-10 22:19:59 +00:00
|
|
|
format!("CONSTANT {value_display}")
|
2024-09-10 03:24:22 +00:00
|
|
|
}
|
2024-09-10 13:26:05 +00:00
|
|
|
Instruction::Return => "RETURN".to_string(),
|
|
|
|
Instruction::Pop => "POP".to_string(),
|
2024-09-10 03:24:22 +00:00
|
|
|
|
|
|
|
// Variables
|
2024-09-11 07:10:12 +00:00
|
|
|
Instruction::DeclareVariable => {
|
2024-09-10 22:19:59 +00:00
|
|
|
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
2024-09-11 08:22:54 +00:00
|
|
|
let identifier_display = chunk
|
|
|
|
.get_identifier(*argument)
|
|
|
|
.map(|identifier| identifier.to_string())
|
|
|
|
.unwrap_or_else(|| "ERROR".to_string());
|
2024-09-10 03:24:22 +00:00
|
|
|
|
2024-09-11 07:10:12 +00:00
|
|
|
format!("DECLARE_VARIABLE {identifier_display}")
|
2024-09-10 03:24:22 +00:00
|
|
|
}
|
|
|
|
Instruction::GetVariable => {
|
2024-09-10 22:19:59 +00:00
|
|
|
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
2024-09-11 08:22:54 +00:00
|
|
|
let identifier_display = chunk
|
|
|
|
.get_identifier(*argument)
|
|
|
|
.map(|identifier| identifier.to_string())
|
|
|
|
.unwrap_or_else(|| "ERROR".to_string());
|
2024-09-10 03:24:22 +00:00
|
|
|
|
2024-09-10 22:19:59 +00:00
|
|
|
format!("GET_VARIABLE {identifier_display}")
|
2024-09-10 03:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Instruction::SetVariable => {
|
2024-09-10 22:19:59 +00:00
|
|
|
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
2024-09-11 08:22:54 +00:00
|
|
|
let identifier_display = chunk
|
|
|
|
.get_identifier(*argument)
|
|
|
|
.map(|identifier| identifier.to_string())
|
|
|
|
.unwrap_or_else(|| "ERROR".to_string());
|
2024-09-10 03:24:22 +00:00
|
|
|
|
2024-09-10 13:26:05 +00:00
|
|
|
format!("SET_VARIABLE {identifier_display}")
|
2024-09-10 03:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Unary
|
|
|
|
Instruction::Negate => "NEGATE".to_string(),
|
|
|
|
Instruction::Not => "NOT".to_string(),
|
|
|
|
|
|
|
|
// Binary
|
|
|
|
Instruction::Add => "ADD".to_string(),
|
|
|
|
Instruction::Subtract => "SUBTRACT".to_string(),
|
|
|
|
Instruction::Multiply => "MULTIPLY".to_string(),
|
|
|
|
Instruction::Divide => "DIVIDE".to_string(),
|
|
|
|
Instruction::Greater => "GREATER".to_string(),
|
|
|
|
Instruction::Less => "LESS".to_string(),
|
|
|
|
Instruction::GreaterEqual => "GREATER_EQUAL".to_string(),
|
|
|
|
Instruction::LessEqual => "LESS_EQUAL".to_string(),
|
|
|
|
Instruction::Equal => "EQUAL".to_string(),
|
|
|
|
Instruction::NotEqual => "NOT_EQUAL".to_string(),
|
|
|
|
Instruction::And => "AND".to_string(),
|
|
|
|
Instruction::Or => "OR".to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Instruction {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{self:?}")
|
|
|
|
}
|
|
|
|
}
|
2024-09-10 14:44:15 +00:00
|
|
|
|
|
|
|
impl From<Instruction> for u8 {
|
|
|
|
fn from(instruction: Instruction) -> Self {
|
|
|
|
instruction as u8
|
|
|
|
}
|
|
|
|
}
|