From fa67a568d9eb75b0400616f53fb438f46fe56ba7 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 17 Aug 2024 05:32:18 -0400 Subject: [PATCH] Pass parser tests; Fix garbage collection --- dust-lang/src/analyzer.rs | 92 +++++++++++------------ dust-lang/src/context.rs | 6 +- dust-lang/src/dust_error.rs | 20 ++--- dust-lang/src/lexer.rs | 143 +++++++++++++++++------------------- dust-lang/src/lib.rs | 4 +- dust-lang/src/parser.rs | 42 +++-------- dust-lang/src/value.rs | 6 +- dust-lang/src/vm.rs | 106 +++++++++++++------------- 8 files changed, 199 insertions(+), 220 deletions(-) diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index fda1b53..00d2d4e 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -37,8 +37,8 @@ pub fn analyze(source: &str) -> Result<(), DustError> { analyzer .analyze() - .map_err(|analyzer_error| DustError::AnalyzerError { - analyzer_error, + .map_err(|analysis_error| DustError::AnalysisError { + analysis_error, source, }) } @@ -69,7 +69,7 @@ impl<'a> Analyzer<'a> { } } - pub fn analyze(&mut self) -> Result<(), AnalyzerError> { + pub fn analyze(&mut self) -> Result<(), AnalysisError> { for statement in &self.abstract_tree.statements { self.analyze_statement(statement)?; } @@ -77,7 +77,7 @@ impl<'a> Analyzer<'a> { Ok(()) } - fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalyzerError> { + fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalysisError> { match statement { Statement::Expression(expression) => self.analyze_expression(expression)?, Statement::ExpressionNullified(expression_node) => { @@ -94,7 +94,7 @@ impl<'a> Analyzer<'a> { identifier.position, ); } else { - return Err(AnalyzerError::ExpectedValue { + return Err(AnalysisError::ExpectedValue { actual: statement.clone(), }); } @@ -111,7 +111,7 @@ impl<'a> Analyzer<'a> { identifier.position, ); } else { - return Err(AnalyzerError::ExpectedValue { + return Err(AnalysisError::ExpectedValue { actual: statement.clone(), }); } @@ -135,7 +135,7 @@ impl<'a> Analyzer<'a> { Ok(()) } - fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalyzerError> { + fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalysisError> { match expression { Expression::Block(block_expression) => self.analyze_block(&block_expression.inner)?, Expression::Call(call_expression) => { @@ -162,7 +162,7 @@ impl<'a> Analyzer<'a> { .update_last_position(&identifier.inner, identifier.position); if !found { - return Err(AnalyzerError::UndefinedVariable { + return Err(AnalysisError::UndefinedVariable { identifier: identifier.clone(), }); } @@ -252,7 +252,7 @@ impl<'a> Analyzer<'a> { .update_last_position(&name.inner, name.position); if !found { - return Err(AnalyzerError::UndefinedType { + return Err(AnalysisError::UndefinedType { identifier: name.clone(), }); } @@ -263,7 +263,7 @@ impl<'a> Analyzer<'a> { .update_last_position(&name.inner, name.position); if !found { - return Err(AnalyzerError::UndefinedType { + return Err(AnalysisError::UndefinedType { identifier: name.clone(), }); } @@ -283,7 +283,7 @@ impl<'a> Analyzer<'a> { Ok(()) } - fn analyze_block(&mut self, block_expression: &BlockExpression) -> Result<(), AnalyzerError> { + fn analyze_block(&mut self, block_expression: &BlockExpression) -> Result<(), AnalysisError> { match block_expression { BlockExpression::Async(statements) => { for statement in statements { @@ -300,7 +300,7 @@ impl<'a> Analyzer<'a> { Ok(()) } - fn analyze_if(&mut self, if_expression: &IfExpression) -> Result<(), AnalyzerError> { + fn analyze_if(&mut self, if_expression: &IfExpression) -> Result<(), AnalysisError> { match if_expression { IfExpression::If { condition, @@ -333,7 +333,7 @@ impl<'a> Analyzer<'a> { } #[derive(Clone, Debug, PartialEq)] -pub enum AnalyzerError { +pub enum AnalysisError { ExpectedBoolean { actual: Statement, }, @@ -389,56 +389,56 @@ pub enum AnalyzerError { }, } -impl AnalyzerError { +impl AnalysisError { pub fn position(&self) -> Span { match self { - AnalyzerError::ExpectedBoolean { actual } => actual.position(), - AnalyzerError::ExpectedIdentifier { actual } => actual.position(), - AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position(), - AnalyzerError::ExpectedIntegerOrRange { actual } => actual.position(), - AnalyzerError::ExpectedList { actual } => actual.position(), - AnalyzerError::ExpectedMap { actual } => actual.position(), - AnalyzerError::ExpectedValue { actual } => actual.position(), - AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position, - AnalyzerError::IndexOutOfBounds { index, .. } => index.position(), - AnalyzerError::TypeConflict { + AnalysisError::ExpectedBoolean { actual } => actual.position(), + AnalysisError::ExpectedIdentifier { actual } => actual.position(), + AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(), + AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(), + AnalysisError::ExpectedList { actual } => actual.position(), + AnalysisError::ExpectedMap { actual } => actual.position(), + AnalysisError::ExpectedValue { actual } => actual.position(), + AnalysisError::ExpectedValueArgumentCount { position, .. } => *position, + AnalysisError::IndexOutOfBounds { index, .. } => index.position(), + AnalysisError::TypeConflict { actual_statement, .. } => actual_statement.position(), - AnalyzerError::UndefinedField { identifier, .. } => identifier.position(), - AnalyzerError::UndefinedType { identifier } => identifier.position, - AnalyzerError::UndefinedVariable { identifier } => identifier.position, - AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position, - AnalyzerError::UnexectedString { actual } => actual.position(), + AnalysisError::UndefinedField { identifier, .. } => identifier.position(), + AnalysisError::UndefinedType { identifier } => identifier.position, + AnalysisError::UndefinedVariable { identifier } => identifier.position, + AnalysisError::UnexpectedIdentifier { identifier } => identifier.position, + AnalysisError::UnexectedString { actual } => actual.position(), } } } -impl Error for AnalyzerError {} +impl Error for AnalysisError {} -impl Display for AnalyzerError { +impl Display for AnalysisError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - AnalyzerError::ExpectedBoolean { actual, .. } => { + AnalysisError::ExpectedBoolean { actual, .. } => { write!(f, "Expected boolean, found {}", actual) } - AnalyzerError::ExpectedIdentifier { actual, .. } => { + AnalysisError::ExpectedIdentifier { actual, .. } => { write!(f, "Expected identifier, found {}", actual) } - AnalyzerError::ExpectedIdentifierOrString { actual } => { + AnalysisError::ExpectedIdentifierOrString { actual } => { write!(f, "Expected identifier or string, found {}", actual) } - AnalyzerError::ExpectedIntegerOrRange { actual, .. } => { + AnalysisError::ExpectedIntegerOrRange { actual, .. } => { write!(f, "Expected integer or range, found {}", actual) } - AnalyzerError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual), - AnalyzerError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual), - AnalyzerError::ExpectedValue { actual, .. } => { + AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual), + AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual), + AnalysisError::ExpectedValue { actual, .. } => { write!(f, "Expected value, found {}", actual) } - AnalyzerError::ExpectedValueArgumentCount { + AnalysisError::ExpectedValueArgumentCount { expected, actual, .. } => write!(f, "Expected {} value arguments, found {}", expected, actual), - AnalyzerError::IndexOutOfBounds { + AnalysisError::IndexOutOfBounds { list, index_value, length, @@ -448,7 +448,7 @@ impl Display for AnalyzerError { "Index {} out of bounds for list {} with length {}", index_value, list, length ), - AnalyzerError::TypeConflict { + AnalysisError::TypeConflict { actual_statement, actual_type, expected, @@ -459,22 +459,22 @@ impl Display for AnalyzerError { expected, actual_statement, actual_type ) } - AnalyzerError::UndefinedField { + AnalysisError::UndefinedField { identifier, statement: map, } => { write!(f, "Undefined field {} in map {}", identifier, map) } - AnalyzerError::UndefinedType { identifier } => { + AnalysisError::UndefinedType { identifier } => { write!(f, "Undefined type {}", identifier) } - AnalyzerError::UndefinedVariable { identifier } => { + AnalysisError::UndefinedVariable { identifier } => { write!(f, "Undefined variable {}", identifier) } - AnalyzerError::UnexpectedIdentifier { identifier, .. } => { + AnalysisError::UnexpectedIdentifier { identifier, .. } => { write!(f, "Unexpected identifier {}", identifier) } - AnalyzerError::UnexectedString { actual, .. } => { + AnalysisError::UnexectedString { actual, .. } => { write!(f, "Unexpected string {}", actual) } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index d64ab5a..3b1c348 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -93,13 +93,13 @@ impl Context { } /// Collects garbage up to the given position, removing all variables with lesser positions. - pub fn collect_garbage(&self, current_position: usize) { - log::trace!("Collecting garbage up to {current_position}"); + pub fn collect_garbage(&self, position: Span) { + log::trace!("Collecting garbage up to {position:?}"); let mut variables = self.variables.write().unwrap(); variables.retain(|identifier, (_, last_used)| { - let should_drop = current_position >= last_used.1; + let should_drop = position.0 > last_used.0 && position.1 > last_used.1; if should_drop { log::trace!("Removing {identifier}"); diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index 4b02070..76c2e44 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -2,18 +2,18 @@ use annotate_snippets::{Level, Renderer, Snippet}; use std::fmt::Display; -use crate::{AnalyzerError, LexError, ParseError, VmError}; +use crate::{AnalysisError, LexError, ParseError, RuntimeError}; /// An error that occurred during the execution of the Dust language and its /// corresponding source code. #[derive(Debug, Clone, PartialEq)] pub enum DustError<'src> { VmError { - vm_error: VmError, + runtime_error: RuntimeError, source: &'src str, }, - AnalyzerError { - analyzer_error: AnalyzerError, + AnalysisError { + analysis_error: AnalysisError, source: &'src str, }, ParseError { @@ -30,7 +30,7 @@ impl<'src> DustError<'src> { pub fn title(&self) -> &'static str { match self { DustError::VmError { .. } => "Runtime error", - DustError::AnalyzerError { .. } => "Analyzer error", + DustError::AnalysisError { .. } => "Analysis error", DustError::ParseError { .. } => "Parse error", DustError::LexError { .. } => "Lex error", } @@ -38,8 +38,8 @@ impl<'src> DustError<'src> { pub fn position(&self) -> (usize, usize) { match self { - DustError::VmError { vm_error, .. } => vm_error.position(), - DustError::AnalyzerError { analyzer_error, .. } => analyzer_error.position(), + DustError::VmError { runtime_error, .. } => runtime_error.position(), + DustError::AnalysisError { analysis_error, .. } => analysis_error.position(), DustError::ParseError { parse_error, .. } => parse_error.position(), DustError::LexError { lex_error, .. } => lex_error.position(), } @@ -48,7 +48,7 @@ impl<'src> DustError<'src> { pub fn source(&self) -> &'src str { match self { DustError::VmError { source, .. } => source, - DustError::AnalyzerError { source, .. } => source, + DustError::AnalysisError { source, .. } => source, DustError::ParseError { source, .. } => source, DustError::LexError { source, .. } => source, } @@ -71,8 +71,8 @@ impl<'src> DustError<'src> { impl Display for DustError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - DustError::VmError { vm_error, .. } => write!(f, "{vm_error}"), - DustError::AnalyzerError { analyzer_error, .. } => write!(f, "{analyzer_error}"), + DustError::VmError { runtime_error, .. } => write!(f, "{runtime_error}"), + DustError::AnalysisError { analysis_error, .. } => write!(f, "{analysis_error}"), DustError::ParseError { parse_error, .. } => write!(f, "{parse_error}"), DustError::LexError { lex_error, .. } => write!(f, "{lex_error}"), } diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 9614e96..5052dea 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -30,12 +30,14 @@ use crate::{ast::Span, Token}; /// ] /// ); /// ``` -pub fn lex<'chars, 'src: 'chars>(input: &'src str) -> Result, Span)>, LexError> { - let mut lexer = Lexer::new(); +pub fn lex<'chars, 'src: 'chars>( + source: &'src str, +) -> Result, Span)>, LexError> { + let mut lexer = Lexer::new(source); let mut tokens = Vec::new(); loop { - let (token, span) = lexer.next_token(input)?; + let (token, span) = lexer.next_token()?; let is_eof = matches!(token, Token::Eof); tokens.push((token, span)); @@ -48,7 +50,6 @@ pub fn lex<'chars, 'src: 'chars>(input: &'src str) -> Result, Ok(tokens) } -#[derive(Debug, Clone)] /// Low-level tool for lexing a single token at a time. /// /// **Note**: It is a logic error to call `next_token` with different inputs. @@ -83,35 +84,40 @@ pub fn lex<'chars, 'src: 'chars>(input: &'src str) -> Result, /// ] /// ) /// ``` -pub struct Lexer { +#[derive(Debug, Clone)] +pub struct Lexer<'src> { + source: &'src str, position: usize, } -impl Lexer { +impl<'src> Lexer<'src> { /// Create a new lexer for the given input. - pub fn new() -> Self { - Lexer { position: 0 } + pub fn new(source: &'src str) -> Self { + Lexer { + source, + position: 0, + } } /// Produce the next token. /// /// It is a logic error to call this method with different inputs. - pub fn next_token<'src>(&mut self, source: &'src str) -> Result<(Token<'src>, Span), LexError> { - self.skip_whitespace(source); + pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> { + self.skip_whitespace(); - let (token, span) = if let Some(c) = self.peek_char(source) { + let (token, span) = if let Some(c) = self.peek_char() { match c { - '0'..='9' => self.lex_number(source)?, + '0'..='9' => self.lex_number()?, '-' => { - let second_char = self.peek_second_char(source); + let second_char = self.peek_second_char(); if let Some('=') = second_char { self.position += 2; (Token::MinusEqual, (self.position - 2, self.position)) } else if let Some('0'..='9') = second_char { - self.lex_number(source)? - } else if "-Infinity" == self.peek_chars(source, 9) { + self.lex_number()? + } else if "-Infinity" == self.peek_chars(9) { self.position += 9; ( @@ -124,11 +130,11 @@ impl Lexer { (Token::Minus, (self.position - 1, self.position)) } } - 'a'..='z' | 'A'..='Z' => self.lex_alphanumeric(source)?, - '"' => self.lex_string('"', source)?, - '\'' => self.lex_string('\'', source)?, + 'a'..='z' | 'A'..='Z' => self.lex_alphanumeric()?, + '"' => self.lex_string('"')?, + '\'' => self.lex_string('\'')?, '+' => { - if let Some('=') = self.peek_second_char(source) { + if let Some('=') = self.peek_second_char() { self.position += 2; (Token::PlusEqual, (self.position - 2, self.position)) @@ -154,7 +160,7 @@ impl Lexer { (Token::RightParenthesis, (self.position - 1, self.position)) } '=' => { - if let Some('=') = self.peek_second_char(source) { + if let Some('=') = self.peek_second_char() { self.position += 2; (Token::DoubleEqual, (self.position - 2, self.position)) @@ -180,7 +186,7 @@ impl Lexer { (Token::Comma, (self.position - 1, self.position)) } '.' => { - if let Some('.') = self.peek_second_char(source) { + if let Some('.') = self.peek_second_char() { self.position += 2; (Token::DoubleDot, (self.position - 2, self.position)) @@ -191,7 +197,7 @@ impl Lexer { } } '>' => { - if let Some('=') = self.peek_second_char(source) { + if let Some('=') = self.peek_second_char() { self.position += 2; (Token::GreaterEqual, (self.position - 2, self.position)) @@ -202,7 +208,7 @@ impl Lexer { } } '<' => { - if let Some('=') = self.peek_second_char(source) { + if let Some('=') = self.peek_second_char() { self.position += 2; (Token::LessEqual, (self.position - 2, self.position)) @@ -233,7 +239,7 @@ impl Lexer { (Token::Percent, (self.position - 1, self.position)) } '&' => { - if let Some('&') = self.peek_second_char(source) { + if let Some('&') = self.peek_second_char() { self.position += 2; (Token::DoubleAmpersand, (self.position - 2, self.position)) @@ -252,7 +258,7 @@ impl Lexer { (Token::Semicolon, (self.position - 1, self.position)) } '|' => { - if let Some('|') = self.peek_second_char(source) { + if let Some('|') = self.peek_second_char() { self.position += 2; (Token::DoublePipe, (self.position - 2, self.position)) @@ -292,8 +298,8 @@ impl Lexer { } /// Peek at the next token without consuming the source. - pub fn peek_token<'src>(&mut self, source: &'src str) -> Result<(Token<'src>, Span), LexError> { - let token = self.next_token(source)?; + pub fn peek_token(&mut self) -> Result<(Token<'src>, Span), LexError> { + let token = self.next_token()?; self.position -= token.0.as_str().len(); @@ -301,8 +307,8 @@ impl Lexer { } /// Progress to the next character. - fn next_char(&mut self, source: &str) -> Option { - if let Some(c) = source[self.position..].chars().next() { + fn next_char(&mut self) -> Option { + if let Some(c) = self.source[self.position..].chars().next() { self.position += c.len_utf8(); Some(c) @@ -312,10 +318,10 @@ impl Lexer { } /// Skip whitespace characters. - fn skip_whitespace(&mut self, source: &str) { - while let Some(c) = self.peek_char(source) { + fn skip_whitespace(&mut self) { + while let Some(c) = self.peek_char() { if c.is_whitespace() { - self.next_char(source); + self.next_char(); } else { break; } @@ -323,18 +329,18 @@ impl Lexer { } /// Peek at the next character without consuming it. - fn peek_char(&self, source: &str) -> Option { - source[self.position..].chars().next() + fn peek_char(&self) -> Option { + self.source[self.position..].chars().next() } /// Peek at the second-to-next character without consuming it. - fn peek_second_char(&self, source: &str) -> Option { - source[self.position..].chars().nth(1) + fn peek_second_char(&self) -> Option { + self.source[self.position..].chars().nth(1) } /// Peek the next `n` characters without consuming them. - fn peek_chars<'src>(&self, source: &'src str, n: usize) -> &'src str { - let remaining_source = &source[self.position..]; + fn peek_chars(&self, n: usize) -> &'src str { + let remaining_source = &self.source[self.position..]; if remaining_source.len() < n { remaining_source @@ -344,32 +350,32 @@ impl Lexer { } /// Lex an integer or float token. - fn lex_number<'src>(&mut self, source: &'src str) -> Result<(Token<'src>, Span), LexError> { + fn lex_number(&mut self) -> Result<(Token<'src>, Span), LexError> { let start_pos = self.position; let mut is_float = false; - if let Some('-') = self.peek_char(source) { - self.next_char(source); + if let Some('-') = self.peek_char() { + self.next_char(); } - while let Some(c) = self.peek_char(source) { + while let Some(c) = self.peek_char() { if c == '.' { - if let Some('0'..='9') = self.peek_second_char(source) { + if let Some('0'..='9') = self.peek_second_char() { if !is_float { - self.next_char(source); + self.next_char(); } - self.next_char(source); + self.next_char(); loop { - let peek_char = self.peek_char(source); + let peek_char = self.peek_char(); if let Some('0'..='9') = peek_char { - self.next_char(source); + self.next_char(); } else if let Some('e') = peek_char { - if let Some('0'..='9') = self.peek_second_char(source) { - self.next_char(source); - self.next_char(source); + if let Some('0'..='9') = self.peek_second_char() { + self.next_char(); + self.next_char(); } else { break; } @@ -385,13 +391,13 @@ impl Lexer { } if c.is_ascii_digit() { - self.next_char(source); + self.next_char(); } else { break; } } - let text = &source[start_pos..self.position]; + let text = &self.source[start_pos..self.position]; if is_float { Ok((Token::Float(text), (start_pos, self.position))) @@ -401,21 +407,18 @@ impl Lexer { } /// Lex an identifier token. - fn lex_alphanumeric<'src>( - &mut self, - source: &'src str, - ) -> Result<(Token<'src>, Span), LexError> { + fn lex_alphanumeric(&mut self) -> Result<(Token<'src>, Span), LexError> { let start_pos = self.position; - while let Some(c) = self.peek_char(source) { + while let Some(c) = self.peek_char() { if c.is_ascii_alphanumeric() || c == '_' { - self.next_char(source); + self.next_char(); } else { break; } } - let string = &source[start_pos..self.position]; + let string = &self.source[start_pos..self.position]; let token = match string { "Infinity" => Token::Float("Infinity"), "NaN" => Token::Float("NaN"), @@ -443,36 +446,26 @@ impl Lexer { Ok((token, (start_pos, self.position))) } - fn lex_string<'src>( - &mut self, - delimiter: char, - source: &'src str, - ) -> Result<(Token<'src>, Span), LexError> { + fn lex_string(&mut self, delimiter: char) -> Result<(Token<'src>, Span), LexError> { let start_pos = self.position; - self.next_char(source); + self.next_char(); - while let Some(c) = self.peek_char(source) { + while let Some(c) = self.peek_char() { if c == delimiter { - self.next_char(source); + self.next_char(); break; } else { - self.next_char(source); + self.next_char(); } } - let text = &source[start_pos + 1..self.position - 1]; + let text = &self.source[start_pos + 1..self.position - 1]; Ok((Token::String(text), (start_pos, self.position))) } } -impl Default for Lexer { - fn default() -> Self { - Self::new() - } -} - #[derive(Debug, PartialEq, Clone)] pub enum LexError { UnexpectedCharacter { character: char, position: usize }, diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index c393cb9..1147691 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -28,7 +28,7 @@ pub mod r#type; pub mod value; pub mod vm; -pub use analyzer::{analyze, Analyzer, AnalyzerError}; +pub use analyzer::{analyze, AnalysisError, Analyzer}; pub use ast::{AbstractSyntaxTree, Expression, Statement}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use context::{Context, VariableData}; @@ -39,4 +39,4 @@ pub use parser::{parse, ParseError, Parser}; pub use r#type::*; pub use token::{Token, TokenKind, TokenOwned}; pub use value::*; -pub use vm::{run, run_with_context, Vm, VmError}; +pub use vm::{run, run_with_context, RuntimeError, Vm}; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 1b39bf8..4ebcc79 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -46,34 +46,18 @@ use crate::{ast::*, DustError, Identifier, LexError, Lexer, Token, TokenKind, To /// ); /// ``` pub fn parse(source: &str) -> Result { - let lexer = Lexer::new(); - let mut parser = Parser::new(source, lexer); - let mut nodes = VecDeque::new(); + let mut tree = AbstractSyntaxTree::new(); - loop { - let node = parser - .parse_statement() - .map_err(|parse_error| DustError::ParseError { - parse_error, - source, - })?; + parse_into(source, &mut tree)?; - nodes.push_back(node); - - if let Token::Eof = parser.current_token { - break; - } - } - - Ok(AbstractSyntaxTree { statements: nodes }) + Ok(tree) } pub fn parse_into<'src>( source: &'src str, tree: &mut AbstractSyntaxTree, ) -> Result<(), DustError<'src>> { - let lexer = Lexer::new(); - let mut parser = Parser::new(source, lexer); + let mut parser = Parser::new(source); loop { let node = parser @@ -118,21 +102,18 @@ pub fn parse_into<'src>( /// /// ``` pub struct Parser<'src> { - source: &'src str, - lexer: Lexer, + lexer: Lexer<'src>, current_token: Token<'src>, current_position: Span, mode: ParserMode, } impl<'src> Parser<'src> { - pub fn new(source: &'src str, lexer: Lexer) -> Self { - let mut lexer = lexer; - let (current_token, current_position) = - lexer.next_token(source).unwrap_or((Token::Eof, (0, 0))); + pub fn new(source: &'src str) -> Self { + let mut lexer = Lexer::new(source); + let (current_token, current_position) = lexer.next_token().unwrap_or((Token::Eof, (0, 0))); Parser { - source, lexer, current_token, current_position, @@ -312,7 +293,7 @@ impl<'src> Parser<'src> { } fn next_token(&mut self) -> Result<(), ParseError> { - let (token, position) = self.lexer.next_token(self.source)?; + let (token, position) = self.lexer.next_token()?; self.current_token = token; self.current_position = position; @@ -1106,7 +1087,7 @@ mod tests { fn let_mut_while_loop() { env_logger::builder().is_test(true).try_init().ok(); - let source = "let mut x = 0; while x < 10 { x += 1 };"; + let source = "let mut x = 0; while x < 10 { x += 1 }; x"; assert_eq!( parse(source), @@ -1144,7 +1125,8 @@ mod tests { (15, 39), ), (15, 39) - )) + )), + Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),), ] .into() }) diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 4afc5d0..a3184fc 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -15,8 +15,8 @@ use serde::{ }; use crate::{ - AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, StructType, - TupleType, Type, Vm, VmError, + AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, + RuntimeError, StructType, TupleType, Type, Vm, }; /// Dust value representation @@ -918,7 +918,7 @@ impl Function { _type_arguments: Option>, value_arguments: Option>, context: &Context, - ) -> Result, VmError> { + ) -> Result, RuntimeError> { let new_context = Context::with_variables_from(context); if let (Some(value_parameters), Some(value_arguments)) = diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 42923fb..4993445 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -58,15 +58,17 @@ pub fn run_with_context(source: &str, context: Context) -> Result, analyzer .analyze() - .map_err(|analyzer_error| DustError::AnalyzerError { - analyzer_error, + .map_err(|analysis_error| DustError::AnalysisError { + analysis_error, source, })?; let mut vm = Vm::new(abstract_syntax_tree, context); - vm.run() - .map_err(|vm_error| DustError::VmError { vm_error, source }) + vm.run().map_err(|runtime_error| DustError::VmError { + runtime_error, + source, + }) } /// Dust virtual machine. @@ -89,7 +91,7 @@ impl Vm { } } - pub fn run(&mut self) -> Result, VmError> { + pub fn run(&mut self) -> Result, RuntimeError> { let mut previous_value = None; while let Some(statement) = self.abstract_tree.statements.pop_front() { @@ -103,7 +105,7 @@ impl Vm { &self, statement: Statement, collect_garbage: bool, - ) -> Result, VmError> { + ) -> Result, RuntimeError> { let position = statement.position(); let result = match statement { Statement::Expression(expression) => self @@ -138,10 +140,10 @@ impl Vm { }; if collect_garbage { - self.context.collect_garbage(position.1); + self.context.collect_garbage(position); } - result.map_err(|error| VmError::Trace { + result.map_err(|error| RuntimeError::Trace { error: Box::new(error), position, }) @@ -151,7 +153,7 @@ impl Vm { &self, let_statement: LetStatement, collect_garbage: bool, - ) -> Result<(), VmError> { + ) -> Result<(), RuntimeError> { match let_statement { LetStatement::Let { identifier, value } => { let value_position = value.position(); @@ -183,7 +185,7 @@ impl Vm { &self, expression: Expression, collect_garbage: bool, - ) -> Result { + ) -> Result { let position = expression.position(); let evaluation_result = match expression { Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage), @@ -200,7 +202,7 @@ impl Vm { if let Some(value) = get_value { Ok(Evaluation::Return(Some(value))) } else { - Err(VmError::UndefinedVariable { + Err(RuntimeError::UndefinedVariable { identifier: identifier.inner, position: identifier.position, }) @@ -242,7 +244,7 @@ impl Vm { (Value::Integer(start), Value::Integer(end)) => { Ok(Evaluation::Return(Some(Value::integer_range(start, end)))) } - _ => Err(VmError::InvalidRange { + _ => Err(RuntimeError::InvalidRange { start_position, end_position, }), @@ -271,7 +273,7 @@ impl Vm { (Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return( Some(Value::integer_range_inclusive(start, end)), )), - _ => Err(VmError::InvalidRange { + _ => Err(RuntimeError::InvalidRange { start_position, end_position, }), @@ -282,7 +284,7 @@ impl Vm { Expression::TupleAccess(_) => todo!(), }; - evaluation_result.map_err(|error| VmError::Trace { + evaluation_result.map_err(|error| RuntimeError::Trace { error: Box::new(error), position, }) @@ -292,7 +294,7 @@ impl Vm { &self, operator: OperatorExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { match operator { OperatorExpression::Assignment { assignee, value } => { let assignee_position = assignee.position(); @@ -306,7 +308,7 @@ impl Vm { assignee .mutate(value) - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position: assignee_position, right_position: value_position, @@ -333,28 +335,28 @@ impl Vm { ComparisonOperator::NotEqual => left_value.not_equal(&right_value), ComparisonOperator::GreaterThan => left_value .greater_than(&right_value) - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position, right_position, })?, ComparisonOperator::GreaterThanOrEqual => left_value .greater_than_or_equal(&right_value) - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position, right_position, })?, ComparisonOperator::LessThan => left_value .less_than(&right_value) - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position, right_position, })?, ComparisonOperator::LessThanOrEqual => left_value .less_than_or_equal(&right_value) - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position, right_position, @@ -384,7 +386,7 @@ impl Vm { MathOperator::Divide => assignee.divide_assign(&modifier), MathOperator::Modulo => assignee.modulo_assign(&modifier), } - .map_err(|error| VmError::ValueError { + .map_err(|error| RuntimeError::ValueError { error, left_position: assignee_position, right_position: modifier_position, @@ -400,7 +402,7 @@ impl Vm { .expect_value(position)?; let integer = value .as_integer() - .ok_or(VmError::ExpectedBoolean { position })?; + .ok_or(RuntimeError::ExpectedBoolean { position })?; let negated = Value::Integer(-integer); Ok(Evaluation::Return(Some(negated))) @@ -412,7 +414,7 @@ impl Vm { .expect_value(position)?; let boolean = value .as_boolean() - .ok_or(VmError::ExpectedBoolean { position })?; + .ok_or(RuntimeError::ExpectedBoolean { position })?; let not = Value::Boolean(!boolean); Ok(Evaluation::Return(Some(not))) @@ -437,7 +439,7 @@ impl Vm { MathOperator::Divide => left_value.divide(&right_value), MathOperator::Modulo => left_value.modulo(&right_value), } - .map_err(|value_error| VmError::ValueError { + .map_err(|value_error| RuntimeError::ValueError { error: value_error, left_position, right_position, @@ -462,7 +464,7 @@ impl Vm { LogicOperator::And => left_value.and(&right_value), LogicOperator::Or => left_value.or(&right_value), } - .map_err(|value_error| VmError::ValueError { + .map_err(|value_error| RuntimeError::ValueError { error: value_error, left_position, right_position, @@ -473,7 +475,7 @@ impl Vm { } } - fn run_loop(&self, loop_expression: LoopExpression) -> Result { + fn run_loop(&self, loop_expression: LoopExpression) -> Result { match loop_expression { LoopExpression::Infinite { block } => loop { self.run_block(block.inner.clone(), false)?; @@ -483,7 +485,7 @@ impl Vm { .run_expression(condition.clone(), false)? .expect_value(condition.position())? .as_boolean() - .ok_or_else(|| VmError::ExpectedBoolean { + .ok_or_else(|| RuntimeError::ExpectedBoolean { position: condition.position(), })? { @@ -500,7 +502,7 @@ impl Vm { } } - fn run_literal(&self, literal: LiteralExpression) -> Result { + fn run_literal(&self, literal: LiteralExpression) -> Result { let value = match literal { LiteralExpression::Boolean(boolean) => Value::Boolean(boolean), LiteralExpression::Float(float) => Value::Float(float), @@ -515,7 +517,7 @@ impl Vm { &self, list_index: ListIndexExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { let ListIndexExpression { list, index } = list_index; let list_position = list.position(); @@ -531,7 +533,7 @@ impl Vm { let index = if let Some(index) = index_value.as_integer() { index as usize } else { - return Err(VmError::ExpectedInteger { + return Err(RuntimeError::ExpectedInteger { position: index_position, }); }; @@ -545,7 +547,7 @@ impl Vm { &self, call_expression: CallExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { let CallExpression { invoker, arguments } = call_expression; let invoker_position = invoker.position(); @@ -553,7 +555,7 @@ impl Vm { if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() { value } else { - return Err(VmError::ExpectedValue { + return Err(RuntimeError::ExpectedValue { position: invoker_position, }); }; @@ -561,7 +563,7 @@ impl Vm { let function = if let Value::Function(function) = invoker_value { function } else { - return Err(VmError::ExpectedFunction { + return Err(RuntimeError::ExpectedFunction { actual: invoker_value, position: invoker_position, }); @@ -575,7 +577,7 @@ impl Vm { if let Some(value) = self.run_expression(argument, collect_garbage)?.value() { value_arguments.push(value); } else { - return Err(VmError::ExpectedValue { position }); + return Err(RuntimeError::ExpectedValue { position }); } } @@ -590,7 +592,7 @@ impl Vm { &self, field_access: FieldAccessExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { let FieldAccessExpression { container, field } = field_access; let container_position = container.position(); @@ -598,7 +600,7 @@ impl Vm { if let Some(value) = self.run_expression(container, collect_garbage)?.value() { value } else { - return Err(VmError::ExpectedValue { + return Err(RuntimeError::ExpectedValue { position: container_position, }); }; @@ -610,7 +612,7 @@ impl Vm { &self, list_expression: ListExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { match list_expression { ListExpression::AutoFill { repeat_operand, @@ -621,7 +623,7 @@ impl Vm { .run_expression(length_operand, collect_garbage)? .expect_value(position)? .as_integer() - .ok_or(VmError::ExpectedInteger { position })?; + .ok_or(RuntimeError::ExpectedInteger { position })?; let position = repeat_operand.position(); let value = self @@ -654,7 +656,7 @@ impl Vm { &self, block: BlockExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { match block { BlockExpression::Async(statements) => { let final_result = Arc::new(Mutex::new(None)); @@ -694,7 +696,9 @@ impl Vm { previous_value = self.run_statement(statement, collect_garbage)?; - self.context.collect_garbage(position.1); + if collect_garbage { + self.context.collect_garbage(position); + } } Ok(Evaluation::Return(previous_value)) @@ -706,7 +710,7 @@ impl Vm { &self, if_expression: IfExpression, collect_garbage: bool, - ) -> Result { + ) -> Result { match if_expression { IfExpression::If { condition, @@ -717,7 +721,7 @@ impl Vm { .run_expression(condition, collect_garbage)? .expect_value(position)? .as_boolean() - .ok_or(VmError::ExpectedBoolean { position })?; + .ok_or(RuntimeError::ExpectedBoolean { position })?; if boolean { self.run_block(if_block.inner, collect_garbage)?; @@ -735,7 +739,7 @@ impl Vm { .run_expression(condition, collect_garbage)? .expect_value(position)? .as_boolean() - .ok_or(VmError::ExpectedBoolean { position })?; + .ok_or(RuntimeError::ExpectedBoolean { position })?; if boolean { self.run_block(if_block.inner, collect_garbage)?; @@ -765,20 +769,20 @@ impl Evaluation { } } - pub fn expect_value(self, position: Span) -> Result { + pub fn expect_value(self, position: Span) -> Result { if let Evaluation::Return(Some(value)) = self { Ok(value) } else { - Err(VmError::ExpectedValue { position }) + Err(RuntimeError::ExpectedValue { position }) } } } #[derive(Clone, Debug, PartialEq)] -pub enum VmError { +pub enum RuntimeError { ParseError(ParseError), Trace { - error: Box, + error: Box, position: Span, }, ValueError { @@ -844,7 +848,7 @@ pub enum VmError { }, } -impl VmError { +impl RuntimeError { pub fn position(&self) -> Span { match self { Self::ParseError(parse_error) => parse_error.position(), @@ -879,13 +883,13 @@ impl VmError { } } -impl From for VmError { +impl From for RuntimeError { fn from(error: ParseError) -> Self { Self::ParseError(error) } } -impl Display for VmError { +impl Display for RuntimeError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::ParseError(parse_error) => write!(f, "{}", parse_error), @@ -998,7 +1002,7 @@ mod tests { #[test] fn async_block() { - let input = "let mut x = 1; async { x += 1; x -= 1; } x"; + let input = "let x = 1; async { x += 1; x -= 1; } x"; assert_eq!(run(input), Ok(Some(Value::Integer(1)))); }