Improve on proof of concept

This commit is contained in:
Jeff 2024-09-15 04:25:24 -04:00
parent 97bde437e8
commit 4653a3f506
3 changed files with 80 additions and 14 deletions

View File

@ -252,8 +252,8 @@ impl<'a> ChunkDisassembler<'a> {
"", "",
"Instructions", "Instructions",
"------------", "------------",
"OFFSET OPERATION INFO POSITION", "OFFSET OPERATION INFO POSITION",
"------- -------------- ------------------------- --------", "------ -------------- ------------------------- --------",
]; ];
const CONSTANT_HEADER: [&'static str; 5] = [ const CONSTANT_HEADER: [&'static str; 5] = [
@ -312,6 +312,22 @@ impl<'a> ChunkDisassembler<'a> {
disassembled.push_str(&name_line); disassembled.push_str(&name_line);
let info_line = center(&format!(
"{} instructions, {} constants, {} locals",
self.chunk.instructions.len(),
self.chunk.constants.len(),
self.chunk.locals.len()
));
let styled_info_line = {
if self.styled {
info_line.bold().dimmed().to_string()
} else {
info_line
}
};
disassembled.push_str(&styled_info_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)));
} }
@ -321,9 +337,9 @@ impl<'a> ChunkDisassembler<'a> {
let operation = instruction.operation().to_string(); let operation = instruction.operation().to_string();
let info_option = instruction.disassembly_info(Some(self.chunk)); let info_option = instruction.disassembly_info(Some(self.chunk));
let instruction_display = if let Some(info) = info_option { let instruction_display = if let Some(info) = info_option {
format!("{offset:<7} {operation:14} {info:25} {position:8}") format!("{offset:<6} {operation:14} {info:25} {position:8}")
} else { } else {
format!("{offset:<7} {operation:14} {:25} {position:8}", " ") format!("{offset:<6} {operation:14} {:25} {position:8}", " ")
}; };
disassembled.push_str(&center(&instruction_display)); disassembled.push_str(&center(&instruction_display));
@ -396,14 +412,14 @@ impl<'a> ChunkDisassembler<'a> {
/// The capacity is calculated as follows: /// The capacity is calculated as follows:
/// - Get the number of static lines, i.e. lines that are always present in the disassembly /// - Get the number of static lines, i.e. lines that are always present in the disassembly
/// - Get the number of dynamic lines, i.e. lines that are generated from the chunk /// - Get the number of dynamic lines, i.e. lines that are generated from the chunk
/// - Add 1 to the width to account for the newline character /// - Add an one 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
/// ///
/// The result is accurate only if the output is not styled. Otherwise the extra bytes added by /// The result is accurate only if the output is not styled. Otherwise the extra bytes added by
/// the ANSI escape codes will make the result too low. It still works as a lower bound in that /// the ANSI escape codes will make the result too low. It still works as a lower bound in that
/// case. /// case.
fn predict_length(&self) -> usize { fn predict_length(&self) -> usize {
const EXTRA_LINES: usize = 1; // There is one empty line after the name of the chunk const EXTRA_LINES: usize = 2; // There is one empty line after the name of the chunk
let static_line_count = let static_line_count =
Self::INSTRUCTION_HEADER.len() + Self::CONSTANT_HEADER.len() + Self::LOCAL_HEADER.len(); Self::INSTRUCTION_HEADER.len() + Self::CONSTANT_HEADER.len() + Self::LOCAL_HEADER.len();

View File

@ -223,7 +223,16 @@ impl<'src> Parser<'src> {
fn parse_grouped(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_grouped(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
self.parse_expression()?; self.parse_expression()?;
self.expect(TokenKind::RightParenthesis)
if self.previous_token == Token::RightParenthesis {
Ok(())
} else {
Err(ParseError::ExpectedToken {
expected: TokenKind::RightParenthesis,
found: self.current_token.to_owned(),
position: self.current_position,
})
}
} }
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
@ -256,12 +265,21 @@ impl<'src> Parser<'src> {
self.parse(rule.precedence.increment())?; self.parse(rule.precedence.increment())?;
let mut push_back_right = false; let mut push_back_right = false;
let mut push_back_left = false;
let mut right_is_constant = false;
let mut left_is_constant = false;
let (right_instruction, right_position) = let (right_instruction, right_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let right = match right_instruction.operation() { let right = match right_instruction.operation() {
Operation::LoadConstant => { Operation::LoadConstant => {
self.decrement_register()?; right_is_constant = true;
self.decrement_register()?;
right_instruction.first_argument()
}
Operation::GetLocal => {
self.decrement_register()?;
right_instruction.first_argument() right_instruction.first_argument()
} }
_ => { _ => {
@ -270,19 +288,27 @@ impl<'src> Parser<'src> {
self.current_register - 1 self.current_register - 1
} }
}; };
let mut push_back_left = false;
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let left = match left_instruction.operation() { let left = match left_instruction.operation() {
Operation::LoadConstant => { Operation::LoadConstant => {
self.decrement_register()?; left_is_constant = true;
self.decrement_register()?;
left_instruction.first_argument()
}
Operation::GetLocal => {
self.decrement_register()?;
left_instruction.first_argument() left_instruction.first_argument()
} }
_ => { _ => {
push_back_left = true; push_back_left = true;
self.current_register - 2 if push_back_right {
self.current_register - 2
} else {
self.current_register - 1
}
} }
}; };
@ -313,11 +339,11 @@ impl<'src> Parser<'src> {
} }
}; };
if !push_back_left { if left_is_constant {
instruction.set_first_argument_to_constant(); instruction.set_first_argument_to_constant();
} }
if !push_back_right { if right_is_constant {
instruction.set_second_argument_to_constant(); instruction.set_second_argument_to_constant();
} }
@ -510,7 +536,7 @@ impl<'src> Parser<'src> {
position: self.previous_position, position: self.previous_position,
}); });
}; };
let allow_assignment = precedence <= Precedence::Assignment; let allow_assignment = precedence < Precedence::Assignment;
prefix_parser(self, allow_assignment)?; prefix_parser(self, allow_assignment)?;

View File

@ -2,6 +2,30 @@ use crate::Local;
use super::*; use super::*;
#[test]
fn add_multiply_precedence() {
assert_eq!(
parse("1 + 2 * 3"),
Ok(Chunk::with_data(
vec![
(
*Instruction::multiply(0, 1, 2)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(6, 7)
),
(
*Instruction::add(1, 0, 0).set_first_argument_to_constant(),
Span(2, 3)
),
(Instruction::r#return(), Span(0, 9)),
],
vec![Value::integer(1), Value::integer(2), Value::integer(3)],
vec![]
))
);
}
#[test] #[test]
fn let_statement() { fn let_statement() {
assert_eq!( assert_eq!(