From 4653a3f506215bf79f78918590da6e1589879271 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 15 Sep 2024 04:25:24 -0400 Subject: [PATCH] Improve on proof of concept --- dust-lang/src/chunk.rs | 28 ++++++++++++++++++----- dust-lang/src/parser/mod.rs | 42 ++++++++++++++++++++++++++++------- dust-lang/src/parser/tests.rs | 24 ++++++++++++++++++++ 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 6b85f28..d7863a3 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -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(); diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index 4af4326..9a428c2 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -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)?; diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index d081901..4a1ce40 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -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!(