Prettify the hell out of chunk disassembly
This commit is contained in:
parent
78c9ed97e2
commit
8b33df3d4a
@ -104,7 +104,7 @@ impl Chunk {
|
|||||||
|
|
||||||
pub fn get_local(&self, index: usize, position: Span) -> Result<&Local, ChunkError> {
|
pub fn get_local(&self, index: usize, position: Span) -> Result<&Local, ChunkError> {
|
||||||
self.locals
|
self.locals
|
||||||
.get(index as usize)
|
.get(index)
|
||||||
.ok_or(ChunkError::LocalIndexOutOfBounds { index, position })
|
.ok_or(ChunkError::LocalIndexOutOfBounds { index, position })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,78 +193,8 @@ impl Chunk {
|
|||||||
self.locals.pop()
|
self.locals.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self, name: &str) -> String {
|
pub fn disassemble<'a>(&self, name: &'a str) -> DisassembledChunk<'a> {
|
||||||
let mut output = String::new();
|
DisassembledChunk::new(name, self)
|
||||||
|
|
||||||
let name_length = name.len();
|
|
||||||
let buffer_length = 51_usize.saturating_sub(name_length);
|
|
||||||
let name_buffer = " ".repeat(buffer_length / 2);
|
|
||||||
let underline = "-".repeat(name_length);
|
|
||||||
|
|
||||||
output.push_str(&format!("{name_buffer}{name}{name_buffer}\n"));
|
|
||||||
output.push_str(&format!("{name_buffer}{underline}{name_buffer}\n",));
|
|
||||||
output.push_str(" Code \n");
|
|
||||||
output.push_str("------ ---------------- -------------------- --------\n");
|
|
||||||
output.push_str("OFFSET INSTRUCTION INFO POSITION\n");
|
|
||||||
output.push_str("------ ---------------- -------------------- --------\n");
|
|
||||||
|
|
||||||
for (offset, (instruction, position)) in self.instructions.iter().enumerate() {
|
|
||||||
let display = format!(
|
|
||||||
"{offset:^6} {:37} {position}\n",
|
|
||||||
instruction.disassemble(self)
|
|
||||||
);
|
|
||||||
|
|
||||||
output.push_str(&display);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str("\n Constants\n");
|
|
||||||
output.push_str("----- ---- -----\n");
|
|
||||||
output.push_str("INDEX KIND VALUE\n");
|
|
||||||
output.push_str("----- ---- -----\n");
|
|
||||||
|
|
||||||
for (index, value_option) in self.constants.iter().enumerate() {
|
|
||||||
let value_kind_display = match value_option {
|
|
||||||
Some(Value::Raw(_)) => "RAW ",
|
|
||||||
Some(Value::Reference(_)) => "REF ",
|
|
||||||
Some(Value::Mutable(_)) => "MUT ",
|
|
||||||
None => "EMPTY",
|
|
||||||
};
|
|
||||||
let value_display = value_option
|
|
||||||
.as_ref()
|
|
||||||
.map(|value| value.to_string())
|
|
||||||
.unwrap_or_else(|| "EMPTY".to_string());
|
|
||||||
let display = format!("{index:3} {value_kind_display} {value_display}\n",);
|
|
||||||
|
|
||||||
output.push_str(&display);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str("\n Locals\n");
|
|
||||||
output.push_str("----- ---------- ----- -----\n");
|
|
||||||
output.push_str("INDEX NAME DEPTH VALUE\n");
|
|
||||||
output.push_str("----- ---------- ----- -----\n");
|
|
||||||
|
|
||||||
for (
|
|
||||||
index,
|
|
||||||
Local {
|
|
||||||
identifier,
|
|
||||||
depth,
|
|
||||||
value,
|
|
||||||
},
|
|
||||||
) in self.locals.iter().enumerate()
|
|
||||||
{
|
|
||||||
let value_display = value
|
|
||||||
.as_ref()
|
|
||||||
.map(|value| value.to_string())
|
|
||||||
.unwrap_or_else(|| "EMPTY".to_string());
|
|
||||||
|
|
||||||
let display = format!(
|
|
||||||
"{index:3} {:10} {depth:<5} {value_display}\n",
|
|
||||||
identifier.as_str()
|
|
||||||
);
|
|
||||||
output.push_str(&display);
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +243,165 @@ impl Local {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DisassembledChunk<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
body: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisassembledChunk<'_> {
|
||||||
|
pub fn new<'a>(name: &'a str, chunk: &Chunk) -> DisassembledChunk<'a> {
|
||||||
|
let mut disassembled = String::new();
|
||||||
|
let mut longest_line = 0;
|
||||||
|
|
||||||
|
disassembled.push('\n');
|
||||||
|
disassembled.push_str(&DisassembledChunk::instructions_header());
|
||||||
|
disassembled.push('\n');
|
||||||
|
|
||||||
|
for (offset, (instruction, position)) in chunk.instructions.iter().enumerate() {
|
||||||
|
let position = position.to_string();
|
||||||
|
let operation = instruction.operation.to_string();
|
||||||
|
let info_option = instruction.disassembly_info(Some(chunk));
|
||||||
|
let instruction_display = if let Some(info) = info_option {
|
||||||
|
format!("{offset:<6} {operation:16} {info:17} {position:8}\n")
|
||||||
|
} else {
|
||||||
|
format!("{offset:<6} {operation:16} {:17} {position:8}\n", " ")
|
||||||
|
};
|
||||||
|
|
||||||
|
disassembled.push_str(&instruction_display);
|
||||||
|
|
||||||
|
let line_length = instruction_display.len();
|
||||||
|
|
||||||
|
if line_length > longest_line {
|
||||||
|
longest_line = line_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut push_centered = |section: &str| {
|
||||||
|
let mut centered = String::new();
|
||||||
|
|
||||||
|
for line in section.lines() {
|
||||||
|
centered.push_str(&format!("{line:^longest_line$}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembled.push_str(¢ered);
|
||||||
|
};
|
||||||
|
|
||||||
|
push_centered("\n");
|
||||||
|
push_centered(&mut DisassembledChunk::constant_header());
|
||||||
|
|
||||||
|
for (index, value_option) in chunk.constants.iter().enumerate() {
|
||||||
|
let value_kind_display = match value_option {
|
||||||
|
Some(Value::Raw(_)) => "RAW ",
|
||||||
|
Some(Value::Reference(_)) => "REF ",
|
||||||
|
Some(Value::Mutable(_)) => "MUT ",
|
||||||
|
None => "EMPTY",
|
||||||
|
};
|
||||||
|
let value_display = value_option
|
||||||
|
.as_ref()
|
||||||
|
.map(|value| value.to_string())
|
||||||
|
.unwrap_or_else(|| "EMPTY".to_string());
|
||||||
|
let constant_display = format!("{index:<5} {value_kind_display:<4} {value_display:<5}");
|
||||||
|
|
||||||
|
push_centered(&constant_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
push_centered("\n");
|
||||||
|
push_centered(&mut DisassembledChunk::local_header());
|
||||||
|
|
||||||
|
for (
|
||||||
|
index,
|
||||||
|
Local {
|
||||||
|
identifier,
|
||||||
|
depth,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
) in chunk.locals.iter().enumerate()
|
||||||
|
{
|
||||||
|
let value_kind_display = match value {
|
||||||
|
Some(Value::Raw(_)) => "RAW ",
|
||||||
|
Some(Value::Reference(_)) => "REF ",
|
||||||
|
Some(Value::Mutable(_)) => "MUT ",
|
||||||
|
None => "EMPTY",
|
||||||
|
};
|
||||||
|
let value_display = value
|
||||||
|
.as_ref()
|
||||||
|
.map(|value| value.to_string())
|
||||||
|
.unwrap_or_else(|| "EMPTY".to_string());
|
||||||
|
let identifier_display = identifier.as_str();
|
||||||
|
let local_display =
|
||||||
|
format!("{index:<5} {identifier_display:<10} {depth:<5} {value_kind_display:<4} {value_display:<5}");
|
||||||
|
|
||||||
|
push_centered(&local_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
DisassembledChunk {
|
||||||
|
name,
|
||||||
|
body: disassembled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string_with_width(&self, width: usize) -> String {
|
||||||
|
let mut display = String::new();
|
||||||
|
|
||||||
|
for line in self.to_string().lines() {
|
||||||
|
display.push_str(&format!("{line:^width$}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
display
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_header(&self) -> String {
|
||||||
|
format!("{:^50}\n{:^50}", self.name, "==============")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instructions_header() -> String {
|
||||||
|
format!(
|
||||||
|
"{:^50}\n{:^50}\n{:<6} {:<16} {:<17} {}\n{} {} {} {}",
|
||||||
|
"Instructions",
|
||||||
|
"------------",
|
||||||
|
"OFFSET",
|
||||||
|
"INSTRUCTION",
|
||||||
|
"INFO",
|
||||||
|
"POSITION",
|
||||||
|
"------",
|
||||||
|
"----------------",
|
||||||
|
"-----------------",
|
||||||
|
"--------"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_header() -> String {
|
||||||
|
format!(
|
||||||
|
"{:^16}\n{:^16}\n{:<5} {:<4} {}\n{} {} {}",
|
||||||
|
"Constants", "---------", "INDEX", "KIND", "VALUE", "-----", "----", "-----"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_header() -> String {
|
||||||
|
format!(
|
||||||
|
"{:^50}\n{:^50}\n{:<5} {:<10} {:<5} {:<5} {:<5}\n{} {} {} {} {}",
|
||||||
|
"Locals",
|
||||||
|
"------",
|
||||||
|
"INDEX",
|
||||||
|
"IDENTIFIER",
|
||||||
|
"DEPTH",
|
||||||
|
"KIND",
|
||||||
|
"VALUE",
|
||||||
|
"-----",
|
||||||
|
"----------",
|
||||||
|
"-----",
|
||||||
|
"-----",
|
||||||
|
"-----"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DisassembledChunk<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}\n{}", self.name_header(), self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ChunkError {
|
pub enum ChunkError {
|
||||||
CodeIndexOfBounds {
|
CodeIndexOfBounds {
|
||||||
|
@ -54,17 +54,17 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn declare_variable(to_register: u8, variable_index: u16) -> Instruction {
|
pub fn declare_local(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::DeclareVariable,
|
operation: Operation::DeclareLocal,
|
||||||
destination: to_register,
|
destination: to_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_variable(to_register: u8, variable_index: u16) -> Instruction {
|
pub fn get_local(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::GetVariable,
|
operation: Operation::GetLocal,
|
||||||
destination: to_register,
|
destination: to_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ impl Instruction {
|
|||||||
|
|
||||||
pub fn set_local(from_register: u8, variable_index: u16) -> Instruction {
|
pub fn set_local(from_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::SetVariable,
|
operation: Operation::SetLocal,
|
||||||
destination: from_register,
|
destination: from_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
@ -127,200 +127,96 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self, chunk: &Chunk) -> String {
|
pub fn disassemble(&self, chunk: &Chunk) -> String {
|
||||||
match self.operation {
|
let mut disassembled = format!("{:16} ", self.operation.to_string());
|
||||||
Operation::Move => {
|
|
||||||
format!(
|
if let Some(info) = self.disassembly_info(Some(chunk)) {
|
||||||
"{:16} R({}) R({})",
|
disassembled.push_str(&info);
|
||||||
self.operation.to_string(),
|
|
||||||
self.destination,
|
|
||||||
self.arguments[0]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Operation::Close => format!("{:16} R({})", self.operation, self.destination),
|
|
||||||
|
disassembled
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> {
|
||||||
|
let info = match self.operation {
|
||||||
|
Operation::Move => {
|
||||||
|
format!("R({}) R({})", self.destination, self.arguments[0])
|
||||||
|
}
|
||||||
|
Operation::Close => format!("R({})", self.destination),
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let constant_index = u16::from_le_bytes(self.arguments) as usize;
|
let constant_index = u16::from_le_bytes(self.arguments) as usize;
|
||||||
let constant_display = match chunk.get_constant(constant_index, Span(0, 0)) {
|
|
||||||
Ok(value) => value.to_string(),
|
|
||||||
Err(error) => format!("{:?}", error),
|
|
||||||
};
|
|
||||||
|
|
||||||
format!(
|
if let Some(chunk) = chunk {
|
||||||
"{:16} R({}) = C({}) {}",
|
match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||||
self.operation.to_string(),
|
Ok(value) => {
|
||||||
self.destination,
|
format!("R({}) = C({}) {}", self.destination, constant_index, value)
|
||||||
constant_index,
|
|
||||||
constant_display
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Operation::DeclareVariable => {
|
Err(error) => format!(
|
||||||
|
"R({}) = C({}) {:?}",
|
||||||
|
self.destination, constant_index, error
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("R({}) = C({})", self.destination, constant_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Operation::DeclareLocal => {
|
||||||
let local_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
let local_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
format!(
|
format!("L({}) = R({})", local_index, self.destination)
|
||||||
"{:16} L({}) = R({})",
|
|
||||||
self.operation.to_string(),
|
|
||||||
local_index,
|
|
||||||
self.destination
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Operation::GetVariable => {
|
Operation::GetLocal => {
|
||||||
|
let local_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
|
format!("R({}) = L({})", self.destination, local_index)
|
||||||
|
}
|
||||||
|
Operation::SetLocal => {
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
format!(
|
format!("L({}) = R({})", identifier_index, self.destination)
|
||||||
"{:16} R{} = R[I({})]",
|
|
||||||
self.operation.to_string(),
|
|
||||||
self.destination,
|
|
||||||
identifier_index
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::SetVariable => {
|
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
|
||||||
|
|
||||||
format!(
|
|
||||||
"{:16} R[C({})] = R({})",
|
|
||||||
self.operation.to_string(),
|
|
||||||
identifier_index,
|
|
||||||
self.destination
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = RC({}) + RC({})",
|
"R({}) = RC({}) + RC({})",
|
||||||
self.operation.to_string(),
|
self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.destination,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = RC({}) - RC({})",
|
"R({}) = RC({}) - RC({})",
|
||||||
self.operation.to_string(),
|
self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.destination,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = RC({}) * RC({})",
|
"R({}) = RC({}) * RC({})",
|
||||||
self.operation.to_string(),
|
self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.destination,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = RC({}) / RC({})",
|
"R({}) = RC({}) / RC({})",
|
||||||
self.operation.to_string(),
|
self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.destination,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Negate => {
|
Operation::Negate => {
|
||||||
format!(
|
format!("R({}) = -RC({})", self.destination, self.arguments[0])
|
||||||
"{:16} R({}) = -RC({})",
|
|
||||||
self.operation.to_string(),
|
|
||||||
self.destination,
|
|
||||||
self.arguments[0]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Return => {
|
|
||||||
format!("{:16}", self.operation.to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Operation::Return => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Instruction {
|
impl Display for Instruction {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self.operation {
|
if let Some(info) = self.disassembly_info(None) {
|
||||||
Operation::Move => {
|
write!(f, "{} {}", self.operation, info)
|
||||||
write!(
|
} else {
|
||||||
f,
|
|
||||||
"{} R({}) R({})",
|
|
||||||
self.operation, self.destination, self.arguments[0]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Close => write!(f, "{} R({})", self.operation, self.destination),
|
|
||||||
Operation::LoadConstant => {
|
|
||||||
let constant_index = u16::from_le_bytes(self.arguments);
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = C({})",
|
|
||||||
self.operation, self.destination, constant_index
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::DeclareVariable => {
|
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} L({}) = R({})",
|
|
||||||
self.operation, identifier_index, self.destination
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::GetVariable => {
|
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R{} = R[I({})]",
|
|
||||||
self.operation, self.destination, identifier_index
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::SetVariable => {
|
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R[C({})] = R({})",
|
|
||||||
self.operation, identifier_index, self.destination
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Add => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = RC({}) + RC({})",
|
|
||||||
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Subtract => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = RC({}) - RC({})",
|
|
||||||
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Multiply => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = RC({}) * RC({})",
|
|
||||||
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Divide => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = RC({}) / RC({})",
|
|
||||||
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Negate => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} R({}) = -RC({})",
|
|
||||||
self.operation, self.destination, self.arguments[0]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operation::Return => {
|
|
||||||
write!(f, "{}", self.operation)
|
write!(f, "{}", self.operation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum Operation {
|
pub enum Operation {
|
||||||
@ -332,9 +228,9 @@ pub enum Operation {
|
|||||||
LoadConstant = 2,
|
LoadConstant = 2,
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
DeclareVariable = 3,
|
DeclareLocal = 3,
|
||||||
GetVariable = 4,
|
GetLocal = 4,
|
||||||
SetVariable = 5,
|
SetLocal = 5,
|
||||||
|
|
||||||
// Binary operations
|
// Binary operations
|
||||||
Add = 6,
|
Add = 6,
|
||||||
@ -355,9 +251,9 @@ impl From<u8> for Operation {
|
|||||||
0 => Operation::Move,
|
0 => Operation::Move,
|
||||||
1 => Operation::Close,
|
1 => Operation::Close,
|
||||||
2 => Operation::LoadConstant,
|
2 => Operation::LoadConstant,
|
||||||
3 => Operation::DeclareVariable,
|
3 => Operation::DeclareLocal,
|
||||||
4 => Operation::GetVariable,
|
4 => Operation::GetLocal,
|
||||||
5 => Operation::SetVariable,
|
5 => Operation::SetLocal,
|
||||||
6 => Operation::Add,
|
6 => Operation::Add,
|
||||||
7 => Operation::Subtract,
|
7 => Operation::Subtract,
|
||||||
8 => Operation::Multiply,
|
8 => Operation::Multiply,
|
||||||
@ -374,9 +270,9 @@ impl Display for Operation {
|
|||||||
Operation::Move => write!(f, "MOVE"),
|
Operation::Move => write!(f, "MOVE"),
|
||||||
Operation::Close => write!(f, "CLOSE"),
|
Operation::Close => write!(f, "CLOSE"),
|
||||||
Operation::LoadConstant => write!(f, "LOAD_CONSTANT"),
|
Operation::LoadConstant => write!(f, "LOAD_CONSTANT"),
|
||||||
Operation::DeclareVariable => write!(f, "DECLARE_VARIABLE"),
|
Operation::DeclareLocal => write!(f, "DECLARE_LOCAL"),
|
||||||
Operation::GetVariable => write!(f, "GET_VARIABLE"),
|
Operation::GetLocal => write!(f, "GET_LOCAL"),
|
||||||
Operation::SetVariable => write!(f, "SET_VARIABLE"),
|
Operation::SetLocal => write!(f, "SET_LOCAL"),
|
||||||
Operation::Add => write!(f, "ADD"),
|
Operation::Add => write!(f, "ADD"),
|
||||||
Operation::Subtract => write!(f, "SUBTRACT"),
|
Operation::Subtract => write!(f, "SUBTRACT"),
|
||||||
Operation::Multiply => write!(f, "MULTIPLY"),
|
Operation::Multiply => write!(f, "MULTIPLY"),
|
||||||
|
@ -138,7 +138,6 @@ impl<'src> Parser<'src> {
|
|||||||
Instruction::load_constant(self.current_register, constant_index),
|
Instruction::load_constant(self.current_register, constant_index),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
self.increment_register()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -276,8 +275,8 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
_ => self.current_register - 1,
|
_ => self.current_register - 1,
|
||||||
};
|
};
|
||||||
let last_instruction = self.chunk.pop_instruction();
|
let previous_instruction = self.chunk.pop_instruction();
|
||||||
let left_register = match last_instruction {
|
let left_register = match previous_instruction {
|
||||||
Some((
|
Some((
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::LoadConstant,
|
operation: Operation::LoadConstant,
|
||||||
@ -340,12 +339,15 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
if allow_assignment && self.allow(TokenKind::Equal)? {
|
if allow_assignment && self.allow(TokenKind::Equal)? {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::set_local(self.current_register, local_index),
|
Instruction::set_local(self.current_register, local_index),
|
||||||
self.previous_position,
|
self.previous_position,
|
||||||
);
|
);
|
||||||
self.increment_register()?;
|
} else {
|
||||||
|
self.emit_instruction(
|
||||||
|
Instruction::get_local(self.current_register, local_index),
|
||||||
|
self.previous_position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -447,7 +449,7 @@ impl<'src> Parser<'src> {
|
|||||||
let local_index = self.chunk.declare_local(identifier, position)?;
|
let local_index = self.chunk.declare_local(identifier, position)?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::declare_variable(self.current_register - 1, local_index),
|
Instruction::declare_local(self.current_register, local_index),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ fn let_statement() {
|
|||||||
Ok(Chunk::with_data(
|
Ok(Chunk::with_data(
|
||||||
vec![
|
vec![
|
||||||
(Instruction::load_constant(0, 0), Span(8, 10)),
|
(Instruction::load_constant(0, 0), Span(8, 10)),
|
||||||
(Instruction::declare_variable(1, 0), Span(4, 5)),
|
(Instruction::declare_local(1, 0), Span(4, 5)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42),],
|
vec![Value::integer(42),],
|
||||||
vec![Local::new(Identifier::new("x"), 0, None)]
|
vec![Local::new(Identifier::new("x"), 0, None)]
|
||||||
|
@ -43,20 +43,20 @@ impl Vm {
|
|||||||
|
|
||||||
self.insert(value, instruction.destination as usize, position)?;
|
self.insert(value, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::DeclareVariable => {
|
Operation::DeclareLocal => {
|
||||||
let register_index = instruction.destination as usize;
|
let register_index = instruction.destination as usize;
|
||||||
let local_index = u16::from_le_bytes(instruction.arguments) as usize;
|
let local_index = u16::from_le_bytes(instruction.arguments) as usize;
|
||||||
let value = self.clone(register_index, position)?;
|
let value = self.clone(register_index, position)?;
|
||||||
|
|
||||||
self.chunk.define_local(local_index, value, position)?;
|
self.chunk.define_local(local_index, value, position)?;
|
||||||
}
|
}
|
||||||
Operation::GetVariable => {
|
Operation::GetLocal => {
|
||||||
let identifier_index = u16::from_le_bytes(instruction.arguments) as usize;
|
let identifier_index = u16::from_le_bytes(instruction.arguments) as usize;
|
||||||
let value = self.clone(identifier_index, position)?;
|
let value = self.clone(identifier_index, position)?;
|
||||||
|
|
||||||
self.insert(value, identifier_index, position)?;
|
self.insert(value, identifier_index, position)?;
|
||||||
}
|
}
|
||||||
Operation::SetVariable => todo!(),
|
Operation::SetLocal => todo!(),
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let left =
|
let left =
|
||||||
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user