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
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}");
|
||||||
|
@ -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}"),
|
||||||
}
|
}
|
||||||
|
@ -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 },
|
||||||
|
@ -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};
|
||||||
|
@ -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()
|
||||||
})
|
})
|
||||||
|
@ -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)) =
|
||||||
|
@ -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))));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user