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 analyzer
.analyze() .analyze()
.map_err(|analyzer_error| DustError::AnalyzerError { .map_err(|analysis_error| DustError::AnalysisError {
analyzer_error, analysis_error,
source, 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 { for statement in &self.abstract_tree.statements {
self.analyze_statement(statement)?; self.analyze_statement(statement)?;
} }
@ -77,7 +77,7 @@ impl<'a> Analyzer<'a> {
Ok(()) Ok(())
} }
fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalyzerError> { fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalysisError> {
match statement { match statement {
Statement::Expression(expression) => self.analyze_expression(expression)?, Statement::Expression(expression) => self.analyze_expression(expression)?,
Statement::ExpressionNullified(expression_node) => { Statement::ExpressionNullified(expression_node) => {
@ -94,7 +94,7 @@ impl<'a> Analyzer<'a> {
identifier.position, identifier.position,
); );
} else { } else {
return Err(AnalyzerError::ExpectedValue { return Err(AnalysisError::ExpectedValue {
actual: statement.clone(), actual: statement.clone(),
}); });
} }
@ -111,7 +111,7 @@ impl<'a> Analyzer<'a> {
identifier.position, identifier.position,
); );
} else { } else {
return Err(AnalyzerError::ExpectedValue { return Err(AnalysisError::ExpectedValue {
actual: statement.clone(), actual: statement.clone(),
}); });
} }
@ -135,7 +135,7 @@ impl<'a> Analyzer<'a> {
Ok(()) Ok(())
} }
fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalyzerError> { fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalysisError> {
match expression { match expression {
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner)?, Expression::Block(block_expression) => self.analyze_block(&block_expression.inner)?,
Expression::Call(call_expression) => { Expression::Call(call_expression) => {
@ -162,7 +162,7 @@ impl<'a> Analyzer<'a> {
.update_last_position(&identifier.inner, identifier.position); .update_last_position(&identifier.inner, identifier.position);
if !found { if !found {
return Err(AnalyzerError::UndefinedVariable { return Err(AnalysisError::UndefinedVariable {
identifier: identifier.clone(), identifier: identifier.clone(),
}); });
} }
@ -252,7 +252,7 @@ impl<'a> Analyzer<'a> {
.update_last_position(&name.inner, name.position); .update_last_position(&name.inner, name.position);
if !found { if !found {
return Err(AnalyzerError::UndefinedType { return Err(AnalysisError::UndefinedType {
identifier: name.clone(), identifier: name.clone(),
}); });
} }
@ -263,7 +263,7 @@ impl<'a> Analyzer<'a> {
.update_last_position(&name.inner, name.position); .update_last_position(&name.inner, name.position);
if !found { if !found {
return Err(AnalyzerError::UndefinedType { return Err(AnalysisError::UndefinedType {
identifier: name.clone(), identifier: name.clone(),
}); });
} }
@ -283,7 +283,7 @@ impl<'a> Analyzer<'a> {
Ok(()) Ok(())
} }
fn analyze_block(&mut self, block_expression: &BlockExpression) -> Result<(), AnalyzerError> { fn analyze_block(&mut self, block_expression: &BlockExpression) -> Result<(), AnalysisError> {
match block_expression { match block_expression {
BlockExpression::Async(statements) => { BlockExpression::Async(statements) => {
for statement in statements { for statement in statements {
@ -300,7 +300,7 @@ impl<'a> Analyzer<'a> {
Ok(()) Ok(())
} }
fn analyze_if(&mut self, if_expression: &IfExpression) -> Result<(), AnalyzerError> { fn analyze_if(&mut self, if_expression: &IfExpression) -> Result<(), AnalysisError> {
match if_expression { match if_expression {
IfExpression::If { IfExpression::If {
condition, condition,
@ -333,7 +333,7 @@ impl<'a> Analyzer<'a> {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum AnalyzerError { pub enum AnalysisError {
ExpectedBoolean { ExpectedBoolean {
actual: Statement, actual: Statement,
}, },
@ -389,56 +389,56 @@ pub enum AnalyzerError {
}, },
} }
impl AnalyzerError { impl AnalysisError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
AnalyzerError::ExpectedBoolean { actual } => actual.position(), AnalysisError::ExpectedBoolean { actual } => actual.position(),
AnalyzerError::ExpectedIdentifier { actual } => actual.position(), AnalysisError::ExpectedIdentifier { actual } => actual.position(),
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position(), AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(),
AnalyzerError::ExpectedIntegerOrRange { actual } => actual.position(), AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(),
AnalyzerError::ExpectedList { actual } => actual.position(), AnalysisError::ExpectedList { actual } => actual.position(),
AnalyzerError::ExpectedMap { actual } => actual.position(), AnalysisError::ExpectedMap { actual } => actual.position(),
AnalyzerError::ExpectedValue { actual } => actual.position(), AnalysisError::ExpectedValue { actual } => actual.position(),
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position, AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
AnalyzerError::IndexOutOfBounds { index, .. } => index.position(), AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
AnalyzerError::TypeConflict { AnalysisError::TypeConflict {
actual_statement, .. actual_statement, ..
} => actual_statement.position(), } => actual_statement.position(),
AnalyzerError::UndefinedField { identifier, .. } => identifier.position(), AnalysisError::UndefinedField { identifier, .. } => identifier.position(),
AnalyzerError::UndefinedType { identifier } => identifier.position, AnalysisError::UndefinedType { identifier } => identifier.position,
AnalyzerError::UndefinedVariable { identifier } => identifier.position, AnalysisError::UndefinedVariable { identifier } => identifier.position,
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position, AnalysisError::UnexpectedIdentifier { identifier } => identifier.position,
AnalyzerError::UnexectedString { actual } => actual.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 { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
AnalyzerError::ExpectedBoolean { actual, .. } => { AnalysisError::ExpectedBoolean { actual, .. } => {
write!(f, "Expected boolean, found {}", actual) write!(f, "Expected boolean, found {}", actual)
} }
AnalyzerError::ExpectedIdentifier { actual, .. } => { AnalysisError::ExpectedIdentifier { actual, .. } => {
write!(f, "Expected identifier, found {}", actual) write!(f, "Expected identifier, found {}", actual)
} }
AnalyzerError::ExpectedIdentifierOrString { actual } => { AnalysisError::ExpectedIdentifierOrString { actual } => {
write!(f, "Expected identifier or string, found {}", actual) write!(f, "Expected identifier or string, found {}", actual)
} }
AnalyzerError::ExpectedIntegerOrRange { actual, .. } => { AnalysisError::ExpectedIntegerOrRange { actual, .. } => {
write!(f, "Expected integer or range, found {}", actual) write!(f, "Expected integer or range, found {}", actual)
} }
AnalyzerError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual), AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual),
AnalyzerError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual), AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual),
AnalyzerError::ExpectedValue { actual, .. } => { AnalysisError::ExpectedValue { actual, .. } => {
write!(f, "Expected value, found {}", actual) write!(f, "Expected value, found {}", actual)
} }
AnalyzerError::ExpectedValueArgumentCount { AnalysisError::ExpectedValueArgumentCount {
expected, actual, .. expected, actual, ..
} => write!(f, "Expected {} value arguments, found {}", expected, actual), } => write!(f, "Expected {} value arguments, found {}", expected, actual),
AnalyzerError::IndexOutOfBounds { AnalysisError::IndexOutOfBounds {
list, list,
index_value, index_value,
length, length,
@ -448,7 +448,7 @@ impl Display for AnalyzerError {
"Index {} out of bounds for list {} with length {}", "Index {} out of bounds for list {} with length {}",
index_value, list, length index_value, list, length
), ),
AnalyzerError::TypeConflict { AnalysisError::TypeConflict {
actual_statement, actual_statement,
actual_type, actual_type,
expected, expected,
@ -459,22 +459,22 @@ impl Display for AnalyzerError {
expected, actual_statement, actual_type expected, actual_statement, actual_type
) )
} }
AnalyzerError::UndefinedField { AnalysisError::UndefinedField {
identifier, identifier,
statement: map, statement: map,
} => { } => {
write!(f, "Undefined field {} in map {}", identifier, map) write!(f, "Undefined field {} in map {}", identifier, map)
} }
AnalyzerError::UndefinedType { identifier } => { AnalysisError::UndefinedType { identifier } => {
write!(f, "Undefined type {}", identifier) write!(f, "Undefined type {}", identifier)
} }
AnalyzerError::UndefinedVariable { identifier } => { AnalysisError::UndefinedVariable { identifier } => {
write!(f, "Undefined variable {}", identifier) write!(f, "Undefined variable {}", identifier)
} }
AnalyzerError::UnexpectedIdentifier { identifier, .. } => { AnalysisError::UnexpectedIdentifier { identifier, .. } => {
write!(f, "Unexpected identifier {}", identifier) write!(f, "Unexpected identifier {}", identifier)
} }
AnalyzerError::UnexectedString { actual, .. } => { AnalysisError::UnexectedString { actual, .. } => {
write!(f, "Unexpected string {}", 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. /// Collects garbage up to the given position, removing all variables with lesser positions.
pub fn collect_garbage(&self, current_position: usize) { pub fn collect_garbage(&self, position: Span) {
log::trace!("Collecting garbage up to {current_position}"); log::trace!("Collecting garbage up to {position:?}");
let mut variables = self.variables.write().unwrap(); let mut variables = self.variables.write().unwrap();
variables.retain(|identifier, (_, last_used)| { 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 { if should_drop {
log::trace!("Removing {identifier}"); log::trace!("Removing {identifier}");

View File

@ -2,18 +2,18 @@
use annotate_snippets::{Level, Renderer, Snippet}; use annotate_snippets::{Level, Renderer, Snippet};
use std::fmt::Display; 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 /// An error that occurred during the execution of the Dust language and its
/// corresponding source code. /// corresponding source code.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum DustError<'src> { pub enum DustError<'src> {
VmError { VmError {
vm_error: VmError, runtime_error: RuntimeError,
source: &'src str, source: &'src str,
}, },
AnalyzerError { AnalysisError {
analyzer_error: AnalyzerError, analysis_error: AnalysisError,
source: &'src str, source: &'src str,
}, },
ParseError { ParseError {
@ -30,7 +30,7 @@ impl<'src> DustError<'src> {
pub fn title(&self) -> &'static str { pub fn title(&self) -> &'static str {
match self { match self {
DustError::VmError { .. } => "Runtime error", DustError::VmError { .. } => "Runtime error",
DustError::AnalyzerError { .. } => "Analyzer error", DustError::AnalysisError { .. } => "Analysis error",
DustError::ParseError { .. } => "Parse error", DustError::ParseError { .. } => "Parse error",
DustError::LexError { .. } => "Lex error", DustError::LexError { .. } => "Lex error",
} }
@ -38,8 +38,8 @@ impl<'src> DustError<'src> {
pub fn position(&self) -> (usize, usize) { pub fn position(&self) -> (usize, usize) {
match self { match self {
DustError::VmError { vm_error, .. } => vm_error.position(), DustError::VmError { runtime_error, .. } => runtime_error.position(),
DustError::AnalyzerError { analyzer_error, .. } => analyzer_error.position(), DustError::AnalysisError { analysis_error, .. } => analysis_error.position(),
DustError::ParseError { parse_error, .. } => parse_error.position(), DustError::ParseError { parse_error, .. } => parse_error.position(),
DustError::LexError { lex_error, .. } => lex_error.position(), DustError::LexError { lex_error, .. } => lex_error.position(),
} }
@ -48,7 +48,7 @@ impl<'src> DustError<'src> {
pub fn source(&self) -> &'src str { pub fn source(&self) -> &'src str {
match self { match self {
DustError::VmError { source, .. } => source, DustError::VmError { source, .. } => source,
DustError::AnalyzerError { source, .. } => source, DustError::AnalysisError { source, .. } => source,
DustError::ParseError { source, .. } => source, DustError::ParseError { source, .. } => source,
DustError::LexError { source, .. } => source, DustError::LexError { source, .. } => source,
} }
@ -71,8 +71,8 @@ impl<'src> DustError<'src> {
impl Display for DustError<'_> { impl Display for DustError<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
DustError::VmError { vm_error, .. } => write!(f, "{vm_error}"), DustError::VmError { runtime_error, .. } => write!(f, "{runtime_error}"),
DustError::AnalyzerError { analyzer_error, .. } => write!(f, "{analyzer_error}"), DustError::AnalysisError { analysis_error, .. } => write!(f, "{analysis_error}"),
DustError::ParseError { parse_error, .. } => write!(f, "{parse_error}"), DustError::ParseError { parse_error, .. } => write!(f, "{parse_error}"),
DustError::LexError { lex_error, .. } => write!(f, "{lex_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> { pub fn lex<'chars, 'src: 'chars>(
let mut lexer = Lexer::new(); source: &'src str,
) -> Result<Vec<(Token<'chars>, Span)>, LexError> {
let mut lexer = Lexer::new(source);
let mut tokens = Vec::new(); let mut tokens = Vec::new();
loop { loop {
let (token, span) = lexer.next_token(input)?; let (token, span) = lexer.next_token()?;
let is_eof = matches!(token, Token::Eof); let is_eof = matches!(token, Token::Eof);
tokens.push((token, span)); tokens.push((token, span));
@ -48,7 +50,6 @@ pub fn lex<'chars, 'src: 'chars>(input: &'src str) -> Result<Vec<(Token<'chars>,
Ok(tokens) Ok(tokens)
} }
#[derive(Debug, Clone)]
/// Low-level tool for lexing a single token at a time. /// Low-level tool for lexing a single token at a time.
/// ///
/// **Note**: It is a logic error to call `next_token` with different inputs. /// **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, position: usize,
} }
impl Lexer { impl<'src> Lexer<'src> {
/// Create a new lexer for the given input. /// Create a new lexer for the given input.
pub fn new() -> Self { pub fn new(source: &'src str) -> Self {
Lexer { position: 0 } Lexer {
source,
position: 0,
}
} }
/// Produce the next token. /// Produce the next token.
/// ///
/// It is a logic error to call this method with different inputs. /// 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> { pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> {
self.skip_whitespace(source); 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 { 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 { if let Some('=') = second_char {
self.position += 2; self.position += 2;
(Token::MinusEqual, (self.position - 2, self.position)) (Token::MinusEqual, (self.position - 2, self.position))
} else if let Some('0'..='9') = second_char { } else if let Some('0'..='9') = second_char {
self.lex_number(source)? self.lex_number()?
} else if "-Infinity" == self.peek_chars(source, 9) { } else if "-Infinity" == self.peek_chars(9) {
self.position += 9; self.position += 9;
( (
@ -124,11 +130,11 @@ impl Lexer {
(Token::Minus, (self.position - 1, self.position)) (Token::Minus, (self.position - 1, self.position))
} }
} }
'a'..='z' | 'A'..='Z' => self.lex_alphanumeric(source)?, 'a'..='z' | 'A'..='Z' => self.lex_alphanumeric()?,
'"' => self.lex_string('"', source)?, '"' => self.lex_string('"')?,
'\'' => self.lex_string('\'', source)?, '\'' => self.lex_string('\'')?,
'+' => { '+' => {
if let Some('=') = self.peek_second_char(source) { if let Some('=') = self.peek_second_char() {
self.position += 2; self.position += 2;
(Token::PlusEqual, (self.position - 2, self.position)) (Token::PlusEqual, (self.position - 2, self.position))
@ -154,7 +160,7 @@ impl Lexer {
(Token::RightParenthesis, (self.position - 1, self.position)) (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; self.position += 2;
(Token::DoubleEqual, (self.position - 2, self.position)) (Token::DoubleEqual, (self.position - 2, self.position))
@ -180,7 +186,7 @@ impl Lexer {
(Token::Comma, (self.position - 1, self.position)) (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; self.position += 2;
(Token::DoubleDot, (self.position - 2, self.position)) (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; self.position += 2;
(Token::GreaterEqual, (self.position - 2, self.position)) (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; self.position += 2;
(Token::LessEqual, (self.position - 2, self.position)) (Token::LessEqual, (self.position - 2, self.position))
@ -233,7 +239,7 @@ impl Lexer {
(Token::Percent, (self.position - 1, self.position)) (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; self.position += 2;
(Token::DoubleAmpersand, (self.position - 2, self.position)) (Token::DoubleAmpersand, (self.position - 2, self.position))
@ -252,7 +258,7 @@ impl Lexer {
(Token::Semicolon, (self.position - 1, self.position)) (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; self.position += 2;
(Token::DoublePipe, (self.position - 2, self.position)) (Token::DoublePipe, (self.position - 2, self.position))
@ -292,8 +298,8 @@ impl Lexer {
} }
/// Peek at the next token without consuming the source. /// Peek at the next token without consuming the source.
pub fn peek_token<'src>(&mut self, source: &'src str) -> Result<(Token<'src>, Span), LexError> { pub fn peek_token(&mut self) -> Result<(Token<'src>, Span), LexError> {
let token = self.next_token(source)?; let token = self.next_token()?;
self.position -= token.0.as_str().len(); self.position -= token.0.as_str().len();
@ -301,8 +307,8 @@ impl Lexer {
} }
/// Progress to the next character. /// Progress to the next character.
fn next_char(&mut self, source: &str) -> Option<char> { fn next_char(&mut self) -> Option<char> {
if let Some(c) = source[self.position..].chars().next() { if let Some(c) = self.source[self.position..].chars().next() {
self.position += c.len_utf8(); self.position += c.len_utf8();
Some(c) Some(c)
@ -312,10 +318,10 @@ impl Lexer {
} }
/// Skip whitespace characters. /// Skip whitespace characters.
fn skip_whitespace(&mut self, source: &str) { fn skip_whitespace(&mut self) {
while let Some(c) = self.peek_char(source) { while let Some(c) = self.peek_char() {
if c.is_whitespace() { if c.is_whitespace() {
self.next_char(source); self.next_char();
} else { } else {
break; break;
} }
@ -323,18 +329,18 @@ impl Lexer {
} }
/// Peek at the next character without consuming it. /// Peek at the next character without consuming it.
fn peek_char(&self, source: &str) -> Option<char> { fn peek_char(&self) -> Option<char> {
source[self.position..].chars().next() self.source[self.position..].chars().next()
} }
/// Peek at the second-to-next character without consuming it. /// Peek at the second-to-next character without consuming it.
fn peek_second_char(&self, source: &str) -> Option<char> { fn peek_second_char(&self) -> Option<char> {
source[self.position..].chars().nth(1) self.source[self.position..].chars().nth(1)
} }
/// Peek the next `n` characters without consuming them. /// Peek the next `n` characters without consuming them.
fn peek_chars<'src>(&self, source: &'src str, n: usize) -> &'src str { fn peek_chars(&self, n: usize) -> &'src str {
let remaining_source = &source[self.position..]; let remaining_source = &self.source[self.position..];
if remaining_source.len() < n { if remaining_source.len() < n {
remaining_source remaining_source
@ -344,32 +350,32 @@ impl Lexer {
} }
/// Lex an integer or float token. /// 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 start_pos = self.position;
let mut is_float = false; let mut is_float = false;
if let Some('-') = self.peek_char(source) { if let Some('-') = self.peek_char() {
self.next_char(source); self.next_char();
} }
while let Some(c) = self.peek_char(source) { while let Some(c) = self.peek_char() {
if c == '.' { if c == '.' {
if let Some('0'..='9') = self.peek_second_char(source) { if let Some('0'..='9') = self.peek_second_char() {
if !is_float { if !is_float {
self.next_char(source); self.next_char();
} }
self.next_char(source); self.next_char();
loop { loop {
let peek_char = self.peek_char(source); let peek_char = self.peek_char();
if let Some('0'..='9') = peek_char { if let Some('0'..='9') = peek_char {
self.next_char(source); self.next_char();
} else if let Some('e') = peek_char { } else if let Some('e') = peek_char {
if let Some('0'..='9') = self.peek_second_char(source) { if let Some('0'..='9') = self.peek_second_char() {
self.next_char(source); self.next_char();
self.next_char(source); self.next_char();
} else { } else {
break; break;
} }
@ -385,13 +391,13 @@ impl Lexer {
} }
if c.is_ascii_digit() { if c.is_ascii_digit() {
self.next_char(source); self.next_char();
} else { } else {
break; break;
} }
} }
let text = &source[start_pos..self.position]; let text = &self.source[start_pos..self.position];
if is_float { if is_float {
Ok((Token::Float(text), (start_pos, self.position))) Ok((Token::Float(text), (start_pos, self.position)))
@ -401,21 +407,18 @@ impl Lexer {
} }
/// Lex an identifier token. /// Lex an identifier token.
fn lex_alphanumeric<'src>( fn lex_alphanumeric(&mut self) -> Result<(Token<'src>, Span), LexError> {
&mut self,
source: &'src str,
) -> Result<(Token<'src>, Span), LexError> {
let start_pos = self.position; 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 == '_' { if c.is_ascii_alphanumeric() || c == '_' {
self.next_char(source); self.next_char();
} else { } else {
break; break;
} }
} }
let string = &source[start_pos..self.position]; let string = &self.source[start_pos..self.position];
let token = match string { let token = match string {
"Infinity" => Token::Float("Infinity"), "Infinity" => Token::Float("Infinity"),
"NaN" => Token::Float("NaN"), "NaN" => Token::Float("NaN"),
@ -443,36 +446,26 @@ impl Lexer {
Ok((token, (start_pos, self.position))) Ok((token, (start_pos, self.position)))
} }
fn lex_string<'src>( fn lex_string(&mut self, delimiter: char) -> Result<(Token<'src>, Span), LexError> {
&mut self,
delimiter: char,
source: &'src str,
) -> Result<(Token<'src>, Span), LexError> {
let start_pos = self.position; 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 { if c == delimiter {
self.next_char(source); self.next_char();
break; break;
} else { } 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))) Ok((Token::String(text), (start_pos, self.position)))
} }
} }
impl Default for Lexer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum LexError { pub enum LexError {
UnexpectedCharacter { character: char, position: usize }, UnexpectedCharacter { character: char, position: usize },

View File

@ -28,7 +28,7 @@ pub mod r#type;
pub mod value; pub mod value;
pub mod vm; pub mod vm;
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, AnalysisError, Analyzer};
pub use ast::{AbstractSyntaxTree, Expression, Statement}; pub use ast::{AbstractSyntaxTree, Expression, Statement};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
pub use context::{Context, VariableData}; pub use context::{Context, VariableData};
@ -39,4 +39,4 @@ pub use parser::{parse, ParseError, Parser};
pub use r#type::*; pub use r#type::*;
pub use token::{Token, TokenKind, TokenOwned}; pub use token::{Token, TokenKind, TokenOwned};
pub use value::*; 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> { pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
let lexer = Lexer::new(); let mut tree = AbstractSyntaxTree::new();
let mut parser = Parser::new(source, lexer);
let mut nodes = VecDeque::new();
loop { parse_into(source, &mut tree)?;
let node = parser
.parse_statement()
.map_err(|parse_error| DustError::ParseError {
parse_error,
source,
})?;
nodes.push_back(node); Ok(tree)
if let Token::Eof = parser.current_token {
break;
}
}
Ok(AbstractSyntaxTree { statements: nodes })
} }
pub fn parse_into<'src>( pub fn parse_into<'src>(
source: &'src str, source: &'src str,
tree: &mut AbstractSyntaxTree, tree: &mut AbstractSyntaxTree,
) -> Result<(), DustError<'src>> { ) -> Result<(), DustError<'src>> {
let lexer = Lexer::new(); let mut parser = Parser::new(source);
let mut parser = Parser::new(source, lexer);
loop { loop {
let node = parser let node = parser
@ -118,21 +102,18 @@ pub fn parse_into<'src>(
/// ///
/// ``` /// ```
pub struct Parser<'src> { pub struct Parser<'src> {
source: &'src str, lexer: Lexer<'src>,
lexer: Lexer,
current_token: Token<'src>, current_token: Token<'src>,
current_position: Span, current_position: Span,
mode: ParserMode, mode: ParserMode,
} }
impl<'src> Parser<'src> { impl<'src> Parser<'src> {
pub fn new(source: &'src str, lexer: Lexer) -> Self { pub fn new(source: &'src str) -> Self {
let mut lexer = lexer; let mut lexer = Lexer::new(source);
let (current_token, current_position) = let (current_token, current_position) = lexer.next_token().unwrap_or((Token::Eof, (0, 0)));
lexer.next_token(source).unwrap_or((Token::Eof, (0, 0)));
Parser { Parser {
source,
lexer, lexer,
current_token, current_token,
current_position, current_position,
@ -312,7 +293,7 @@ impl<'src> Parser<'src> {
} }
fn next_token(&mut self) -> Result<(), ParseError> { 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_token = token;
self.current_position = position; self.current_position = position;
@ -1106,7 +1087,7 @@ mod tests {
fn let_mut_while_loop() { fn let_mut_while_loop() {
env_logger::builder().is_test(true).try_init().ok(); 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!( assert_eq!(
parse(source), parse(source),
@ -1144,7 +1125,8 @@ mod tests {
(15, 39), (15, 39),
), ),
(15, 39) (15, 39)
)) )),
Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),),
] ]
.into() .into()
}) })

View File

@ -15,8 +15,8 @@ use serde::{
}; };
use crate::{ use crate::{
AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, StructType, AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier,
TupleType, Type, Vm, VmError, RuntimeError, StructType, TupleType, Type, Vm,
}; };
/// Dust value representation /// Dust value representation
@ -918,7 +918,7 @@ impl Function {
_type_arguments: Option<Vec<Type>>, _type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>, value_arguments: Option<Vec<Value>>,
context: &Context, context: &Context,
) -> Result<Option<Value>, VmError> { ) -> Result<Option<Value>, RuntimeError> {
let new_context = Context::with_variables_from(context); let new_context = Context::with_variables_from(context);
if let (Some(value_parameters), Some(value_arguments)) = 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 analyzer
.analyze() .analyze()
.map_err(|analyzer_error| DustError::AnalyzerError { .map_err(|analysis_error| DustError::AnalysisError {
analyzer_error, analysis_error,
source, source,
})?; })?;
let mut vm = Vm::new(abstract_syntax_tree, context); let mut vm = Vm::new(abstract_syntax_tree, context);
vm.run() vm.run().map_err(|runtime_error| DustError::VmError {
.map_err(|vm_error| DustError::VmError { vm_error, source }) runtime_error,
source,
})
} }
/// Dust virtual machine. /// 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; let mut previous_value = None;
while let Some(statement) = self.abstract_tree.statements.pop_front() { while let Some(statement) = self.abstract_tree.statements.pop_front() {
@ -103,7 +105,7 @@ impl Vm {
&self, &self,
statement: Statement, statement: Statement,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Option<Value>, VmError> { ) -> Result<Option<Value>, RuntimeError> {
let position = statement.position(); let position = statement.position();
let result = match statement { let result = match statement {
Statement::Expression(expression) => self Statement::Expression(expression) => self
@ -138,10 +140,10 @@ impl Vm {
}; };
if collect_garbage { 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), error: Box::new(error),
position, position,
}) })
@ -151,7 +153,7 @@ impl Vm {
&self, &self,
let_statement: LetStatement, let_statement: LetStatement,
collect_garbage: bool, collect_garbage: bool,
) -> Result<(), VmError> { ) -> Result<(), RuntimeError> {
match let_statement { match let_statement {
LetStatement::Let { identifier, value } => { LetStatement::Let { identifier, value } => {
let value_position = value.position(); let value_position = value.position();
@ -183,7 +185,7 @@ impl Vm {
&self, &self,
expression: Expression, expression: Expression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
let position = expression.position(); let position = expression.position();
let evaluation_result = match expression { let evaluation_result = match expression {
Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage), Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage),
@ -200,7 +202,7 @@ impl Vm {
if let Some(value) = get_value { if let Some(value) = get_value {
Ok(Evaluation::Return(Some(value))) Ok(Evaluation::Return(Some(value)))
} else { } else {
Err(VmError::UndefinedVariable { Err(RuntimeError::UndefinedVariable {
identifier: identifier.inner, identifier: identifier.inner,
position: identifier.position, position: identifier.position,
}) })
@ -242,7 +244,7 @@ impl Vm {
(Value::Integer(start), Value::Integer(end)) => { (Value::Integer(start), Value::Integer(end)) => {
Ok(Evaluation::Return(Some(Value::integer_range(start, end)))) Ok(Evaluation::Return(Some(Value::integer_range(start, end))))
} }
_ => Err(VmError::InvalidRange { _ => Err(RuntimeError::InvalidRange {
start_position, start_position,
end_position, end_position,
}), }),
@ -271,7 +273,7 @@ impl Vm {
(Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return( (Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return(
Some(Value::integer_range_inclusive(start, end)), Some(Value::integer_range_inclusive(start, end)),
)), )),
_ => Err(VmError::InvalidRange { _ => Err(RuntimeError::InvalidRange {
start_position, start_position,
end_position, end_position,
}), }),
@ -282,7 +284,7 @@ impl Vm {
Expression::TupleAccess(_) => todo!(), Expression::TupleAccess(_) => todo!(),
}; };
evaluation_result.map_err(|error| VmError::Trace { evaluation_result.map_err(|error| RuntimeError::Trace {
error: Box::new(error), error: Box::new(error),
position, position,
}) })
@ -292,7 +294,7 @@ impl Vm {
&self, &self,
operator: OperatorExpression, operator: OperatorExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
match operator { match operator {
OperatorExpression::Assignment { assignee, value } => { OperatorExpression::Assignment { assignee, value } => {
let assignee_position = assignee.position(); let assignee_position = assignee.position();
@ -306,7 +308,7 @@ impl Vm {
assignee assignee
.mutate(value) .mutate(value)
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position: assignee_position, left_position: assignee_position,
right_position: value_position, right_position: value_position,
@ -333,28 +335,28 @@ impl Vm {
ComparisonOperator::NotEqual => left_value.not_equal(&right_value), ComparisonOperator::NotEqual => left_value.not_equal(&right_value),
ComparisonOperator::GreaterThan => left_value ComparisonOperator::GreaterThan => left_value
.greater_than(&right_value) .greater_than(&right_value)
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position, left_position,
right_position, right_position,
})?, })?,
ComparisonOperator::GreaterThanOrEqual => left_value ComparisonOperator::GreaterThanOrEqual => left_value
.greater_than_or_equal(&right_value) .greater_than_or_equal(&right_value)
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position, left_position,
right_position, right_position,
})?, })?,
ComparisonOperator::LessThan => left_value ComparisonOperator::LessThan => left_value
.less_than(&right_value) .less_than(&right_value)
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position, left_position,
right_position, right_position,
})?, })?,
ComparisonOperator::LessThanOrEqual => left_value ComparisonOperator::LessThanOrEqual => left_value
.less_than_or_equal(&right_value) .less_than_or_equal(&right_value)
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position, left_position,
right_position, right_position,
@ -384,7 +386,7 @@ impl Vm {
MathOperator::Divide => assignee.divide_assign(&modifier), MathOperator::Divide => assignee.divide_assign(&modifier),
MathOperator::Modulo => assignee.modulo_assign(&modifier), MathOperator::Modulo => assignee.modulo_assign(&modifier),
} }
.map_err(|error| VmError::ValueError { .map_err(|error| RuntimeError::ValueError {
error, error,
left_position: assignee_position, left_position: assignee_position,
right_position: modifier_position, right_position: modifier_position,
@ -400,7 +402,7 @@ impl Vm {
.expect_value(position)?; .expect_value(position)?;
let integer = value let integer = value
.as_integer() .as_integer()
.ok_or(VmError::ExpectedBoolean { position })?; .ok_or(RuntimeError::ExpectedBoolean { position })?;
let negated = Value::Integer(-integer); let negated = Value::Integer(-integer);
Ok(Evaluation::Return(Some(negated))) Ok(Evaluation::Return(Some(negated)))
@ -412,7 +414,7 @@ impl Vm {
.expect_value(position)?; .expect_value(position)?;
let boolean = value let boolean = value
.as_boolean() .as_boolean()
.ok_or(VmError::ExpectedBoolean { position })?; .ok_or(RuntimeError::ExpectedBoolean { position })?;
let not = Value::Boolean(!boolean); let not = Value::Boolean(!boolean);
Ok(Evaluation::Return(Some(not))) Ok(Evaluation::Return(Some(not)))
@ -437,7 +439,7 @@ impl Vm {
MathOperator::Divide => left_value.divide(&right_value), MathOperator::Divide => left_value.divide(&right_value),
MathOperator::Modulo => left_value.modulo(&right_value), MathOperator::Modulo => left_value.modulo(&right_value),
} }
.map_err(|value_error| VmError::ValueError { .map_err(|value_error| RuntimeError::ValueError {
error: value_error, error: value_error,
left_position, left_position,
right_position, right_position,
@ -462,7 +464,7 @@ impl Vm {
LogicOperator::And => left_value.and(&right_value), LogicOperator::And => left_value.and(&right_value),
LogicOperator::Or => left_value.or(&right_value), LogicOperator::Or => left_value.or(&right_value),
} }
.map_err(|value_error| VmError::ValueError { .map_err(|value_error| RuntimeError::ValueError {
error: value_error, error: value_error,
left_position, left_position,
right_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 { match loop_expression {
LoopExpression::Infinite { block } => loop { LoopExpression::Infinite { block } => loop {
self.run_block(block.inner.clone(), false)?; self.run_block(block.inner.clone(), false)?;
@ -483,7 +485,7 @@ impl Vm {
.run_expression(condition.clone(), false)? .run_expression(condition.clone(), false)?
.expect_value(condition.position())? .expect_value(condition.position())?
.as_boolean() .as_boolean()
.ok_or_else(|| VmError::ExpectedBoolean { .ok_or_else(|| RuntimeError::ExpectedBoolean {
position: condition.position(), 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 { let value = match literal {
LiteralExpression::Boolean(boolean) => Value::Boolean(boolean), LiteralExpression::Boolean(boolean) => Value::Boolean(boolean),
LiteralExpression::Float(float) => Value::Float(float), LiteralExpression::Float(float) => Value::Float(float),
@ -515,7 +517,7 @@ impl Vm {
&self, &self,
list_index: ListIndexExpression, list_index: ListIndexExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
let ListIndexExpression { list, index } = list_index; let ListIndexExpression { list, index } = list_index;
let list_position = list.position(); let list_position = list.position();
@ -531,7 +533,7 @@ impl Vm {
let index = if let Some(index) = index_value.as_integer() { let index = if let Some(index) = index_value.as_integer() {
index as usize index as usize
} else { } else {
return Err(VmError::ExpectedInteger { return Err(RuntimeError::ExpectedInteger {
position: index_position, position: index_position,
}); });
}; };
@ -545,7 +547,7 @@ impl Vm {
&self, &self,
call_expression: CallExpression, call_expression: CallExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
let CallExpression { invoker, arguments } = call_expression; let CallExpression { invoker, arguments } = call_expression;
let invoker_position = invoker.position(); let invoker_position = invoker.position();
@ -553,7 +555,7 @@ impl Vm {
if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() { if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(RuntimeError::ExpectedValue {
position: invoker_position, position: invoker_position,
}); });
}; };
@ -561,7 +563,7 @@ impl Vm {
let function = if let Value::Function(function) = invoker_value { let function = if let Value::Function(function) = invoker_value {
function function
} else { } else {
return Err(VmError::ExpectedFunction { return Err(RuntimeError::ExpectedFunction {
actual: invoker_value, actual: invoker_value,
position: invoker_position, position: invoker_position,
}); });
@ -575,7 +577,7 @@ impl Vm {
if let Some(value) = self.run_expression(argument, collect_garbage)?.value() { if let Some(value) = self.run_expression(argument, collect_garbage)?.value() {
value_arguments.push(value); value_arguments.push(value);
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(RuntimeError::ExpectedValue { position });
} }
} }
@ -590,7 +592,7 @@ impl Vm {
&self, &self,
field_access: FieldAccessExpression, field_access: FieldAccessExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
let FieldAccessExpression { container, field } = field_access; let FieldAccessExpression { container, field } = field_access;
let container_position = container.position(); let container_position = container.position();
@ -598,7 +600,7 @@ impl Vm {
if let Some(value) = self.run_expression(container, collect_garbage)?.value() { if let Some(value) = self.run_expression(container, collect_garbage)?.value() {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(RuntimeError::ExpectedValue {
position: container_position, position: container_position,
}); });
}; };
@ -610,7 +612,7 @@ impl Vm {
&self, &self,
list_expression: ListExpression, list_expression: ListExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
match list_expression { match list_expression {
ListExpression::AutoFill { ListExpression::AutoFill {
repeat_operand, repeat_operand,
@ -621,7 +623,7 @@ impl Vm {
.run_expression(length_operand, collect_garbage)? .run_expression(length_operand, collect_garbage)?
.expect_value(position)? .expect_value(position)?
.as_integer() .as_integer()
.ok_or(VmError::ExpectedInteger { position })?; .ok_or(RuntimeError::ExpectedInteger { position })?;
let position = repeat_operand.position(); let position = repeat_operand.position();
let value = self let value = self
@ -654,7 +656,7 @@ impl Vm {
&self, &self,
block: BlockExpression, block: BlockExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
match block { match block {
BlockExpression::Async(statements) => { BlockExpression::Async(statements) => {
let final_result = Arc::new(Mutex::new(None)); let final_result = Arc::new(Mutex::new(None));
@ -694,7 +696,9 @@ impl Vm {
previous_value = self.run_statement(statement, collect_garbage)?; 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)) Ok(Evaluation::Return(previous_value))
@ -706,7 +710,7 @@ impl Vm {
&self, &self,
if_expression: IfExpression, if_expression: IfExpression,
collect_garbage: bool, collect_garbage: bool,
) -> Result<Evaluation, VmError> { ) -> Result<Evaluation, RuntimeError> {
match if_expression { match if_expression {
IfExpression::If { IfExpression::If {
condition, condition,
@ -717,7 +721,7 @@ impl Vm {
.run_expression(condition, collect_garbage)? .run_expression(condition, collect_garbage)?
.expect_value(position)? .expect_value(position)?
.as_boolean() .as_boolean()
.ok_or(VmError::ExpectedBoolean { position })?; .ok_or(RuntimeError::ExpectedBoolean { position })?;
if boolean { if boolean {
self.run_block(if_block.inner, collect_garbage)?; self.run_block(if_block.inner, collect_garbage)?;
@ -735,7 +739,7 @@ impl Vm {
.run_expression(condition, collect_garbage)? .run_expression(condition, collect_garbage)?
.expect_value(position)? .expect_value(position)?
.as_boolean() .as_boolean()
.ok_or(VmError::ExpectedBoolean { position })?; .ok_or(RuntimeError::ExpectedBoolean { position })?;
if boolean { if boolean {
self.run_block(if_block.inner, collect_garbage)?; 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 { if let Evaluation::Return(Some(value)) = self {
Ok(value) Ok(value)
} else { } else {
Err(VmError::ExpectedValue { position }) Err(RuntimeError::ExpectedValue { position })
} }
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum VmError { pub enum RuntimeError {
ParseError(ParseError), ParseError(ParseError),
Trace { Trace {
error: Box<VmError>, error: Box<RuntimeError>,
position: Span, position: Span,
}, },
ValueError { ValueError {
@ -844,7 +848,7 @@ pub enum VmError {
}, },
} }
impl VmError { impl RuntimeError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
Self::ParseError(parse_error) => parse_error.position(), 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 { fn from(error: ParseError) -> Self {
Self::ParseError(error) Self::ParseError(error)
} }
} }
impl Display for VmError { impl Display for RuntimeError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::ParseError(parse_error) => write!(f, "{}", parse_error), Self::ParseError(parse_error) => write!(f, "{}", parse_error),
@ -998,7 +1002,7 @@ mod tests {
#[test] #[test]
fn async_block() { 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)))); assert_eq!(run(input), Ok(Some(Value::Integer(1))));
} }