Improve on proof of concept
This commit is contained in:
parent
97bde437e8
commit
4653a3f506
@ -252,8 +252,8 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
"",
|
||||
"Instructions",
|
||||
"------------",
|
||||
"OFFSET OPERATION INFO POSITION",
|
||||
"------- -------------- ------------------------- --------",
|
||||
"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(¢er(&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();
|
||||
|
@ -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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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)?;
|
||||
|
||||
|
@ -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!(
|
||||
|
Loading…
Reference in New Issue
Block a user