Try embedding contexts in the AST

This commit is contained in:
Jeff 2024-08-30 18:06:58 -04:00
parent d032334635
commit 012728b00a
8 changed files with 405 additions and 347 deletions

View File

@ -17,8 +17,8 @@ use crate::{
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
StructExpression, TupleAccessExpression,
},
core_library, parse, Context, ContextError, DustError, Expression, Identifier, RangeableType,
StructType, Type, TypeConflict, TypeEvaluation,
parse, ContextError, DustError, Expression, Identifier, RangeableType, StructType, Type,
TypeConflict, TypeEvaluation,
};
/// Analyzes the abstract syntax tree for errors.
@ -34,8 +34,7 @@ use crate::{
/// ```
pub fn analyze(source: &str) -> Result<(), DustError> {
let abstract_tree = parse(source)?;
let context = core_library().create_child();
let mut analyzer = Analyzer::new(&abstract_tree, context);
let mut analyzer = Analyzer::new(&abstract_tree);
analyzer.analyze();
@ -61,15 +60,13 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
/// assert!(!analyzer.errors.is_empty());
pub struct Analyzer<'a> {
abstract_tree: &'a AbstractSyntaxTree,
context: Context,
pub errors: Vec<AnalysisError>,
}
impl<'a> Analyzer<'a> {
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: Context) -> Self {
pub fn new(abstract_tree: &'a AbstractSyntaxTree) -> Self {
Self {
abstract_tree,
context,
errors: Vec::new(),
}
}
@ -91,14 +88,14 @@ impl<'a> Analyzer<'a> {
Statement::Let(let_statement) => match &let_statement.inner {
LetStatement::Let { identifier, value }
| LetStatement::LetMut { identifier, value } => {
let r#type = match value.type_evaluation(&self.context) {
let r#type = match value.type_evaluation(&self.abstract_tree.context) {
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => {
let set_type = self.context.set_variable_type(
let set_type = self.abstract_tree.context.set_variable_type(
identifier.inner.clone(),
Type::Struct(StructType::Unit { name }),
statement.position(),
@ -119,7 +116,7 @@ impl<'a> Analyzer<'a> {
};
if let Some(r#type) = r#type {
let set_type = self.context.set_variable_type(
let set_type = self.abstract_tree.context.set_variable_type(
identifier.inner.clone(),
r#type.clone(),
statement.position(),
@ -145,17 +142,19 @@ impl<'a> Analyzer<'a> {
},
Statement::StructDefinition(struct_definition) => {
let set_constructor_type = match &struct_definition.inner {
StructDefinition::Unit { name } => self.context.set_constructor_type(
name.inner.clone(),
StructType::Unit {
name: name.inner.clone(),
},
statement.position(),
),
StructDefinition::Unit { name } => {
self.abstract_tree.context.set_constructor_type(
name.inner.clone(),
StructType::Unit {
name: name.inner.clone(),
},
statement.position(),
)
}
StructDefinition::Tuple { name, items } => {
let fields = items.iter().map(|item| item.inner.clone()).collect();
self.context.set_constructor_type(
self.abstract_tree.context.set_constructor_type(
name.inner.clone(),
StructType::Tuple {
name: name.inner.clone(),
@ -172,7 +171,7 @@ impl<'a> Analyzer<'a> {
})
.collect();
self.context.set_constructor_type(
self.abstract_tree.context.set_constructor_type(
name.inner.clone(),
StructType::Fields {
name: name.inner.clone(),
@ -206,7 +205,8 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(invoker, statement_position);
let invoker_evaluation = match invoker.type_evaluation(&self.context) {
let invoker_evaluation = match invoker.type_evaluation(&self.abstract_tree.context)
{
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
@ -219,14 +219,15 @@ impl<'a> Analyzer<'a> {
invoker_evaluation
{
for (expected_type, argument) in fields.iter().zip(arguments.iter()) {
let actual_type = match argument.type_evaluation(&self.context) {
Ok(evaluation) => evaluation.r#type(),
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
let actual_type =
match argument.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation.r#type(),
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
return;
}
};
if let Some(r#type) = actual_type {
let check = expected_type.check(&r#type);
@ -282,14 +283,15 @@ impl<'a> Analyzer<'a> {
for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) {
self.analyze_expression(argument, statement_position);
let argument_evaluation = match argument.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(error) => {
self.errors.push(AnalysisError::AstError(error));
let argument_evaluation =
match argument.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(error) => {
self.errors.push(AnalysisError::AstError(error));
continue;
}
};
continue;
}
};
let actual_type = if let Some(r#type) = argument_evaluation.r#type() {
r#type
@ -321,7 +323,7 @@ impl<'a> Analyzer<'a> {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
let evaluation = match container.type_evaluation(&self.context) {
let evaluation = match container.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
@ -355,6 +357,7 @@ impl<'a> Analyzer<'a> {
}
Expression::Identifier(identifier) => {
let find_identifier = self
.abstract_tree
.context
.update_last_position(&identifier.inner, statement_position);
@ -394,7 +397,7 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(list, statement_position);
self.analyze_expression(index, statement_position);
let list_type_evaluation = match list.type_evaluation(&self.context) {
let list_type_evaluation = match list.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
@ -413,7 +416,8 @@ impl<'a> Analyzer<'a> {
return;
}
};
let index_type_evaluation = match index.type_evaluation(&self.context) {
let index_type_evaluation = match index.type_evaluation(&self.abstract_tree.context)
{
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
@ -540,22 +544,24 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(assignee, statement_position);
self.analyze_expression(modifier, statement_position);
let assignee_type_evaluation = match assignee.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
let assignee_type_evaluation =
match assignee.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let modifier_type_evaluation = match modifier.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let modifier_type_evaluation =
match modifier.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
return;
}
};
let (expected_type, actual_type) = match (
assignee_type_evaluation.r#type(),
@ -608,22 +614,24 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let left_type_evaluation = match left.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
let left_type_evaluation =
match left.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation = match right.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation =
match right.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
return;
}
};
let (left_type, right_type) = match (
left_type_evaluation.r#type(),
@ -704,22 +712,24 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let left_type_evaluation = match left.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
let left_type_evaluation =
match left.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation = match right.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation =
match right.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
return;
}
};
let (left_type, right_type) = match (
left_type_evaluation.r#type(),
@ -775,6 +785,7 @@ impl<'a> Analyzer<'a> {
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { name, fields } => {
let update_position = self
.abstract_tree
.context
.update_last_position(&name.inner, statement_position);
@ -795,7 +806,7 @@ impl<'a> Analyzer<'a> {
Expression::TupleAccess(tuple_access) => {
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
let type_evaluation = match tuple.type_evaluation(&self.context) {
let type_evaluation = match tuple.type_evaluation(&self.abstract_tree.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
@ -840,18 +851,19 @@ impl<'a> Analyzer<'a> {
}
fn analyze_block(&mut self, block_expression: &BlockExpression) {
match block_expression {
BlockExpression::Async(statements) => {
for statement in statements {
self.analyze_statement(statement);
}
}
BlockExpression::Sync(statements) => {
for statement in statements {
self.analyze_statement(statement);
}
}
}
let ast = match block_expression {
BlockExpression::Async(ast) => ast,
BlockExpression::Sync(ast) => ast,
};
ast.context
.assign_parent(self.abstract_tree.context.clone());
let mut analyzer = Analyzer::new(ast);
analyzer.analyze();
self.errors.append(&mut analyzer.errors);
}
fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) {

View File

@ -1,6 +1,6 @@
use std::{
cmp::Ordering,
collections::{HashMap, VecDeque},
collections::HashMap,
fmt::{self, Display, Formatter},
};
@ -11,7 +11,7 @@ use crate::{
TypeEvaluation, ValueData,
};
use super::{AstError, Node, Span, Statement};
use super::{AbstractSyntaxTree, AstError, Node, Span};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Expression {
@ -1139,16 +1139,16 @@ impl Display for ElseExpression {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BlockExpression {
Async(VecDeque<Statement>),
Sync(VecDeque<Statement>),
Async(AbstractSyntaxTree),
Sync(AbstractSyntaxTree),
}
impl BlockExpression {
fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
fn type_evaluation(&self, _: &Context) -> Result<TypeEvaluation, AstError> {
match self {
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
if let Some(statement) = statements.back() {
statement.type_evaluation(context)
BlockExpression::Async(ast) | BlockExpression::Sync(ast) => {
if let Some(statement) = ast.statements.back() {
statement.type_evaluation(&ast.context)
} else {
Ok(TypeEvaluation::Return(None))
}
@ -1160,10 +1160,10 @@ impl BlockExpression {
impl Display for BlockExpression {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
BlockExpression::Async(statements) => {
BlockExpression::Async(ast) => {
write!(f, "async {{ ")?;
for (i, statement) in statements.iter().enumerate() {
for (i, statement) in ast.statements.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
@ -1173,10 +1173,10 @@ impl Display for BlockExpression {
write!(f, " }}")
}
BlockExpression::Sync(statements) => {
BlockExpression::Sync(ast) => {
write!(f, "{{ ")?;
for (i, statement) in statements.iter().enumerate() {
for (i, statement) in ast.statements.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}

View File

@ -13,26 +13,51 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::ContextError;
use crate::{Context, ContextError};
pub type Span = (usize, usize);
/// In-memory representation of a Dust program.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AbstractSyntaxTree {
pub statements: VecDeque<Statement>,
#[serde(skip)]
pub context: Context,
}
impl Eq for AbstractSyntaxTree {}
impl PartialEq for AbstractSyntaxTree {
fn eq(&self, other: &Self) -> bool {
self.statements == other.statements
}
}
impl PartialOrd for AbstractSyntaxTree {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AbstractSyntaxTree {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.statements.cmp(&other.statements)
}
}
impl AbstractSyntaxTree {
pub fn new() -> Self {
Self {
statements: VecDeque::new(),
context: Context::new(),
}
}
pub fn with_statements<T: Into<VecDeque<Statement>>>(statements: T) -> Self {
Self {
statements: statements.into(),
context: Context::new(),
}
}
}

View File

@ -13,7 +13,7 @@ pub type Associations = HashMap<Identifier, (ContextData, Span)>;
#[derive(Debug, Clone)]
pub struct Context {
associations: Arc<RwLock<Associations>>,
parent: Option<Box<Context>>,
parent: Arc<RwLock<Option<Context>>>,
}
impl Context {
@ -24,7 +24,7 @@ impl Context {
pub fn with_data(data: Associations) -> Self {
Self {
associations: Arc::new(RwLock::new(data)),
parent: None,
parent: Arc::new(RwLock::new(None)),
}
}
@ -36,10 +36,14 @@ impl Context {
pub fn create_child(&self) -> Self {
Self {
associations: Arc::new(RwLock::new(HashMap::new())),
parent: Some(Box::new(self.clone())),
parent: Arc::new(RwLock::new(Some(self.clone()))),
}
}
pub fn assign_parent(&self, parent: Self) {
self.parent.write().unwrap().replace(parent);
}
/// Returns the number of associated identifiers in the context.
pub fn association_count(&self) -> Result<usize, ContextError> {
Ok(self.associations.read()?.len())
@ -49,7 +53,7 @@ impl Context {
pub fn contains(&self, identifier: &Identifier) -> Result<bool, ContextError> {
if self.associations.read()?.contains_key(identifier) {
Ok(true)
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.contains(identifier)
} else {
Ok(false)
@ -77,7 +81,7 @@ impl Context {
_ => {}
}
if let Some(parent) = &self.parent {
if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.get_type(identifier)
} else {
Ok(None)
@ -88,7 +92,7 @@ impl Context {
pub fn get_data(&self, identifier: &Identifier) -> Result<Option<ContextData>, ContextError> {
if let Some((variable_data, _)) = self.associations.read()?.get(identifier) {
Ok(Some(variable_data.clone()))
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.get_data(identifier)
} else {
Ok(None)
@ -104,7 +108,7 @@ impl Context {
self.associations.read()?.get(identifier)
{
Ok(Some(value.clone()))
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.get_variable_value(identifier)
} else {
Ok(None)
@ -120,7 +124,7 @@ impl Context {
self.associations.read()?.get(identifier)
{
Ok(Some(constructor.clone()))
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.get_constructor(identifier)
} else {
Ok(None)
@ -140,7 +144,7 @@ impl Context {
ContextData::ConstructorType(struct_type) => Ok(Some(struct_type.clone())),
_ => Ok(None),
}
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.get_constructor_type(identifier)
} else {
Ok(None)
@ -285,7 +289,7 @@ impl Context {
log::trace!("Updating {identifier}'s last position to {position:?}");
Ok(true)
} else if let Some(parent) = &self.parent {
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
parent.contains(identifier)
} else {
Ok(false)
@ -372,7 +376,7 @@ impl Display for ContextError {
#[cfg(test)]
mod tests {
use crate::vm::run_with_context;
use crate::{parse, run, Vm};
use super::*;
@ -384,29 +388,25 @@ mod tests {
let z = x + y;
z
";
let context = Context::new();
assert_eq!(
run_with_context(source, context.clone()),
Ok(Some(Value::integer(15)))
);
let ast = parse(source).unwrap();
let context = ast.context.clone();
assert_eq!(Vm.run(ast), Ok(Some(Value::integer(15))));
assert_eq!(context.association_count().unwrap(), 0);
}
#[test]
fn garbage_collector_does_not_break_loops() {
let source = "
let y = 1;
let mut z = 0;
while z < 10 {
z = z + y
z += 1;
}
";
let context = Context::new();
run_with_context(source, context.clone()).unwrap();
let ast = parse(source).unwrap();
let context = ast.context.clone();
assert_eq!(Vm.run(ast), Ok(None));
assert_eq!(context.association_count().unwrap(), 0);
}
}

View File

@ -45,4 +45,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, RuntimeError, Vm};
pub use vm::{run, RuntimeError, Vm};

View File

@ -10,7 +10,9 @@ use std::{
str::ParseBoolError,
};
use crate::{ast::*, DustError, Identifier, LexError, Lexer, Token, TokenKind, TokenOwned, Type};
use crate::{
ast::*, Context, DustError, Identifier, LexError, Lexer, Token, TokenKind, TokenOwned, Type,
};
/// Parses the input into an abstract syntax tree.
///
@ -96,6 +98,7 @@ pub struct Parser<'src> {
current_token: Token<'src>,
current_position: Span,
mode: ParserMode,
context: Context,
}
impl<'src> Parser<'src> {
@ -107,6 +110,7 @@ impl<'src> Parser<'src> {
current_token,
current_position,
mode: ParserMode::Normal,
context: Context::new(),
}
}
@ -1011,10 +1015,15 @@ impl<'src> Parser<'src> {
self.next_token()?;
let ast = AbstractSyntaxTree {
statements,
context: self.context.create_child(),
};
return if is_async {
Ok(Node::new(BlockExpression::Async(statements), position))
Ok(Node::new(BlockExpression::Async(ast), position))
} else {
Ok(Node::new(BlockExpression::Sync(statements), position))
Ok(Node::new(BlockExpression::Sync(ast), position))
};
}
@ -1201,9 +1210,12 @@ mod tests {
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::infinite_loop(
Node::new(
BlockExpression::Sync(VecDeque::from([Statement::ExpressionNullified(
Node::new(Expression::r#break(None, (7, 12)), (7, 13))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::r#break(None, (7, 12)),
(7, 13)
))
])),
(5, 15)
),
(0, 15)
@ -1238,8 +1250,8 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::Expression(Expression::map(
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::map(
vec![
(
Node::new(Identifier::new("x"), (6, 7)),
@ -1255,9 +1267,8 @@ mod tests {
),
],
(0, 31),
))]
.into(),
})
))
]))
);
}
@ -1267,42 +1278,39 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [
Statement::Let(Node::new(
LetStatement::LetMut {
identifier: Node::new(Identifier::new("x"), (8, 9)),
value: Expression::literal(0, (12, 13)),
},
(0, 14),
)),
Statement::ExpressionNullified(Node::new(
Expression::while_loop(
Expression::comparison(
Expression::identifier(Identifier::new("x"), (21, 22)),
Node::new(ComparisonOperator::LessThan, (23, 24)),
Expression::literal(10, (25, 27)),
(21, 27),
),
Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::compound_assignment(
Expression::identifier(Identifier::new("x"), (30, 31)),
Node::new(MathOperator::Add, (32, 34)),
Expression::literal(1, (35, 36)),
(30, 36),
),
)])),
(28, 38),
),
(15, 38),
Ok(AbstractSyntaxTree::with_statements([
Statement::Let(Node::new(
LetStatement::LetMut {
identifier: Node::new(Identifier::new("x"), (8, 9)),
value: Expression::literal(0, (12, 13)),
},
(0, 14),
)),
Statement::ExpressionNullified(Node::new(
Expression::while_loop(
Expression::comparison(
Expression::identifier(Identifier::new("x"), (21, 22)),
Node::new(ComparisonOperator::LessThan, (23, 24)),
Expression::literal(10, (25, 27)),
(21, 27),
),
(15, 39)
)),
Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),),
]
.into()
})
Node::new(
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::compound_assignment(
Expression::identifier(Identifier::new("x"), (30, 31)),
Node::new(MathOperator::Add, (32, 34)),
Expression::literal(1, (35, 36)),
(30, 36),
),)
])),
(28, 38),
),
(15, 38),
),
(15, 39)
)),
Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),),
]))
);
}
@ -1330,16 +1338,15 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::Let(Node::new(
Ok(AbstractSyntaxTree::with_statements([Statement::Let(
Node::new(
LetStatement::LetMut {
identifier: Node::new(Identifier::new("x"), (8, 9)),
value: Expression::literal(false, (12, 17)),
},
(0, 18),
))]
.into()
})
)
)]))
);
}
@ -1349,9 +1356,9 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::Expression(Expression::block(
BlockExpression::Async(VecDeque::from([
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block(
BlockExpression::Async(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
@ -1371,9 +1378,8 @@ mod tests {
))
])),
(0, 25)
))]
.into()
})
))
]))
);
}
@ -1668,9 +1674,12 @@ mod tests {
IfExpression::If {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))
])),
(5, 10)
)
},
@ -1691,15 +1700,21 @@ mod tests {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))
])),
(5, 10)
),
r#else: ElseExpression::Block(Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("z"), (18, 19))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("z"),
(18, 19)
))
])),
(16, 21)
))
},
@ -1720,24 +1735,33 @@ mod tests {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))
])),
(5, 10)
),
r#else: ElseExpression::If(Node::new(
Box::new(IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
if_block: Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("a"), (23, 24))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("a"),
(23, 24)
))
])),
(21, 26)
),
r#else: ElseExpression::Block(Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::identifier(Identifier::new("b"), (34, 35))
)])),
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::identifier(
Identifier::new("b"),
(34, 35)
))
])),
(32, 37)
)),
}),
@ -1767,8 +1791,8 @@ mod tests {
(6, 12)
),
Node::new(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::operator(
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(
Identifier::new("x"),
@ -1778,8 +1802,8 @@ mod tests {
modifier: Expression::literal(1, (20, 21)),
},
(15, 21)
)
)])),
))
])),
(13, 23)
),
(0, 23)
@ -1834,16 +1858,16 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block(
BlockExpression::Sync(VecDeque::from([Statement::Expression(
Expression::operator(
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::operator(
OperatorExpression::Math {
left: Expression::literal(40, (2, 4)),
operator: Node::new(MathOperator::Add, (5, 6)),
right: Expression::literal(2, (7, 8)),
},
(2, 8)
)
)])),
))
])),
(0, 10)
))
]))
@ -1858,7 +1882,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block(
BlockExpression::Sync(VecDeque::from([
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::assignment(
Expression::identifier("foo", (2, 5)),

View File

@ -1418,9 +1418,7 @@ impl Function {
}
}
let vm = Vm::new(new_context);
vm.run(body)
Vm.run(body)
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
}
}

View File

@ -37,28 +37,8 @@ use crate::{
/// assert_eq!(result, Ok(Some(Value::integer(42))));
/// ```
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let context = core_library().create_child();
run_with_context(source, context)
}
/// Run the source code with a context and return the result.
///
/// # Example
/// ```
/// # use dust_lang::*;
/// let context = Context::new();
///
/// context.set_variable_value(Identifier::new("foo"), Value::integer(40));
/// context.update_last_position(&Identifier::new("foo"), (100, 100));
///
/// let result = run_with_context("foo + 2", context);
///
/// assert_eq!(result, Ok(Some(Value::integer(42))));
/// ```
pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
let abstract_syntax_tree = parse(source)?;
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context.clone());
let mut analyzer = Analyzer::new(&abstract_syntax_tree);
analyzer.analyze();
@ -69,9 +49,7 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
});
}
let vm = Vm::new(context);
vm.run(abstract_syntax_tree)
Vm.run(abstract_syntax_tree)
.map_err(|runtime_error| DustError::Runtime {
runtime_error,
source,
@ -85,20 +63,14 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
/// before running it.
///
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
pub struct Vm {
context: Context,
}
pub struct Vm;
impl Vm {
pub fn new(context: Context) -> Self {
Self { context }
}
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
let mut previous_evaluation = Evaluation::Return(None);
while let Some(statement) = tree.statements.pop_front() {
previous_evaluation = self.run_statement(statement, true)?;
previous_evaluation = self.run_statement(statement, &tree.context, true)?;
}
match previous_evaluation {
@ -117,7 +89,7 @@ impl Vm {
.into_par_iter()
.enumerate()
.find_map_any(|(i, statement)| {
let evaluation_result = self.run_statement(statement, false);
let evaluation_result = self.run_statement(statement, &tree.context, false);
match evaluation_result {
Ok(evaluation_option) => {
@ -134,21 +106,22 @@ impl Vm {
});
if let Some(error) = error_option {
Err(error)
} else {
let final_result = final_result.lock().unwrap();
return Err(error);
}
match &*final_result {
Evaluation::Break(value_option) => Ok(value_option.clone()),
Evaluation::Return(value_option) => Ok(value_option.clone()),
_ => Ok(None),
}
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(
&self,
statement: Statement,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
log::trace!(
@ -160,10 +133,10 @@ impl Vm {
let position = statement.position();
let result = match statement {
Statement::Expression(expression) => {
Ok(self.run_expression(expression, collect_garbage)?)
Ok(self.run_expression(expression, context, collect_garbage)?)
}
Statement::ExpressionNullified(expression) => {
let evaluation = self.run_expression(expression.inner, collect_garbage)?;
let evaluation = self.run_expression(expression.inner, context, collect_garbage)?;
if let Evaluation::Break(_) = evaluation {
Ok(evaluation)
@ -172,7 +145,7 @@ impl Vm {
}
}
Statement::Let(let_statement) => {
self.run_let_statement(let_statement.inner, collect_garbage)?;
self.run_let_statement(let_statement.inner, context, collect_garbage)?;
Ok(Evaluation::Return(None))
}
@ -209,7 +182,7 @@ impl Vm {
};
let constructor = struct_type.constructor();
self.context
context
.set_constructor(name, constructor)
.map_err(|error| RuntimeError::ContextError {
error,
@ -221,7 +194,7 @@ impl Vm {
};
if collect_garbage {
self.context
context
.collect_garbage(position.1)
.map_err(|error| RuntimeError::ContextError { error, position })?;
}
@ -235,13 +208,14 @@ impl Vm {
fn run_let_statement(
&self,
let_statement: LetStatement,
context: &Context,
collect_garbage: bool,
) -> Result<(), RuntimeError> {
match let_statement {
LetStatement::Let { identifier, value } => {
let position = value.position();
let value = self
.run_expression(value, collect_garbage)?
.run_expression(value, context, collect_garbage)?
.expect_value(position)?;
let new_value = match value {
Value::Mutable(_) => {
@ -250,7 +224,7 @@ impl Vm {
_ => value,
};
self.context
context
.set_variable_value(identifier.inner, new_value)
.map_err(|error| RuntimeError::ContextError { error, position })?;
@ -259,11 +233,11 @@ impl Vm {
LetStatement::LetMut { identifier, value } => {
let position = value.position();
let mutable_value = self
.run_expression(value, collect_garbage)?
.run_expression(value, context, collect_garbage)?
.expect_value(position)?
.into_mutable();
self.context
context
.set_variable_value(identifier.inner, mutable_value)
.map_err(|error| RuntimeError::ContextError { error, position })?;
@ -277,6 +251,7 @@ impl Vm {
fn run_expression(
&self,
expression: Expression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
log::trace!(
@ -287,14 +262,16 @@ impl Vm {
let position = expression.position();
let evaluation_result = match expression {
Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage),
Expression::Block(Node { inner, .. }) => {
self.run_block(*inner, context, collect_garbage)
}
Expression::Break(Node { inner, .. }) => {
let break_expression = if let Some(expression) = inner {
*expression
} else {
return Ok(Evaluation::Break(None));
};
let run_break = self.run_expression(break_expression, collect_garbage)?;
let run_break = self.run_expression(break_expression, context, collect_garbage)?;
let evaluation = match run_break {
Evaluation::Break(value_option) => Evaluation::Break(value_option),
Evaluation::Return(value_option) => Evaluation::Break(value_option),
@ -305,9 +282,9 @@ impl Vm {
Ok(evaluation)
}
Expression::Call(call) => self.run_call(*call.inner, collect_garbage),
Expression::Call(call) => self.run_call(*call.inner, context, collect_garbage),
Expression::Dereference(Node { inner, .. }) => {
let run_expression = self.run_expression(*inner, collect_garbage)?;
let run_expression = self.run_expression(*inner, context, collect_garbage)?;
let evaluation = match run_expression {
Evaluation::Constructor(_) => {
return Err(RuntimeError::ExpectedValue { position })
@ -323,30 +300,34 @@ impl Vm {
Ok(evaluation)
}
Expression::FieldAccess(field_access) => {
self.run_field_access(*field_access.inner, collect_garbage)
self.run_field_access(*field_access.inner, context, collect_garbage)
}
Expression::Grouped(expression) => {
self.run_expression(*expression.inner, collect_garbage)
self.run_expression(*expression.inner, context, collect_garbage)
}
Expression::Identifier(identifier) => self.run_identifier(identifier, context),
Expression::If(if_expression) => {
self.run_if(*if_expression.inner, context, collect_garbage)
}
Expression::Identifier(identifier) => self.run_identifier(identifier),
Expression::If(if_expression) => self.run_if(*if_expression.inner, collect_garbage),
Expression::List(list_expression) => {
self.run_list(*list_expression.inner, collect_garbage)
self.run_list(*list_expression.inner, context, collect_garbage)
}
Expression::ListIndex(list_index) => {
self.run_list_index(*list_index.inner, collect_garbage)
self.run_list_index(*list_index.inner, context, collect_garbage)
}
Expression::Literal(literal) => self.run_literal(*literal.inner),
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
Expression::Map(map_expression) => self.run_map(*map_expression.inner, collect_garbage),
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner, context),
Expression::Map(map_expression) => {
self.run_map(*map_expression.inner, context, collect_garbage)
}
Expression::Operator(operator_expression) => {
self.run_operator(*operator_expression.inner, collect_garbage)
self.run_operator(*operator_expression.inner, context, collect_garbage)
}
Expression::Range(range_expression) => {
self.run_range(*range_expression.inner, collect_garbage)
self.run_range(*range_expression.inner, context, collect_garbage)
}
Expression::Struct(struct_expression) => {
self.run_struct(*struct_expression.inner, collect_garbage)
self.run_struct(*struct_expression.inner, context, collect_garbage)
}
Expression::TupleAccess(_) => todo!(),
};
@ -363,13 +344,18 @@ impl Vm {
})
}
fn run_identifier(&self, identifier: Node<Identifier>) -> Result<Evaluation, RuntimeError> {
let get_data = self.context.get_data(&identifier.inner).map_err(|error| {
RuntimeError::ContextError {
error,
position: identifier.position,
}
})?;
fn run_identifier(
&self,
identifier: Node<Identifier>,
context: &Context,
) -> Result<Evaluation, RuntimeError> {
let get_data =
context
.get_data(&identifier.inner)
.map_err(|error| RuntimeError::ContextError {
error,
position: identifier.position,
})?;
if let Some(ContextData::VariableValue(value)) = get_data {
return Ok(Evaluation::Return(Some(value)));
@ -397,13 +383,13 @@ impl Vm {
fn run_struct(
&self,
struct_expression: StructExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let StructExpression::Fields { name, fields } = struct_expression;
let position = name.position;
let constructor = self
.context
let constructor = context
.get_constructor(&name.inner)
.map_err(|error| RuntimeError::ContextError { error, position })?;
@ -413,7 +399,7 @@ impl Vm {
for (identifier, expression) in fields {
let position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.run_expression(expression, context, collect_garbage)?
.expect_value(position)?;
arguments.insert(identifier.inner, value);
@ -432,13 +418,14 @@ impl Vm {
fn run_range(
&self,
range: RangeExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match range {
RangeExpression::Exclusive { start, end } => {
let start_position = start.position();
let start = self
.run_expression(start, collect_garbage)?
.run_expression(start, context, collect_garbage)?
.expect_value(start_position)?;
let start_data = match start {
@ -448,7 +435,7 @@ impl Vm {
};
let end_position = end.position();
let end = self
.run_expression(end, collect_garbage)?
.run_expression(end, context, collect_garbage)?
.expect_value(end_position)?;
let end_data = match end {
Value::Raw(data) => data,
@ -478,7 +465,7 @@ impl Vm {
RangeExpression::Inclusive { start, end } => {
let start_position = start.position();
let start = self
.run_expression(start, collect_garbage)?
.run_expression(start, context, collect_garbage)?
.expect_value(start_position)?;
let start_data = match start {
@ -488,7 +475,7 @@ impl Vm {
};
let end_position = end.position();
let end = self
.run_expression(end, collect_garbage)?
.run_expression(end, context, collect_garbage)?
.expect_value(end_position)?;
let end_data = match end {
Value::Raw(data) => data,
@ -521,6 +508,7 @@ impl Vm {
fn run_map(
&self,
map: MapExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let MapExpression { pairs } = map;
@ -530,7 +518,7 @@ impl Vm {
for (identifier, expression) in pairs {
let expression_position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.run_expression(expression, context, collect_garbage)?
.expect_value(expression_position)?;
map.insert(identifier.inner, value);
@ -542,17 +530,18 @@ impl Vm {
fn run_operator(
&self,
operator: OperatorExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match operator {
OperatorExpression::Assignment { assignee, value } => {
let assignee_position = assignee.position();
let assignee = self
.run_expression(assignee, collect_garbage)?
.run_expression(assignee, context, collect_garbage)?
.expect_value(assignee_position)?;
let value_position = value.position();
let value = self
.run_expression(value, collect_garbage)?
.run_expression(value, context, collect_garbage)?
.expect_value(value_position)?;
assignee
@ -572,11 +561,11 @@ impl Vm {
} => {
let left_position = left.position();
let left_value = self
.run_expression(left, collect_garbage)?
.run_expression(left, context, collect_garbage)?
.expect_value(left_position)?;
let right_position = right.position();
let right_value = self
.run_expression(right, collect_garbage)?
.run_expression(right, context, collect_garbage)?
.expect_value(right_position)?;
let result = match operator.inner {
ComparisonOperator::Equal => left_value.equal(&right_value),
@ -605,11 +594,11 @@ impl Vm {
} => {
let assignee_position = assignee.position();
let assignee = self
.run_expression(assignee, collect_garbage)?
.run_expression(assignee, context, collect_garbage)?
.expect_value(assignee_position)?;
let modifier_position = modifier.position();
let modifier = self
.run_expression(modifier, collect_garbage)?
.run_expression(modifier, context, collect_garbage)?
.expect_value(modifier_position)?;
match operator.inner {
@ -631,7 +620,7 @@ impl Vm {
OperatorExpression::Negation(expression) => {
let position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.run_expression(expression, context, collect_garbage)?
.expect_value(position)?;
let negated = value.negate().map_err(|error| RuntimeError::ValueError {
error,
@ -644,7 +633,7 @@ impl Vm {
OperatorExpression::Not(expression) => {
let position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.run_expression(expression, context, collect_garbage)?
.expect_value(position)?;
let not = value.not().map_err(|error| RuntimeError::ValueError {
error,
@ -661,11 +650,11 @@ impl Vm {
} => {
let left_position = left.position();
let left_value = self
.run_expression(left, collect_garbage)?
.run_expression(left, context, collect_garbage)?
.expect_value(left_position)?;
let right_position = right.position();
let right_value = self
.run_expression(right, collect_garbage)?
.run_expression(right, context, collect_garbage)?
.expect_value(right_position)?;
let outcome = match operator.inner {
MathOperator::Add => left_value.add(&right_value),
@ -689,11 +678,11 @@ impl Vm {
} => {
let left_position = left.position();
let left_value = self
.run_expression(left, collect_garbage)?
.run_expression(left, context, collect_garbage)?
.expect_value(left_position)?;
let right_position = right.position();
let right_value = self
.run_expression(right, collect_garbage)?
.run_expression(right, context, collect_garbage)?
.expect_value(right_position)?;
let outcome = match operator.inner {
LogicOperator::And => left_value.and(&right_value),
@ -710,14 +699,18 @@ impl Vm {
}
}
fn run_loop(&self, loop_expression: LoopExpression) -> Result<Evaluation, RuntimeError> {
fn run_loop(
&self,
loop_expression: LoopExpression,
context: &Context,
) -> Result<Evaluation, RuntimeError> {
match loop_expression {
LoopExpression::Infinite {
block: Node { inner, .. },
} => match inner {
BlockExpression::Sync(statements) => 'outer: loop {
for statement in statements.clone() {
let evaluation = self.run_statement(statement, false)?;
BlockExpression::Sync(ast) => 'outer: loop {
for statement in ast.statements.clone() {
let evaluation = self.run_statement(statement, &ast.context, false)?;
if let Evaluation::Break(value_option) = evaluation {
break 'outer Ok(Evaluation::Return(value_option));
@ -728,14 +721,14 @@ impl Vm {
},
LoopExpression::While { condition, block } => {
while self
.run_expression(condition.clone(), false)?
.run_expression(condition.clone(), context, false)?
.expect_value(condition.position())?
.as_boolean()
.ok_or_else(|| RuntimeError::ExpectedBoolean {
position: condition.position(),
})?
{
self.run_block(block.inner.clone(), false)?;
self.run_block(block.inner.clone(), context, false)?;
}
Ok(Evaluation::Return(None))
@ -764,18 +757,19 @@ impl Vm {
fn run_list_index(
&self,
list_index: ListIndexExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let ListIndexExpression { list, index } = list_index;
let list_position = list.position();
let list_value = self
.run_expression(list, collect_garbage)?
.run_expression(list, context, collect_garbage)?
.expect_value(list_position)?;
let index_position = index.position();
let index_value = self
.run_expression(index, collect_garbage)?
.run_expression(index, context, collect_garbage)?
.expect_value(index_position)?;
let get_index =
@ -793,6 +787,7 @@ impl Vm {
fn run_call(
&self,
call_expression: CallExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let CallExpression { invoker, arguments } = call_expression;
@ -803,7 +798,7 @@ impl Vm {
let container_position = container.position();
let container_value = self
.run_expression(container, collect_garbage)?
.run_expression(container, context, collect_garbage)?
.expect_value(container_position)?;
let function = if let Some(value) = container_value.get_field(&field.inner) {
@ -848,7 +843,7 @@ impl Vm {
for argument in arguments {
let position = argument.position();
let value = self
.run_expression(argument, collect_garbage)?
.run_expression(argument, context, collect_garbage)?
.expect_value(position)?;
value_arguments.push(value);
@ -866,7 +861,7 @@ impl Vm {
}
let invoker_position = invoker.position();
let run_invoker = self.run_expression(invoker, collect_garbage)?;
let run_invoker = self.run_expression(invoker, context, collect_garbage)?;
match run_invoker {
Evaluation::Constructor(constructor) => {
@ -875,7 +870,10 @@ impl Vm {
for argument in arguments {
let position = argument.position();
if let Some(value) = self.run_expression(argument, collect_garbage)?.value() {
if let Some(value) = self
.run_expression(argument, context, collect_garbage)?
.value()
{
fields.push(value);
} else {
return Err(RuntimeError::ExpectedValue { position });
@ -925,7 +923,7 @@ impl Vm {
for argument in arguments {
let position = argument.position();
let value = self
.run_expression(argument, collect_garbage)?
.run_expression(argument, context, collect_garbage)?
.expect_value(position)?;
if let Some(value_arguments) = &mut value_arguments {
@ -954,19 +952,22 @@ impl Vm {
fn run_field_access(
&self,
field_access: FieldAccessExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let FieldAccessExpression { container, field } = field_access;
let container_position = container.position();
let container_value =
if let Some(value) = self.run_expression(container, collect_garbage)?.value() {
value
} else {
return Err(RuntimeError::ExpectedValue {
position: container_position,
});
};
let container_value = if let Some(value) = self
.run_expression(container, context, collect_garbage)?
.value()
{
value
} else {
return Err(RuntimeError::ExpectedValue {
position: container_position,
});
};
Ok(Evaluation::Return(container_value.get_field(&field.inner)))
}
@ -974,6 +975,7 @@ impl Vm {
fn run_list(
&self,
list_expression: ListExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match list_expression {
@ -983,14 +985,14 @@ impl Vm {
} => {
let position = length_operand.position();
let length = self
.run_expression(length_operand, collect_garbage)?
.run_expression(length_operand, context, collect_garbage)?
.expect_value(position)?
.as_integer()
.ok_or(RuntimeError::ExpectedInteger { position })?;
let position = repeat_operand.position();
let value = self
.run_expression(repeat_operand, collect_garbage)?
.run_expression(repeat_operand, context, collect_garbage)?
.expect_value(position)?;
Ok(Evaluation::Return(Some(Value::list(vec![
@ -1004,7 +1006,7 @@ impl Vm {
for expression in expressions {
let position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.run_expression(expression, context, collect_garbage)?
.expect_value(position)?;
values.push(value);
@ -1018,20 +1020,16 @@ impl Vm {
fn run_block(
&self,
block: BlockExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let block_context = self.context.create_child();
let vm = Vm::new(block_context);
match block {
BlockExpression::Async(statements) => vm
.run_async(AbstractSyntaxTree::with_statements(statements))
.map(Evaluation::Return),
BlockExpression::Sync(statements) => {
BlockExpression::Async(ast) => Vm.run_async(ast).map(Evaluation::Return),
BlockExpression::Sync(ast) => {
let mut evaluation = Evaluation::Return(None);
for statement in statements {
evaluation = vm.run_statement(statement, collect_garbage)?;
for statement in ast.statements {
evaluation = Vm.run_statement(statement, &ast.context, collect_garbage)?;
if let Evaluation::Break(_) = evaluation {
return Ok(evaluation);
@ -1046,6 +1044,7 @@ impl Vm {
fn run_if(
&self,
if_expression: IfExpression,
context: &Context,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match if_expression {
@ -1055,13 +1054,13 @@ impl Vm {
} => {
let position = condition.position();
let boolean = self
.run_expression(condition, collect_garbage)?
.run_expression(condition, context, collect_garbage)?
.expect_value(position)?
.as_boolean()
.ok_or(RuntimeError::ExpectedBoolean { position })?;
if boolean {
let evaluation = self.run_block(if_block.inner, collect_garbage)?;
let evaluation = self.run_block(if_block.inner, context, collect_garbage)?;
if let Evaluation::Break(_) = evaluation {
return Ok(evaluation);
@ -1077,20 +1076,20 @@ impl Vm {
} => {
let position = condition.position();
let boolean = self
.run_expression(condition, collect_garbage)?
.run_expression(condition, context, collect_garbage)?
.expect_value(position)?
.as_boolean()
.ok_or(RuntimeError::ExpectedBoolean { position })?;
if boolean {
self.run_block(if_block.inner, collect_garbage)
self.run_block(if_block.inner, context, collect_garbage)
} else {
match r#else {
ElseExpression::If(if_expression) => {
self.run_if(*if_expression.inner, collect_garbage)
self.run_if(*if_expression.inner, context, collect_garbage)
}
ElseExpression::Block(block) => {
self.run_block(block.inner, collect_garbage)
self.run_block(block.inner, context, collect_garbage)
}
}
}