Implement block scopes; Refactor async block execution
This commit is contained in:
parent
511cc10e98
commit
561a290b16
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
collections::{HashMap, VecDeque},
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1131,15 +1131,15 @@ impl Display for ElseExpression {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum BlockExpression {
|
pub enum BlockExpression {
|
||||||
Async(Vec<Statement>),
|
Async(VecDeque<Statement>),
|
||||||
Sync(Vec<Statement>),
|
Sync(VecDeque<Statement>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockExpression {
|
impl BlockExpression {
|
||||||
fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
|
fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
|
||||||
match self {
|
match self {
|
||||||
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
|
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
|
||||||
if let Some(statement) = statements.last() {
|
if let Some(statement) = statements.back() {
|
||||||
statement.type_evaluation(context)
|
statement.type_evaluation(context)
|
||||||
} else {
|
} else {
|
||||||
Ok(TypeEvaluation::Return(None))
|
Ok(TypeEvaluation::Return(None))
|
||||||
|
@ -30,7 +30,7 @@ impl AbstractSyntaxTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_statements<const LEN: usize>(statements: [Statement; LEN]) -> Self {
|
pub fn with_statements<T: Into<VecDeque<Statement>>>(statements: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
statements: statements.into(),
|
statements: statements.into(),
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
//! - `parse` convenience function
|
//! - `parse` convenience function
|
||||||
//! - `Parser` struct, which parses the input a statement at a time
|
//! - `Parser` struct, which parses the input a statement at a time
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
num::{ParseFloatError, ParseIntError},
|
num::{ParseFloatError, ParseIntError},
|
||||||
str::ParseBoolError,
|
str::ParseBoolError,
|
||||||
@ -994,7 +995,7 @@ impl<'src> Parser<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut statements = Vec::new();
|
let mut statements = VecDeque::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Token::RightCurlyBrace = self.current_token {
|
if let Token::RightCurlyBrace = self.current_token {
|
||||||
@ -1011,7 +1012,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
let statement = self.parse_statement()?;
|
let statement = self.parse_statement()?;
|
||||||
|
|
||||||
statements.push(statement);
|
statements.push_back(statement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,10 +1178,9 @@ mod tests {
|
|||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::Expression(Expression::infinite_loop(
|
Statement::Expression(Expression::infinite_loop(
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::ExpressionNullified(Node::new(
|
BlockExpression::Sync(VecDeque::from([Statement::ExpressionNullified(
|
||||||
Expression::r#break(None, (7, 12)),
|
Node::new(Expression::r#break(None, (7, 12)), (7, 13))
|
||||||
(7, 13)
|
)])),
|
||||||
))]),
|
|
||||||
(5, 15)
|
(5, 15)
|
||||||
),
|
),
|
||||||
(0, 15)
|
(0, 15)
|
||||||
@ -1262,14 +1262,14 @@ mod tests {
|
|||||||
(21, 27),
|
(21, 27),
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::compound_assignment(
|
Expression::compound_assignment(
|
||||||
Expression::identifier(Identifier::new("x"), (30, 31)),
|
Expression::identifier(Identifier::new("x"), (30, 31)),
|
||||||
Node::new(MathOperator::Add, (32, 34)),
|
Node::new(MathOperator::Add, (32, 34)),
|
||||||
Expression::literal(1, (35, 36)),
|
Expression::literal(1, (35, 36)),
|
||||||
(30, 36),
|
(30, 36),
|
||||||
),
|
),
|
||||||
)]),
|
)])),
|
||||||
(28, 38),
|
(28, 38),
|
||||||
),
|
),
|
||||||
(15, 38),
|
(15, 38),
|
||||||
@ -1328,7 +1328,7 @@ mod tests {
|
|||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
statements: [Statement::Expression(Expression::block(
|
statements: [Statement::Expression(Expression::block(
|
||||||
BlockExpression::Async(vec![
|
BlockExpression::Async(VecDeque::from([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::operator(
|
Expression::operator(
|
||||||
OperatorExpression::Assignment {
|
OperatorExpression::Assignment {
|
||||||
@ -1346,7 +1346,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
(16, 23)
|
(16, 23)
|
||||||
))
|
))
|
||||||
]),
|
])),
|
||||||
(0, 25)
|
(0, 25)
|
||||||
))]
|
))]
|
||||||
.into()
|
.into()
|
||||||
@ -1645,9 +1645,9 @@ mod tests {
|
|||||||
IfExpression::If {
|
IfExpression::If {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Expression::identifier(Identifier::new("y"), (7, 8))
|
||||||
)]),
|
)])),
|
||||||
(5, 10)
|
(5, 10)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -1668,15 +1668,15 @@ mod tests {
|
|||||||
IfExpression::IfElse {
|
IfExpression::IfElse {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Expression::identifier(Identifier::new("y"), (7, 8))
|
||||||
)]),
|
)])),
|
||||||
(5, 10)
|
(5, 10)
|
||||||
),
|
),
|
||||||
r#else: ElseExpression::Block(Node::new(
|
r#else: ElseExpression::Block(Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("z"), (18, 19))
|
Expression::identifier(Identifier::new("z"), (18, 19))
|
||||||
)]),
|
)])),
|
||||||
(16, 21)
|
(16, 21)
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
@ -1697,24 +1697,24 @@ mod tests {
|
|||||||
IfExpression::IfElse {
|
IfExpression::IfElse {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Expression::identifier(Identifier::new("y"), (7, 8))
|
||||||
)]),
|
)])),
|
||||||
(5, 10)
|
(5, 10)
|
||||||
),
|
),
|
||||||
r#else: ElseExpression::If(Node::new(
|
r#else: ElseExpression::If(Node::new(
|
||||||
Box::new(IfExpression::IfElse {
|
Box::new(IfExpression::IfElse {
|
||||||
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
|
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("a"), (23, 24))
|
Expression::identifier(Identifier::new("a"), (23, 24))
|
||||||
)]),
|
)])),
|
||||||
(21, 26)
|
(21, 26)
|
||||||
),
|
),
|
||||||
r#else: ElseExpression::Block(Node::new(
|
r#else: ElseExpression::Block(Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("b"), (34, 35))
|
Expression::identifier(Identifier::new("b"), (34, 35))
|
||||||
)]),
|
)])),
|
||||||
(32, 37)
|
(32, 37)
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
@ -1744,14 +1744,19 @@ mod tests {
|
|||||||
(6, 12)
|
(6, 12)
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
OperatorExpression::CompoundAssignment {
|
Expression::operator(
|
||||||
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
|
OperatorExpression::CompoundAssignment {
|
||||||
operator: Node::new(MathOperator::Add, (17, 19)),
|
assignee: Expression::identifier(
|
||||||
modifier: Expression::literal(1, (20, 21)),
|
Identifier::new("x"),
|
||||||
},
|
(15, 16)
|
||||||
(15, 21)
|
),
|
||||||
))]),
|
operator: Node::new(MathOperator::Add, (17, 19)),
|
||||||
|
modifier: Expression::literal(1, (20, 21)),
|
||||||
|
},
|
||||||
|
(15, 21)
|
||||||
|
)
|
||||||
|
)])),
|
||||||
(13, 23)
|
(13, 23)
|
||||||
),
|
),
|
||||||
(0, 23)
|
(0, 23)
|
||||||
@ -1806,14 +1811,16 @@ mod tests {
|
|||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::Expression(Expression::block(
|
Statement::Expression(Expression::block(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
|
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
||||||
OperatorExpression::Math {
|
Expression::operator(
|
||||||
left: Expression::literal(40, (2, 4)),
|
OperatorExpression::Math {
|
||||||
operator: Node::new(MathOperator::Add, (5, 6)),
|
left: Expression::literal(40, (2, 4)),
|
||||||
right: Expression::literal(2, (7, 8)),
|
operator: Node::new(MathOperator::Add, (5, 6)),
|
||||||
},
|
right: Expression::literal(2, (7, 8)),
|
||||||
(2, 8)
|
},
|
||||||
))]),
|
(2, 8)
|
||||||
|
)
|
||||||
|
)])),
|
||||||
(0, 10)
|
(0, 10)
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
@ -1828,7 +1835,7 @@ mod tests {
|
|||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::Expression(Expression::block(
|
Statement::Expression(Expression::block(
|
||||||
BlockExpression::Sync(vec![
|
BlockExpression::Sync(VecDeque::from([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::assignment(
|
Expression::assignment(
|
||||||
Expression::identifier("foo", (2, 5)),
|
Expression::identifier("foo", (2, 5)),
|
||||||
@ -1850,7 +1857,7 @@ mod tests {
|
|||||||
Expression::literal("42", (28, 32)),
|
Expression::literal("42", (28, 32)),
|
||||||
(22, 32)
|
(22, 32)
|
||||||
))
|
))
|
||||||
]),
|
])),
|
||||||
(0, 34)
|
(0, 34)
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
|
@ -1398,9 +1398,9 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = Vm::new(body, new_context);
|
let mut vm = Vm::new(new_context);
|
||||||
|
|
||||||
vm.run()
|
vm.run(body)
|
||||||
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
|
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
use rayon::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
@ -69,12 +69,13 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = Vm::new(abstract_syntax_tree, context);
|
let vm = Vm::new(context);
|
||||||
|
|
||||||
vm.run().map_err(|runtime_error| DustError::Runtime {
|
vm.run(abstract_syntax_tree)
|
||||||
runtime_error,
|
.map_err(|runtime_error| DustError::Runtime {
|
||||||
source,
|
runtime_error,
|
||||||
})
|
source,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dust virtual machine.
|
/// Dust virtual machine.
|
||||||
@ -85,37 +86,71 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
|
|||||||
///
|
///
|
||||||
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
abstract_tree: AbstractSyntaxTree,
|
|
||||||
context: Context,
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn new(abstract_tree: AbstractSyntaxTree, context: Context) -> Self {
|
pub fn new(context: Context) -> Self {
|
||||||
Self {
|
Self { context }
|
||||||
abstract_tree,
|
|
||||||
context,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<Option<Value>, RuntimeError> {
|
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
||||||
let mut previous_evaluation = None;
|
let mut previous_evaluation = Evaluation::Return(None);
|
||||||
|
|
||||||
while let Some(statement) = self.abstract_tree.statements.pop_front() {
|
while let Some(statement) = tree.statements.pop_front() {
|
||||||
previous_evaluation = self.run_statement(statement, true)?;
|
previous_evaluation = self.run_statement(statement, true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match previous_evaluation {
|
match previous_evaluation {
|
||||||
Some(Evaluation::Break(value_option)) => Ok(value_option),
|
Evaluation::Break(value_option) => Ok(value_option),
|
||||||
Some(Evaluation::Return(value_option)) => Ok(value_option),
|
Evaluation::Return(value_option) => Ok(value_option),
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_async(&self, tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
||||||
|
let final_result = Arc::new(Mutex::new(Evaluation::Return(None)));
|
||||||
|
let statements_length = tree.statements.len();
|
||||||
|
|
||||||
|
let error_option =
|
||||||
|
tree.statements
|
||||||
|
.into_par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map_any(|(i, statement)| {
|
||||||
|
let evaluation_result = self.run_statement(statement, false);
|
||||||
|
|
||||||
|
match evaluation_result {
|
||||||
|
Ok(evaluation_option) => {
|
||||||
|
if i == statements_length - 1 {
|
||||||
|
let mut final_result = final_result.lock().unwrap();
|
||||||
|
|
||||||
|
*final_result = evaluation_option;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(error) => Some(error),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(error) = error_option {
|
||||||
|
Err(error)
|
||||||
|
} else {
|
||||||
|
let final_result = final_result.lock().unwrap();
|
||||||
|
|
||||||
|
match &*final_result {
|
||||||
|
Evaluation::Break(value_option) => Ok(value_option.clone()),
|
||||||
|
Evaluation::Return(value_option) => Ok(value_option.clone()),
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_statement(
|
fn run_statement(
|
||||||
&self,
|
&self,
|
||||||
statement: Statement,
|
statement: Statement,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Running statement at {:?}: {}",
|
"Running statement at {:?}: {}",
|
||||||
statement.position(),
|
statement.position(),
|
||||||
@ -125,21 +160,21 @@ impl Vm {
|
|||||||
let position = statement.position();
|
let position = statement.position();
|
||||||
let result = match statement {
|
let result = match statement {
|
||||||
Statement::Expression(expression) => {
|
Statement::Expression(expression) => {
|
||||||
Ok(Some(self.run_expression(expression, collect_garbage)?))
|
Ok(self.run_expression(expression, collect_garbage)?)
|
||||||
}
|
}
|
||||||
Statement::ExpressionNullified(expression) => {
|
Statement::ExpressionNullified(expression) => {
|
||||||
let evaluation = self.run_expression(expression.inner, collect_garbage)?;
|
let evaluation = self.run_expression(expression.inner, collect_garbage)?;
|
||||||
|
|
||||||
if let Evaluation::Break(_) = evaluation {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
Ok(Some(evaluation))
|
Ok(evaluation)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(Evaluation::Return(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Let(let_statement) => {
|
Statement::Let(let_statement) => {
|
||||||
self.run_let_statement(let_statement.inner, collect_garbage)?;
|
self.run_let_statement(let_statement.inner, collect_garbage)?;
|
||||||
|
|
||||||
Ok(None)
|
Ok(Evaluation::Return(None))
|
||||||
}
|
}
|
||||||
Statement::StructDefinition(struct_definition) => {
|
Statement::StructDefinition(struct_definition) => {
|
||||||
let (name, struct_type) = match struct_definition.inner {
|
let (name, struct_type) = match struct_definition.inner {
|
||||||
@ -181,7 +216,7 @@ impl Vm {
|
|||||||
position: struct_definition.position,
|
position: struct_definition.position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(None)
|
Ok(Evaluation::Return(None))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -295,9 +330,15 @@ impl Vm {
|
|||||||
Expression::TupleAccess(_) => todo!(),
|
Expression::TupleAccess(_) => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
evaluation_result.map_err(|error| RuntimeError::Expression {
|
evaluation_result.map_err(|error| {
|
||||||
error: Box::new(error),
|
if error.position() == position {
|
||||||
position,
|
error
|
||||||
|
} else {
|
||||||
|
RuntimeError::Expression {
|
||||||
|
error: Box::new(error),
|
||||||
|
position,
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,7 +698,7 @@ impl Vm {
|
|||||||
for statement in statements.clone() {
|
for statement in statements.clone() {
|
||||||
let evaluation = self.run_statement(statement, false)?;
|
let evaluation = self.run_statement(statement, false)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Break(value_option)) = evaluation {
|
if let Evaluation::Break(value_option) = evaluation {
|
||||||
break 'outer Ok(Evaluation::Return(value_option));
|
break 'outer Ok(Evaluation::Return(value_option));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -958,54 +999,25 @@ impl Vm {
|
|||||||
block: BlockExpression,
|
block: BlockExpression,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
|
let block_context = self.context.create_child();
|
||||||
|
let vm = Vm::new(block_context);
|
||||||
|
|
||||||
match block {
|
match block {
|
||||||
BlockExpression::Async(statements) => {
|
BlockExpression::Async(statements) => vm
|
||||||
let final_result = Arc::new(Mutex::new(None));
|
.run_async(AbstractSyntaxTree::with_statements(statements))
|
||||||
let statements_length = statements.len();
|
.map(Evaluation::Return),
|
||||||
let error_option =
|
|
||||||
statements
|
|
||||||
.into_par_iter()
|
|
||||||
.enumerate()
|
|
||||||
.find_map_any(|(i, statement)| {
|
|
||||||
let evaluation_result = self.run_statement(statement, false);
|
|
||||||
|
|
||||||
match evaluation_result {
|
|
||||||
Ok(evaluation_option) => {
|
|
||||||
if i == statements_length - 1 {
|
|
||||||
let mut final_result = final_result.lock().unwrap();
|
|
||||||
|
|
||||||
*final_result = evaluation_option;
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(error) => Some(error),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(error) = error_option {
|
|
||||||
Err(error)
|
|
||||||
} else if let Some(evaluation) = final_result.lock().unwrap().take() {
|
|
||||||
Ok(evaluation)
|
|
||||||
} else {
|
|
||||||
Ok(Evaluation::Return(None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BlockExpression::Sync(statements) => {
|
BlockExpression::Sync(statements) => {
|
||||||
let mut previous_evaluation = None;
|
let mut evaluation = Evaluation::Return(None);
|
||||||
|
|
||||||
for statement in statements {
|
for statement in statements {
|
||||||
previous_evaluation = self.run_statement(statement, collect_garbage)?;
|
evaluation = vm.run_statement(statement, collect_garbage)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Break(value_option)) = previous_evaluation {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
return Ok(Evaluation::Break(value_option));
|
return Ok(evaluation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match previous_evaluation {
|
Ok(evaluation)
|
||||||
Some(evaluation) => Ok(evaluation),
|
|
||||||
None => Ok(Evaluation::Return(None)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1386,6 +1398,55 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_scope_captures_parent() {
|
||||||
|
let source = "let x = 42; { x }";
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_scope_does_not_capture_child() {
|
||||||
|
let source = "{ let x = 42; } x";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
run(source),
|
||||||
|
Err(DustError::Runtime {
|
||||||
|
runtime_error: RuntimeError::UnassociatedIdentifier {
|
||||||
|
identifier: Identifier::new("x"),
|
||||||
|
position: (16, 17)
|
||||||
|
},
|
||||||
|
source
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_scope_does_not_capture_sibling() {
|
||||||
|
let source = "{ let x = 42; } { x }";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
run(source),
|
||||||
|
Err(DustError::Runtime {
|
||||||
|
runtime_error: RuntimeError::Expression {
|
||||||
|
error: Box::new(RuntimeError::UnassociatedIdentifier {
|
||||||
|
identifier: Identifier::new("x"),
|
||||||
|
position: (18, 19)
|
||||||
|
}),
|
||||||
|
position: (16, 21)
|
||||||
|
},
|
||||||
|
source
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_scope_does_not_pollute_parent() {
|
||||||
|
let source = "let x = 42; { let x = \"foo\"; let x = \"bar\"; } x";
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn character() {
|
fn character() {
|
||||||
let input = "'a'";
|
let input = "'a'";
|
||||||
|
Loading…
Reference in New Issue
Block a user