1
0

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

@ -253,7 +253,7 @@ impl<'a> ChunkDisassembler<'a> {
"Instructions",
"------------",
"OFFSET OPERATION INFO POSITION",
"------- -------------- ------------------------- --------",
"------ -------------- ------------------------- --------",
];
const CONSTANT_HEADER: [&'static str; 5] = [
@ -312,6 +312,22 @@ impl<'a> ChunkDisassembler<'a> {
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 {
disassembled.push_str(&style(center(line)));
}
@ -321,9 +337,9 @@ impl<'a> ChunkDisassembler<'a> {
let operation = instruction.operation().to_string();
let info_option = instruction.disassembly_info(Some(self.chunk));
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 {
format!("{offset:<7} {operation:14} {:25} {position:8}", " ")
format!("{offset:<6} {operation:14} {:25} {position:8}", " ")
};
disassembled.push_str(&center(&instruction_display));
@ -396,14 +412,14 @@ impl<'a> ChunkDisassembler<'a> {
/// 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 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
///
/// 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
/// case.
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 =
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> {
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> {
@ -256,12 +265,21 @@ impl<'src> Parser<'src> {
self.parse(rule.precedence.increment())?;
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) =
self.chunk.pop_instruction(self.current_position)?;
let right = match right_instruction.operation() {
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()
}
_ => {
@ -270,19 +288,27 @@ impl<'src> Parser<'src> {
self.current_register - 1
}
};
let mut push_back_left = false;
let (left_instruction, left_position) =
self.chunk.pop_instruction(self.current_position)?;
let left = match left_instruction.operation() {
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()
}
_ => {
push_back_left = true;
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();
}
if !push_back_right {
if right_is_constant {
instruction.set_second_argument_to_constant();
}
@ -510,7 +536,7 @@ impl<'src> Parser<'src> {
position: self.previous_position,
});
};
let allow_assignment = precedence <= Precedence::Assignment;
let allow_assignment = precedence < Precedence::Assignment;
prefix_parser(self, allow_assignment)?;

View File

@ -2,6 +2,30 @@ use crate::Local;
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]
fn let_statement() {
assert_eq!(