Replace local variables with indexes to the register

This commit is contained in:
Jeff 2024-09-13 02:28:18 -04:00
parent a0439675b7
commit 3b7987c218
3 changed files with 36 additions and 50 deletions

View File

@ -156,17 +156,19 @@ impl Chunk {
pub fn define_local( pub fn define_local(
&mut self, &mut self,
index: usize, local_index: usize,
value: Value, register_index: u8,
position: Span, position: Span,
) -> Result<(), ChunkError> { ) -> Result<(), ChunkError> {
let local = self let local =
.locals self.locals
.get_mut(index) .get_mut(local_index)
.ok_or_else(|| ChunkError::LocalIndexOutOfBounds { index, position })?; .ok_or_else(|| ChunkError::LocalIndexOutOfBounds {
let value = value.into_reference(); index: local_index,
position,
})?;
local.value = Some(value); local.register_index = Some(register_index);
Ok(()) Ok(())
} }
@ -238,15 +240,15 @@ impl PartialEq for Chunk {
pub struct Local { pub struct Local {
pub identifier: Identifier, pub identifier: Identifier,
pub depth: usize, pub depth: usize,
pub value: Option<Value>, pub register_index: Option<u8>,
} }
impl Local { impl Local {
pub fn new(identifier: Identifier, depth: usize, value: Option<Value>) -> Self { pub fn new(identifier: Identifier, depth: usize, register_index: Option<u8>) -> Self {
Self { Self {
identifier, identifier,
depth, depth,
value, register_index,
} }
} }
} }
@ -279,8 +281,8 @@ impl<'a> ChunkDisassembler<'a> {
"", "",
"Locals", "Locals",
"------", "------",
"INDEX IDENTIFIER DEPTH KIND VALUE", "INDEX IDENTIFIER DEPTH REGISTER",
"----- ---------- ----- ----- -----", "----- ---------- ----- --------",
]; ];
/// The default width of the disassembly output. To correctly align the output, this should be /// The default width of the disassembly output. To correctly align the output, this should be
@ -297,11 +299,6 @@ impl<'a> ChunkDisassembler<'a> {
} }
pub fn disassemble(&self) -> String { pub fn disassemble(&self) -> String {
let chunk_header = self.chunk_header();
let mut disassembled = String::with_capacity(self.predict_capacity());
println!("capactity: {}", disassembled.capacity());
let center = |line: &str| format!("{line:^width$}\n", width = self.width); let center = |line: &str| format!("{line:^width$}\n", width = self.width);
let style = |line: String| { let style = |line: String| {
if self.styled { if self.styled {
@ -311,9 +308,12 @@ impl<'a> ChunkDisassembler<'a> {
} }
}; };
for line in chunk_header.iter() { let name_line = style(center(&format!("Chunk Disassembly: {}", self.name)));
disassembled.push_str(&style(center(line))); let mut disassembled = String::with_capacity(self.predict_capacity());
}
println!("capactity: {}", disassembled.capacity());
disassembled.push_str(&name_line);
for line in Self::INSTRUCTION_HEADER { for line in Self::INSTRUCTION_HEADER {
disassembled.push_str(&style(center(line))); disassembled.push_str(&style(center(line)));
@ -360,22 +360,17 @@ impl<'a> ChunkDisassembler<'a> {
Local { Local {
identifier, identifier,
depth, depth,
value: value_option, register_index,
}, },
) in self.chunk.locals.iter().enumerate() ) in self.chunk.locals.iter().enumerate()
{ {
let value_kind_display = if let Some(value) = value_option { let register_display = register_index
value.kind().to_string()
} else {
"empty".to_string()
};
let value_display = value_option
.as_ref() .as_ref()
.map(|value| value.to_string()) .map(|value| value.to_string())
.unwrap_or_else(|| "EMPTY".to_string()); .unwrap_or_else(|| "EMPTY".to_string());
let identifier_display = identifier.as_str(); let identifier_display = identifier.as_str();
let local_display = let local_display =
format!("{index:<5} {identifier_display:<10} {depth:<5} {value_kind_display:<4} {value_display:<5}"); format!("{index:<5} {identifier_display:<10} {depth:<5} {register_display:<8}");
disassembled.push_str(&center(&local_display)); disassembled.push_str(&center(&local_display));
} }
@ -397,19 +392,6 @@ impl<'a> ChunkDisassembler<'a> {
self self
} }
fn chunk_header(&self) -> [String; 3] {
[
self.name.to_string(),
"=".repeat(self.name.len()),
format!(
"{} instructions, {} constants, {} locals",
self.chunk.instructions.len(),
self.chunk.constants.len(),
self.chunk.locals.len()
),
]
}
/// Predicts the capacity of the disassembled output. This is used to pre-allocate the string /// Predicts the capacity of the disassembled output. This is used to pre-allocate the string
/// buffer to avoid reallocations. /// buffer to avoid reallocations.
/// ///
@ -419,6 +401,8 @@ impl<'a> ChunkDisassembler<'a> {
/// - Add 1 to the width to account for the newline character /// - Add 1 to the width to account for the newline character
/// - Multiply the total number of lines by the width of the disassembly output /// - Multiply the total number of lines by the width of the disassembly output
fn predict_capacity(&self) -> usize { fn predict_capacity(&self) -> usize {
const EXTRA_LINES: usize = 1;
let chunk_header_line_count = 3; // self.chunk_header().len() is hard-coded to 3 let chunk_header_line_count = 3; // self.chunk_header().len() is hard-coded to 3
let static_line_count = chunk_header_line_count let static_line_count = chunk_header_line_count
+ Self::INSTRUCTION_HEADER.len() + Self::INSTRUCTION_HEADER.len()
@ -426,9 +410,9 @@ impl<'a> ChunkDisassembler<'a> {
+ Self::LOCAL_HEADER.len(); + Self::LOCAL_HEADER.len();
let dynamic_line_count = let dynamic_line_count =
self.chunk.instructions.len() + self.chunk.constants.len() + self.chunk.locals.len(); self.chunk.instructions.len() + self.chunk.constants.len() + self.chunk.locals.len();
let total_line_count = static_line_count + dynamic_line_count; let total_line_count = static_line_count + dynamic_line_count + EXTRA_LINES;
total_line_count * (self.width + 1) total_line_count * (self.width)
} }
} }

View File

@ -55,18 +55,17 @@ impl Vm {
self.insert(value, to_register, position)?; self.insert(value, to_register, position)?;
} }
Operation::DeclareLocal => { Operation::DeclareLocal => {
let from_register = instruction.destination as usize; let from_register = instruction.destination;
let to_local = u16::from_le_bytes(instruction.arguments) as usize; let to_local = u16::from_le_bytes(instruction.arguments) as usize;
let value = self.clone(from_register, position)?;
self.chunk.define_local(to_local, value, position)?; self.chunk.define_local(to_local, from_register, position)?;
} }
Operation::GetLocal => { Operation::GetLocal => {
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 local = self.chunk.get_local(local_index, position)?; let local = self.chunk.get_local(local_index, position)?;
let value = if let Some(value) = &local.value { let value = if let Some(value_index) = &local.register_index {
value.clone() self.clone(*value_index as usize, position)?
} else { } else {
return Err(VmError::UndefinedVariable { return Err(VmError::UndefinedVariable {
identifier: local.identifier.clone(), identifier: local.identifier.clone(),

View File

@ -60,7 +60,10 @@ fn main() {
fn parse_and_display_errors(source: &str) { fn parse_and_display_errors(source: &str) {
match parse(source) { match parse(source) {
Ok(chunk) => println!("{}", chunk.disassembler("Dust CLI Input").disassemble()), Ok(chunk) => println!(
"{}",
chunk.disassembler("Dust CLI Input").styled().disassemble()
),
Err(error) => { Err(error) => {
eprintln!("{}", error.report()); eprintln!("{}", error.report());
} }