Pass parser tests; Fix garbage collection

This commit is contained in:
Jeff 2024-08-17 05:32:18 -04:00
parent b024d81148
commit fa67a568d9
8 changed files with 199 additions and 220 deletions

View File

@ -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)
}
}

View File

@ -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}");

View File

@ -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}"),
}

View File

@ -30,12 +30,14 @@ use crate::{ast::Span, Token};
/// ]
/// );
/// ```
pub fn lex<'chars, 'src: 'chars>(input: &'src str) -> Result<Vec<(Token<'chars>, Span)>, LexError> {
let mut lexer = Lexer::new();
pub fn lex<'chars, 'src: 'chars>(
source: &'src str,
) -> Result<Vec<(Token<'chars>, 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<Vec<(Token<'chars>,
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<Vec<(Token<'chars>,
/// ]
/// )
/// ```
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<char> {
if let Some(c) = source[self.position..].chars().next() {
fn next_char(&mut self) -> Option<char> {
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<char> {
source[self.position..].chars().next()
fn peek_char(&self) -> Option<char> {
self.source[self.position..].chars().next()
}
/// Peek at the second-to-next character without consuming it.
fn peek_second_char(&self, source: &str) -> Option<char> {
source[self.position..].chars().nth(1)
fn peek_second_char(&self) -> Option<char> {
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 },

View File

@ -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};

View File

@ -46,34 +46,18 @@ use crate::{ast::*, DustError, Identifier, LexError, Lexer, Token, TokenKind, To
/// );
/// ```
pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
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()
})

View File

@ -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<Vec<Type>>,
value_arguments: Option<Vec<Value>>,
context: &Context,
) -> Result<Option<Value>, VmError> {
) -> Result<Option<Value>, RuntimeError> {
let new_context = Context::with_variables_from(context);
if let (Some(value_parameters), Some(value_arguments)) =

View File

@ -58,15 +58,17 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
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<Option<Value>, VmError> {
pub fn run(&mut self) -> Result<Option<Value>, 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<Option<Value>, VmError> {
) -> Result<Option<Value>, 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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
fn run_loop(&self, loop_expression: LoopExpression) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Evaluation, VmError> {
) -> Result<Evaluation, RuntimeError> {
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<Value, VmError> {
pub fn expect_value(self, position: Span) -> Result<Value, RuntimeError> {
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<VmError>,
error: Box<RuntimeError>,
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<ParseError> for VmError {
impl From<ParseError> 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))));
}