Replace local variables with indexes to the register
This commit is contained in:
parent
a0439675b7
commit
3b7987c218
@ -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(¢er(&local_display));
|
disassembled.push_str(¢er(&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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user