Pass parser tests; Fix garbage collection
This commit is contained in:
parent
b024d81148
commit
fa67a568d9
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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}");
|
||||
|
@ -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}"),
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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};
|
||||
|
@ -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()
|
||||
})
|
||||
|
@ -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)) =
|
||||
|
@ -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))));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user