Improve on proof of concept
This commit is contained in:
parent
97bde437e8
commit
4653a3f506
@ -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(¢er(&instruction_display));
|
disassembled.push_str(¢er(&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();
|
||||||
|
@ -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)?;
|
||||||
|
|
||||||
|
@ -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!(
|
||||||
|
Loading…
Reference in New Issue
Block a user