Try embedding contexts in the AST
This commit is contained in:
parent
d032334635
commit
012728b00a
@ -17,8 +17,8 @@ use crate::{
|
|||||||
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
||||||
StructExpression, TupleAccessExpression,
|
StructExpression, TupleAccessExpression,
|
||||||
},
|
},
|
||||||
core_library, parse, Context, ContextError, DustError, Expression, Identifier, RangeableType,
|
parse, ContextError, DustError, Expression, Identifier, RangeableType, StructType, Type,
|
||||||
StructType, Type, TypeConflict, TypeEvaluation,
|
TypeConflict, TypeEvaluation,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Analyzes the abstract syntax tree for errors.
|
/// Analyzes the abstract syntax tree for errors.
|
||||||
@ -34,8 +34,7 @@ use crate::{
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn analyze(source: &str) -> Result<(), DustError> {
|
pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||||
let abstract_tree = parse(source)?;
|
let abstract_tree = parse(source)?;
|
||||||
let context = core_library().create_child();
|
let mut analyzer = Analyzer::new(&abstract_tree);
|
||||||
let mut analyzer = Analyzer::new(&abstract_tree, context);
|
|
||||||
|
|
||||||
analyzer.analyze();
|
analyzer.analyze();
|
||||||
|
|
||||||
@ -61,15 +60,13 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
|
|||||||
/// assert!(!analyzer.errors.is_empty());
|
/// assert!(!analyzer.errors.is_empty());
|
||||||
pub struct Analyzer<'a> {
|
pub struct Analyzer<'a> {
|
||||||
abstract_tree: &'a AbstractSyntaxTree,
|
abstract_tree: &'a AbstractSyntaxTree,
|
||||||
context: Context,
|
|
||||||
pub errors: Vec<AnalysisError>,
|
pub errors: Vec<AnalysisError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Analyzer<'a> {
|
impl<'a> Analyzer<'a> {
|
||||||
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: Context) -> Self {
|
pub fn new(abstract_tree: &'a AbstractSyntaxTree) -> Self {
|
||||||
Self {
|
Self {
|
||||||
abstract_tree,
|
abstract_tree,
|
||||||
context,
|
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,14 +88,14 @@ impl<'a> Analyzer<'a> {
|
|||||||
Statement::Let(let_statement) => match &let_statement.inner {
|
Statement::Let(let_statement) => match &let_statement.inner {
|
||||||
LetStatement::Let { identifier, value }
|
LetStatement::Let { identifier, value }
|
||||||
| LetStatement::LetMut { 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) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => {
|
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(),
|
identifier.inner.clone(),
|
||||||
Type::Struct(StructType::Unit { name }),
|
Type::Struct(StructType::Unit { name }),
|
||||||
statement.position(),
|
statement.position(),
|
||||||
@ -119,7 +116,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(r#type) = r#type {
|
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(),
|
identifier.inner.clone(),
|
||||||
r#type.clone(),
|
r#type.clone(),
|
||||||
statement.position(),
|
statement.position(),
|
||||||
@ -145,17 +142,19 @@ impl<'a> Analyzer<'a> {
|
|||||||
},
|
},
|
||||||
Statement::StructDefinition(struct_definition) => {
|
Statement::StructDefinition(struct_definition) => {
|
||||||
let set_constructor_type = match &struct_definition.inner {
|
let set_constructor_type = match &struct_definition.inner {
|
||||||
StructDefinition::Unit { name } => self.context.set_constructor_type(
|
StructDefinition::Unit { name } => {
|
||||||
name.inner.clone(),
|
self.abstract_tree.context.set_constructor_type(
|
||||||
StructType::Unit {
|
name.inner.clone(),
|
||||||
name: name.inner.clone(),
|
StructType::Unit {
|
||||||
},
|
name: name.inner.clone(),
|
||||||
statement.position(),
|
},
|
||||||
),
|
statement.position(),
|
||||||
|
)
|
||||||
|
}
|
||||||
StructDefinition::Tuple { name, items } => {
|
StructDefinition::Tuple { name, items } => {
|
||||||
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
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(),
|
name.inner.clone(),
|
||||||
StructType::Tuple {
|
StructType::Tuple {
|
||||||
name: name.inner.clone(),
|
name: name.inner.clone(),
|
||||||
@ -172,7 +171,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.context.set_constructor_type(
|
self.abstract_tree.context.set_constructor_type(
|
||||||
name.inner.clone(),
|
name.inner.clone(),
|
||||||
StructType::Fields {
|
StructType::Fields {
|
||||||
name: name.inner.clone(),
|
name: name.inner.clone(),
|
||||||
@ -206,7 +205,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
self.analyze_expression(invoker, statement_position);
|
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,
|
Ok(evaluation) => evaluation,
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
@ -219,14 +219,15 @@ impl<'a> Analyzer<'a> {
|
|||||||
invoker_evaluation
|
invoker_evaluation
|
||||||
{
|
{
|
||||||
for (expected_type, argument) in fields.iter().zip(arguments.iter()) {
|
for (expected_type, argument) in fields.iter().zip(arguments.iter()) {
|
||||||
let actual_type = match argument.type_evaluation(&self.context) {
|
let actual_type =
|
||||||
Ok(evaluation) => evaluation.r#type(),
|
match argument.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation.r#type(),
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(r#type) = actual_type {
|
if let Some(r#type) = actual_type {
|
||||||
let check = expected_type.check(&r#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) {
|
for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) {
|
||||||
self.analyze_expression(argument, statement_position);
|
self.analyze_expression(argument, statement_position);
|
||||||
|
|
||||||
let argument_evaluation = match argument.type_evaluation(&self.context) {
|
let argument_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match argument.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(error));
|
Err(error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(error));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let actual_type = if let Some(r#type) = argument_evaluation.r#type() {
|
let actual_type = if let Some(r#type) = argument_evaluation.r#type() {
|
||||||
r#type
|
r#type
|
||||||
@ -321,7 +323,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
let FieldAccessExpression { container, field } =
|
let FieldAccessExpression { container, field } =
|
||||||
field_access_expression.inner.as_ref();
|
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,
|
Ok(evaluation) => evaluation,
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
@ -355,6 +357,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let find_identifier = self
|
let find_identifier = self
|
||||||
|
.abstract_tree
|
||||||
.context
|
.context
|
||||||
.update_last_position(&identifier.inner, statement_position);
|
.update_last_position(&identifier.inner, statement_position);
|
||||||
|
|
||||||
@ -394,7 +397,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(list, statement_position);
|
self.analyze_expression(list, statement_position);
|
||||||
self.analyze_expression(index, 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,
|
Ok(evaluation) => evaluation,
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
@ -413,7 +416,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
return;
|
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,
|
Ok(evaluation) => evaluation,
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(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(assignee, statement_position);
|
||||||
self.analyze_expression(modifier, statement_position);
|
self.analyze_expression(modifier, statement_position);
|
||||||
|
|
||||||
let assignee_type_evaluation = match assignee.type_evaluation(&self.context) {
|
let assignee_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match assignee.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let modifier_type_evaluation = match modifier.type_evaluation(&self.context) {
|
let modifier_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match modifier.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (expected_type, actual_type) = match (
|
let (expected_type, actual_type) = match (
|
||||||
assignee_type_evaluation.r#type(),
|
assignee_type_evaluation.r#type(),
|
||||||
@ -608,22 +614,24 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(left, statement_position);
|
self.analyze_expression(left, statement_position);
|
||||||
self.analyze_expression(right, statement_position);
|
self.analyze_expression(right, statement_position);
|
||||||
|
|
||||||
let left_type_evaluation = match left.type_evaluation(&self.context) {
|
let left_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match left.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let right_type_evaluation = match right.type_evaluation(&self.context) {
|
let right_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match right.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (left_type, right_type) = match (
|
let (left_type, right_type) = match (
|
||||||
left_type_evaluation.r#type(),
|
left_type_evaluation.r#type(),
|
||||||
@ -704,22 +712,24 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(left, statement_position);
|
self.analyze_expression(left, statement_position);
|
||||||
self.analyze_expression(right, statement_position);
|
self.analyze_expression(right, statement_position);
|
||||||
|
|
||||||
let left_type_evaluation = match left.type_evaluation(&self.context) {
|
let left_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match left.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let right_type_evaluation = match right.type_evaluation(&self.context) {
|
let right_type_evaluation =
|
||||||
Ok(evaluation) => evaluation,
|
match right.type_evaluation(&self.abstract_tree.context) {
|
||||||
Err(ast_error) => {
|
Ok(evaluation) => evaluation,
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (left_type, right_type) = match (
|
let (left_type, right_type) = match (
|
||||||
left_type_evaluation.r#type(),
|
left_type_evaluation.r#type(),
|
||||||
@ -775,6 +785,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||||
StructExpression::Fields { name, fields } => {
|
StructExpression::Fields { name, fields } => {
|
||||||
let update_position = self
|
let update_position = self
|
||||||
|
.abstract_tree
|
||||||
.context
|
.context
|
||||||
.update_last_position(&name.inner, statement_position);
|
.update_last_position(&name.inner, statement_position);
|
||||||
|
|
||||||
@ -795,7 +806,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
Expression::TupleAccess(tuple_access) => {
|
Expression::TupleAccess(tuple_access) => {
|
||||||
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
|
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,
|
Ok(evaluation) => evaluation,
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(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) {
|
fn analyze_block(&mut self, block_expression: &BlockExpression) {
|
||||||
match block_expression {
|
let ast = match block_expression {
|
||||||
BlockExpression::Async(statements) => {
|
BlockExpression::Async(ast) => ast,
|
||||||
for statement in statements {
|
BlockExpression::Sync(ast) => ast,
|
||||||
self.analyze_statement(statement);
|
};
|
||||||
}
|
|
||||||
}
|
ast.context
|
||||||
BlockExpression::Sync(statements) => {
|
.assign_parent(self.abstract_tree.context.clone());
|
||||||
for statement in statements {
|
|
||||||
self.analyze_statement(statement);
|
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) {
|
fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{HashMap, VecDeque},
|
collections::HashMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ use crate::{
|
|||||||
TypeEvaluation, ValueData,
|
TypeEvaluation, ValueData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AstError, Node, Span, Statement};
|
use super::{AbstractSyntaxTree, AstError, Node, Span};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
@ -1139,16 +1139,16 @@ 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(VecDeque<Statement>),
|
Async(AbstractSyntaxTree),
|
||||||
Sync(VecDeque<Statement>),
|
Sync(AbstractSyntaxTree),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockExpression {
|
impl BlockExpression {
|
||||||
fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
|
fn type_evaluation(&self, _: &Context) -> Result<TypeEvaluation, AstError> {
|
||||||
match self {
|
match self {
|
||||||
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
|
BlockExpression::Async(ast) | BlockExpression::Sync(ast) => {
|
||||||
if let Some(statement) = statements.back() {
|
if let Some(statement) = ast.statements.back() {
|
||||||
statement.type_evaluation(context)
|
statement.type_evaluation(&ast.context)
|
||||||
} else {
|
} else {
|
||||||
Ok(TypeEvaluation::Return(None))
|
Ok(TypeEvaluation::Return(None))
|
||||||
}
|
}
|
||||||
@ -1160,10 +1160,10 @@ impl BlockExpression {
|
|||||||
impl Display for BlockExpression {
|
impl Display for BlockExpression {
|
||||||
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 {
|
||||||
BlockExpression::Async(statements) => {
|
BlockExpression::Async(ast) => {
|
||||||
write!(f, "async {{ ")?;
|
write!(f, "async {{ ")?;
|
||||||
|
|
||||||
for (i, statement) in statements.iter().enumerate() {
|
for (i, statement) in ast.statements.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
}
|
}
|
||||||
@ -1173,10 +1173,10 @@ impl Display for BlockExpression {
|
|||||||
|
|
||||||
write!(f, " }}")
|
write!(f, " }}")
|
||||||
}
|
}
|
||||||
BlockExpression::Sync(statements) => {
|
BlockExpression::Sync(ast) => {
|
||||||
write!(f, "{{ ")?;
|
write!(f, "{{ ")?;
|
||||||
|
|
||||||
for (i, statement) in statements.iter().enumerate() {
|
for (i, statement) in ast.statements.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
}
|
}
|
||||||
|
@ -13,26 +13,51 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ContextError;
|
use crate::{Context, ContextError};
|
||||||
|
|
||||||
pub type Span = (usize, usize);
|
pub type Span = (usize, usize);
|
||||||
|
|
||||||
/// In-memory representation of a Dust program.
|
/// 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 struct AbstractSyntaxTree {
|
||||||
pub statements: VecDeque<Statement>,
|
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 {
|
impl AbstractSyntaxTree {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
statements: VecDeque::new(),
|
statements: VecDeque::new(),
|
||||||
|
context: Context::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_statements<T: Into<VecDeque<Statement>>>(statements: T) -> Self {
|
pub fn with_statements<T: Into<VecDeque<Statement>>>(statements: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
statements: statements.into(),
|
statements: statements.into(),
|
||||||
|
context: Context::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub type Associations = HashMap<Identifier, (ContextData, Span)>;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
associations: Arc<RwLock<Associations>>,
|
associations: Arc<RwLock<Associations>>,
|
||||||
parent: Option<Box<Context>>,
|
parent: Arc<RwLock<Option<Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
@ -24,7 +24,7 @@ impl Context {
|
|||||||
pub fn with_data(data: Associations) -> Self {
|
pub fn with_data(data: Associations) -> Self {
|
||||||
Self {
|
Self {
|
||||||
associations: Arc::new(RwLock::new(data)),
|
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 {
|
pub fn create_child(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
associations: Arc::new(RwLock::new(HashMap::new())),
|
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.
|
/// Returns the number of associated identifiers in the context.
|
||||||
pub fn association_count(&self) -> Result<usize, ContextError> {
|
pub fn association_count(&self) -> Result<usize, ContextError> {
|
||||||
Ok(self.associations.read()?.len())
|
Ok(self.associations.read()?.len())
|
||||||
@ -49,7 +53,7 @@ impl Context {
|
|||||||
pub fn contains(&self, identifier: &Identifier) -> Result<bool, ContextError> {
|
pub fn contains(&self, identifier: &Identifier) -> Result<bool, ContextError> {
|
||||||
if self.associations.read()?.contains_key(identifier) {
|
if self.associations.read()?.contains_key(identifier) {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else if let Some(parent) = &self.parent {
|
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
|
||||||
parent.contains(identifier)
|
parent.contains(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
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)
|
parent.get_type(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -88,7 +92,7 @@ impl Context {
|
|||||||
pub fn get_data(&self, identifier: &Identifier) -> Result<Option<ContextData>, ContextError> {
|
pub fn get_data(&self, identifier: &Identifier) -> Result<Option<ContextData>, ContextError> {
|
||||||
if let Some((variable_data, _)) = self.associations.read()?.get(identifier) {
|
if let Some((variable_data, _)) = self.associations.read()?.get(identifier) {
|
||||||
Ok(Some(variable_data.clone()))
|
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)
|
parent.get_data(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -104,7 +108,7 @@ impl Context {
|
|||||||
self.associations.read()?.get(identifier)
|
self.associations.read()?.get(identifier)
|
||||||
{
|
{
|
||||||
Ok(Some(value.clone()))
|
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)
|
parent.get_variable_value(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -120,7 +124,7 @@ impl Context {
|
|||||||
self.associations.read()?.get(identifier)
|
self.associations.read()?.get(identifier)
|
||||||
{
|
{
|
||||||
Ok(Some(constructor.clone()))
|
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)
|
parent.get_constructor(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -140,7 +144,7 @@ impl Context {
|
|||||||
ContextData::ConstructorType(struct_type) => Ok(Some(struct_type.clone())),
|
ContextData::ConstructorType(struct_type) => Ok(Some(struct_type.clone())),
|
||||||
_ => Ok(None),
|
_ => 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)
|
parent.get_constructor_type(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -285,7 +289,7 @@ impl Context {
|
|||||||
log::trace!("Updating {identifier}'s last position to {position:?}");
|
log::trace!("Updating {identifier}'s last position to {position:?}");
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else if let Some(parent) = &self.parent {
|
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
|
||||||
parent.contains(identifier)
|
parent.contains(identifier)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@ -372,7 +376,7 @@ impl Display for ContextError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::vm::run_with_context;
|
use crate::{parse, run, Vm};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -384,29 +388,25 @@ mod tests {
|
|||||||
let z = x + y;
|
let z = x + y;
|
||||||
z
|
z
|
||||||
";
|
";
|
||||||
let context = Context::new();
|
let ast = parse(source).unwrap();
|
||||||
|
let context = ast.context.clone();
|
||||||
assert_eq!(
|
|
||||||
run_with_context(source, context.clone()),
|
|
||||||
Ok(Some(Value::integer(15)))
|
|
||||||
);
|
|
||||||
|
|
||||||
|
assert_eq!(Vm.run(ast), Ok(Some(Value::integer(15))));
|
||||||
assert_eq!(context.association_count().unwrap(), 0);
|
assert_eq!(context.association_count().unwrap(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn garbage_collector_does_not_break_loops() {
|
fn garbage_collector_does_not_break_loops() {
|
||||||
let source = "
|
let source = "
|
||||||
let y = 1;
|
|
||||||
let mut z = 0;
|
let mut z = 0;
|
||||||
while z < 10 {
|
while z < 10 {
|
||||||
z = z + y
|
z += 1;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let context = Context::new();
|
let ast = parse(source).unwrap();
|
||||||
|
let context = ast.context.clone();
|
||||||
run_with_context(source, context.clone()).unwrap();
|
|
||||||
|
|
||||||
|
assert_eq!(Vm.run(ast), Ok(None));
|
||||||
assert_eq!(context.association_count().unwrap(), 0);
|
assert_eq!(context.association_count().unwrap(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,4 +45,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, RuntimeError, Vm};
|
pub use vm::{run, RuntimeError, Vm};
|
||||||
|
@ -10,7 +10,9 @@ use std::{
|
|||||||
str::ParseBoolError,
|
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.
|
/// Parses the input into an abstract syntax tree.
|
||||||
///
|
///
|
||||||
@ -96,6 +98,7 @@ pub struct Parser<'src> {
|
|||||||
current_token: Token<'src>,
|
current_token: Token<'src>,
|
||||||
current_position: Span,
|
current_position: Span,
|
||||||
mode: ParserMode,
|
mode: ParserMode,
|
||||||
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Parser<'src> {
|
impl<'src> Parser<'src> {
|
||||||
@ -107,6 +110,7 @@ impl<'src> Parser<'src> {
|
|||||||
current_token,
|
current_token,
|
||||||
current_position,
|
current_position,
|
||||||
mode: ParserMode::Normal,
|
mode: ParserMode::Normal,
|
||||||
|
context: Context::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,10 +1015,15 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
|
let ast = AbstractSyntaxTree {
|
||||||
|
statements,
|
||||||
|
context: self.context.create_child(),
|
||||||
|
};
|
||||||
|
|
||||||
return if is_async {
|
return if is_async {
|
||||||
Ok(Node::new(BlockExpression::Async(statements), position))
|
Ok(Node::new(BlockExpression::Async(ast), position))
|
||||||
} else {
|
} 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([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::Expression(Expression::infinite_loop(
|
Statement::Expression(Expression::infinite_loop(
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(VecDeque::from([Statement::ExpressionNullified(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Node::new(Expression::r#break(None, (7, 12)), (7, 13))
|
Statement::ExpressionNullified(Node::new(
|
||||||
)])),
|
Expression::r#break(None, (7, 12)),
|
||||||
|
(7, 13)
|
||||||
|
))
|
||||||
|
])),
|
||||||
(5, 15)
|
(5, 15)
|
||||||
),
|
),
|
||||||
(0, 15)
|
(0, 15)
|
||||||
@ -1238,8 +1250,8 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
statements: [Statement::Expression(Expression::map(
|
Statement::Expression(Expression::map(
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
Node::new(Identifier::new("x"), (6, 7)),
|
Node::new(Identifier::new("x"), (6, 7)),
|
||||||
@ -1255,9 +1267,8 @@ mod tests {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
(0, 31),
|
(0, 31),
|
||||||
))]
|
))
|
||||||
.into(),
|
]))
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1267,42 +1278,39 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
statements: [
|
Statement::Let(Node::new(
|
||||||
Statement::Let(Node::new(
|
LetStatement::LetMut {
|
||||||
LetStatement::LetMut {
|
identifier: Node::new(Identifier::new("x"), (8, 9)),
|
||||||
identifier: Node::new(Identifier::new("x"), (8, 9)),
|
value: Expression::literal(0, (12, 13)),
|
||||||
value: Expression::literal(0, (12, 13)),
|
},
|
||||||
},
|
(0, 14),
|
||||||
(0, 14),
|
)),
|
||||||
)),
|
Statement::ExpressionNullified(Node::new(
|
||||||
Statement::ExpressionNullified(Node::new(
|
Expression::while_loop(
|
||||||
Expression::while_loop(
|
Expression::comparison(
|
||||||
Expression::comparison(
|
Expression::identifier(Identifier::new("x"), (21, 22)),
|
||||||
Expression::identifier(Identifier::new("x"), (21, 22)),
|
Node::new(ComparisonOperator::LessThan, (23, 24)),
|
||||||
Node::new(ComparisonOperator::LessThan, (23, 24)),
|
Expression::literal(10, (25, 27)),
|
||||||
Expression::literal(10, (25, 27)),
|
(21, 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),
|
|
||||||
),
|
),
|
||||||
(15, 39)
|
Node::new(
|
||||||
)),
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),),
|
Statement::Expression(Expression::compound_assignment(
|
||||||
]
|
Expression::identifier(Identifier::new("x"), (30, 31)),
|
||||||
.into()
|
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!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree::with_statements([Statement::Let(
|
||||||
statements: [Statement::Let(Node::new(
|
Node::new(
|
||||||
LetStatement::LetMut {
|
LetStatement::LetMut {
|
||||||
identifier: Node::new(Identifier::new("x"), (8, 9)),
|
identifier: Node::new(Identifier::new("x"), (8, 9)),
|
||||||
value: Expression::literal(false, (12, 17)),
|
value: Expression::literal(false, (12, 17)),
|
||||||
},
|
},
|
||||||
(0, 18),
|
(0, 18),
|
||||||
))]
|
)
|
||||||
.into()
|
)]))
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,9 +1356,9 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
statements: [Statement::Expression(Expression::block(
|
Statement::Expression(Expression::block(
|
||||||
BlockExpression::Async(VecDeque::from([
|
BlockExpression::Async(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::operator(
|
Expression::operator(
|
||||||
OperatorExpression::Assignment {
|
OperatorExpression::Assignment {
|
||||||
@ -1371,9 +1378,8 @@ mod tests {
|
|||||||
))
|
))
|
||||||
])),
|
])),
|
||||||
(0, 25)
|
(0, 25)
|
||||||
))]
|
))
|
||||||
.into()
|
]))
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1668,9 +1674,12 @@ 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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Statement::Expression(Expression::identifier(
|
||||||
)])),
|
Identifier::new("y"),
|
||||||
|
(7, 8)
|
||||||
|
))
|
||||||
|
])),
|
||||||
(5, 10)
|
(5, 10)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -1691,15 +1700,21 @@ 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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Statement::Expression(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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("z"), (18, 19))
|
Statement::Expression(Expression::identifier(
|
||||||
)])),
|
Identifier::new("z"),
|
||||||
|
(18, 19)
|
||||||
|
))
|
||||||
|
])),
|
||||||
(16, 21)
|
(16, 21)
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
@ -1720,24 +1735,33 @@ 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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("y"), (7, 8))
|
Statement::Expression(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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("a"), (23, 24))
|
Statement::Expression(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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::identifier(Identifier::new("b"), (34, 35))
|
Statement::Expression(Expression::identifier(
|
||||||
)])),
|
Identifier::new("b"),
|
||||||
|
(34, 35)
|
||||||
|
))
|
||||||
|
])),
|
||||||
(32, 37)
|
(32, 37)
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
@ -1767,8 +1791,8 @@ mod tests {
|
|||||||
(6, 12)
|
(6, 12)
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::operator(
|
Statement::Expression(Expression::operator(
|
||||||
OperatorExpression::CompoundAssignment {
|
OperatorExpression::CompoundAssignment {
|
||||||
assignee: Expression::identifier(
|
assignee: Expression::identifier(
|
||||||
Identifier::new("x"),
|
Identifier::new("x"),
|
||||||
@ -1778,8 +1802,8 @@ mod tests {
|
|||||||
modifier: Expression::literal(1, (20, 21)),
|
modifier: Expression::literal(1, (20, 21)),
|
||||||
},
|
},
|
||||||
(15, 21)
|
(15, 21)
|
||||||
)
|
))
|
||||||
)])),
|
])),
|
||||||
(13, 23)
|
(13, 23)
|
||||||
),
|
),
|
||||||
(0, 23)
|
(0, 23)
|
||||||
@ -1834,16 +1858,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(VecDeque::from([Statement::Expression(
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Expression::operator(
|
Statement::Expression(Expression::operator(
|
||||||
OperatorExpression::Math {
|
OperatorExpression::Math {
|
||||||
left: Expression::literal(40, (2, 4)),
|
left: Expression::literal(40, (2, 4)),
|
||||||
operator: Node::new(MathOperator::Add, (5, 6)),
|
operator: Node::new(MathOperator::Add, (5, 6)),
|
||||||
right: Expression::literal(2, (7, 8)),
|
right: Expression::literal(2, (7, 8)),
|
||||||
},
|
},
|
||||||
(2, 8)
|
(2, 8)
|
||||||
)
|
))
|
||||||
)])),
|
])),
|
||||||
(0, 10)
|
(0, 10)
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
@ -1858,7 +1882,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(VecDeque::from([
|
BlockExpression::Sync(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::assignment(
|
Expression::assignment(
|
||||||
Expression::identifier("foo", (2, 5)),
|
Expression::identifier("foo", (2, 5)),
|
||||||
|
@ -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)))
|
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,28 +37,8 @@ use crate::{
|
|||||||
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
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 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();
|
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 {
|
.map_err(|runtime_error| DustError::Runtime {
|
||||||
runtime_error,
|
runtime_error,
|
||||||
source,
|
source,
|
||||||
@ -85,20 +63,14 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
|
|||||||
/// before running it.
|
/// before running it.
|
||||||
///
|
///
|
||||||
/// 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;
|
||||||
context: Context,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn new(context: Context) -> Self {
|
|
||||||
Self { context }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
||||||
let mut previous_evaluation = Evaluation::Return(None);
|
let mut previous_evaluation = Evaluation::Return(None);
|
||||||
|
|
||||||
while let Some(statement) = 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, &tree.context, true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match previous_evaluation {
|
match previous_evaluation {
|
||||||
@ -117,7 +89,7 @@ impl Vm {
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map_any(|(i, statement)| {
|
.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 {
|
match evaluation_result {
|
||||||
Ok(evaluation_option) => {
|
Ok(evaluation_option) => {
|
||||||
@ -134,21 +106,22 @@ impl Vm {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(error) = error_option {
|
if let Some(error) = error_option {
|
||||||
Err(error)
|
return Err(error);
|
||||||
} else {
|
}
|
||||||
let final_result = final_result.lock().unwrap();
|
|
||||||
|
|
||||||
match &*final_result {
|
let final_result = final_result.lock().unwrap();
|
||||||
Evaluation::Break(value_option) => Ok(value_option.clone()),
|
|
||||||
Evaluation::Return(value_option) => Ok(value_option.clone()),
|
match &*final_result {
|
||||||
_ => Ok(None),
|
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,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
@ -160,10 +133,10 @@ 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(self.run_expression(expression, collect_garbage)?)
|
Ok(self.run_expression(expression, context, collect_garbage)?)
|
||||||
}
|
}
|
||||||
Statement::ExpressionNullified(expression) => {
|
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 {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
Ok(evaluation)
|
Ok(evaluation)
|
||||||
@ -172,7 +145,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Let(let_statement) => {
|
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))
|
Ok(Evaluation::Return(None))
|
||||||
}
|
}
|
||||||
@ -209,7 +182,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
let constructor = struct_type.constructor();
|
let constructor = struct_type.constructor();
|
||||||
|
|
||||||
self.context
|
context
|
||||||
.set_constructor(name, constructor)
|
.set_constructor(name, constructor)
|
||||||
.map_err(|error| RuntimeError::ContextError {
|
.map_err(|error| RuntimeError::ContextError {
|
||||||
error,
|
error,
|
||||||
@ -221,7 +194,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if collect_garbage {
|
if collect_garbage {
|
||||||
self.context
|
context
|
||||||
.collect_garbage(position.1)
|
.collect_garbage(position.1)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
}
|
}
|
||||||
@ -235,13 +208,14 @@ impl Vm {
|
|||||||
fn run_let_statement(
|
fn run_let_statement(
|
||||||
&self,
|
&self,
|
||||||
let_statement: LetStatement,
|
let_statement: LetStatement,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<(), RuntimeError> {
|
) -> Result<(), RuntimeError> {
|
||||||
match let_statement {
|
match let_statement {
|
||||||
LetStatement::Let { identifier, value } => {
|
LetStatement::Let { identifier, value } => {
|
||||||
let position = value.position();
|
let position = value.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(value, collect_garbage)?
|
.run_expression(value, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
let new_value = match value {
|
let new_value = match value {
|
||||||
Value::Mutable(_) => {
|
Value::Mutable(_) => {
|
||||||
@ -250,7 +224,7 @@ impl Vm {
|
|||||||
_ => value,
|
_ => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context
|
context
|
||||||
.set_variable_value(identifier.inner, new_value)
|
.set_variable_value(identifier.inner, new_value)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
|
|
||||||
@ -259,11 +233,11 @@ impl Vm {
|
|||||||
LetStatement::LetMut { identifier, value } => {
|
LetStatement::LetMut { identifier, value } => {
|
||||||
let position = value.position();
|
let position = value.position();
|
||||||
let mutable_value = self
|
let mutable_value = self
|
||||||
.run_expression(value, collect_garbage)?
|
.run_expression(value, context, collect_garbage)?
|
||||||
.expect_value(position)?
|
.expect_value(position)?
|
||||||
.into_mutable();
|
.into_mutable();
|
||||||
|
|
||||||
self.context
|
context
|
||||||
.set_variable_value(identifier.inner, mutable_value)
|
.set_variable_value(identifier.inner, mutable_value)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
|
|
||||||
@ -277,6 +251,7 @@ impl Vm {
|
|||||||
fn run_expression(
|
fn run_expression(
|
||||||
&self,
|
&self,
|
||||||
expression: Expression,
|
expression: Expression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
@ -287,14 +262,16 @@ impl Vm {
|
|||||||
|
|
||||||
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, context, collect_garbage)
|
||||||
|
}
|
||||||
Expression::Break(Node { inner, .. }) => {
|
Expression::Break(Node { inner, .. }) => {
|
||||||
let break_expression = if let Some(expression) = inner {
|
let break_expression = if let Some(expression) = inner {
|
||||||
*expression
|
*expression
|
||||||
} else {
|
} else {
|
||||||
return Ok(Evaluation::Break(None));
|
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 {
|
let evaluation = match run_break {
|
||||||
Evaluation::Break(value_option) => Evaluation::Break(value_option),
|
Evaluation::Break(value_option) => Evaluation::Break(value_option),
|
||||||
Evaluation::Return(value_option) => Evaluation::Break(value_option),
|
Evaluation::Return(value_option) => Evaluation::Break(value_option),
|
||||||
@ -305,9 +282,9 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(evaluation)
|
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, .. }) => {
|
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 {
|
let evaluation = match run_expression {
|
||||||
Evaluation::Constructor(_) => {
|
Evaluation::Constructor(_) => {
|
||||||
return Err(RuntimeError::ExpectedValue { position })
|
return Err(RuntimeError::ExpectedValue { position })
|
||||||
@ -323,30 +300,34 @@ impl Vm {
|
|||||||
Ok(evaluation)
|
Ok(evaluation)
|
||||||
}
|
}
|
||||||
Expression::FieldAccess(field_access) => {
|
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) => {
|
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) => {
|
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) => {
|
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::Literal(literal) => self.run_literal(*literal.inner),
|
||||||
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
|
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner, context),
|
||||||
Expression::Map(map_expression) => self.run_map(*map_expression.inner, collect_garbage),
|
Expression::Map(map_expression) => {
|
||||||
|
self.run_map(*map_expression.inner, context, collect_garbage)
|
||||||
|
}
|
||||||
Expression::Operator(operator_expression) => {
|
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) => {
|
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) => {
|
Expression::Struct(struct_expression) => {
|
||||||
self.run_struct(*struct_expression.inner, collect_garbage)
|
self.run_struct(*struct_expression.inner, context, collect_garbage)
|
||||||
}
|
}
|
||||||
Expression::TupleAccess(_) => todo!(),
|
Expression::TupleAccess(_) => todo!(),
|
||||||
};
|
};
|
||||||
@ -363,13 +344,18 @@ impl Vm {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_identifier(&self, identifier: Node<Identifier>) -> Result<Evaluation, RuntimeError> {
|
fn run_identifier(
|
||||||
let get_data = self.context.get_data(&identifier.inner).map_err(|error| {
|
&self,
|
||||||
RuntimeError::ContextError {
|
identifier: Node<Identifier>,
|
||||||
error,
|
context: &Context,
|
||||||
position: identifier.position,
|
) -> 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 {
|
if let Some(ContextData::VariableValue(value)) = get_data {
|
||||||
return Ok(Evaluation::Return(Some(value)));
|
return Ok(Evaluation::Return(Some(value)));
|
||||||
@ -397,13 +383,13 @@ impl Vm {
|
|||||||
fn run_struct(
|
fn run_struct(
|
||||||
&self,
|
&self,
|
||||||
struct_expression: StructExpression,
|
struct_expression: StructExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let StructExpression::Fields { name, fields } = struct_expression;
|
let StructExpression::Fields { name, fields } = struct_expression;
|
||||||
|
|
||||||
let position = name.position;
|
let position = name.position;
|
||||||
let constructor = self
|
let constructor = context
|
||||||
.context
|
|
||||||
.get_constructor(&name.inner)
|
.get_constructor(&name.inner)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
|
|
||||||
@ -413,7 +399,7 @@ impl Vm {
|
|||||||
for (identifier, expression) in fields {
|
for (identifier, expression) in fields {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(expression, collect_garbage)?
|
.run_expression(expression, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
|
|
||||||
arguments.insert(identifier.inner, value);
|
arguments.insert(identifier.inner, value);
|
||||||
@ -432,13 +418,14 @@ impl Vm {
|
|||||||
fn run_range(
|
fn run_range(
|
||||||
&self,
|
&self,
|
||||||
range: RangeExpression,
|
range: RangeExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
match range {
|
match range {
|
||||||
RangeExpression::Exclusive { start, end } => {
|
RangeExpression::Exclusive { start, end } => {
|
||||||
let start_position = start.position();
|
let start_position = start.position();
|
||||||
let start = self
|
let start = self
|
||||||
.run_expression(start, collect_garbage)?
|
.run_expression(start, context, collect_garbage)?
|
||||||
.expect_value(start_position)?;
|
.expect_value(start_position)?;
|
||||||
|
|
||||||
let start_data = match start {
|
let start_data = match start {
|
||||||
@ -448,7 +435,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
let end_position = end.position();
|
let end_position = end.position();
|
||||||
let end = self
|
let end = self
|
||||||
.run_expression(end, collect_garbage)?
|
.run_expression(end, context, collect_garbage)?
|
||||||
.expect_value(end_position)?;
|
.expect_value(end_position)?;
|
||||||
let end_data = match end {
|
let end_data = match end {
|
||||||
Value::Raw(data) => data,
|
Value::Raw(data) => data,
|
||||||
@ -478,7 +465,7 @@ impl Vm {
|
|||||||
RangeExpression::Inclusive { start, end } => {
|
RangeExpression::Inclusive { start, end } => {
|
||||||
let start_position = start.position();
|
let start_position = start.position();
|
||||||
let start = self
|
let start = self
|
||||||
.run_expression(start, collect_garbage)?
|
.run_expression(start, context, collect_garbage)?
|
||||||
.expect_value(start_position)?;
|
.expect_value(start_position)?;
|
||||||
|
|
||||||
let start_data = match start {
|
let start_data = match start {
|
||||||
@ -488,7 +475,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
let end_position = end.position();
|
let end_position = end.position();
|
||||||
let end = self
|
let end = self
|
||||||
.run_expression(end, collect_garbage)?
|
.run_expression(end, context, collect_garbage)?
|
||||||
.expect_value(end_position)?;
|
.expect_value(end_position)?;
|
||||||
let end_data = match end {
|
let end_data = match end {
|
||||||
Value::Raw(data) => data,
|
Value::Raw(data) => data,
|
||||||
@ -521,6 +508,7 @@ impl Vm {
|
|||||||
fn run_map(
|
fn run_map(
|
||||||
&self,
|
&self,
|
||||||
map: MapExpression,
|
map: MapExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let MapExpression { pairs } = map;
|
let MapExpression { pairs } = map;
|
||||||
@ -530,7 +518,7 @@ impl Vm {
|
|||||||
for (identifier, expression) in pairs {
|
for (identifier, expression) in pairs {
|
||||||
let expression_position = expression.position();
|
let expression_position = expression.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(expression, collect_garbage)?
|
.run_expression(expression, context, collect_garbage)?
|
||||||
.expect_value(expression_position)?;
|
.expect_value(expression_position)?;
|
||||||
|
|
||||||
map.insert(identifier.inner, value);
|
map.insert(identifier.inner, value);
|
||||||
@ -542,17 +530,18 @@ impl Vm {
|
|||||||
fn run_operator(
|
fn run_operator(
|
||||||
&self,
|
&self,
|
||||||
operator: OperatorExpression,
|
operator: OperatorExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> 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();
|
||||||
let assignee = self
|
let assignee = self
|
||||||
.run_expression(assignee, collect_garbage)?
|
.run_expression(assignee, context, collect_garbage)?
|
||||||
.expect_value(assignee_position)?;
|
.expect_value(assignee_position)?;
|
||||||
let value_position = value.position();
|
let value_position = value.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(value, collect_garbage)?
|
.run_expression(value, context, collect_garbage)?
|
||||||
.expect_value(value_position)?;
|
.expect_value(value_position)?;
|
||||||
|
|
||||||
assignee
|
assignee
|
||||||
@ -572,11 +561,11 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let left_position = left.position();
|
let left_position = left.position();
|
||||||
let left_value = self
|
let left_value = self
|
||||||
.run_expression(left, collect_garbage)?
|
.run_expression(left, context, collect_garbage)?
|
||||||
.expect_value(left_position)?;
|
.expect_value(left_position)?;
|
||||||
let right_position = right.position();
|
let right_position = right.position();
|
||||||
let right_value = self
|
let right_value = self
|
||||||
.run_expression(right, collect_garbage)?
|
.run_expression(right, context, collect_garbage)?
|
||||||
.expect_value(right_position)?;
|
.expect_value(right_position)?;
|
||||||
let result = match operator.inner {
|
let result = match operator.inner {
|
||||||
ComparisonOperator::Equal => left_value.equal(&right_value),
|
ComparisonOperator::Equal => left_value.equal(&right_value),
|
||||||
@ -605,11 +594,11 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let assignee_position = assignee.position();
|
let assignee_position = assignee.position();
|
||||||
let assignee = self
|
let assignee = self
|
||||||
.run_expression(assignee, collect_garbage)?
|
.run_expression(assignee, context, collect_garbage)?
|
||||||
.expect_value(assignee_position)?;
|
.expect_value(assignee_position)?;
|
||||||
let modifier_position = modifier.position();
|
let modifier_position = modifier.position();
|
||||||
let modifier = self
|
let modifier = self
|
||||||
.run_expression(modifier, collect_garbage)?
|
.run_expression(modifier, context, collect_garbage)?
|
||||||
.expect_value(modifier_position)?;
|
.expect_value(modifier_position)?;
|
||||||
|
|
||||||
match operator.inner {
|
match operator.inner {
|
||||||
@ -631,7 +620,7 @@ impl Vm {
|
|||||||
OperatorExpression::Negation(expression) => {
|
OperatorExpression::Negation(expression) => {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(expression, collect_garbage)?
|
.run_expression(expression, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
let negated = value.negate().map_err(|error| RuntimeError::ValueError {
|
let negated = value.negate().map_err(|error| RuntimeError::ValueError {
|
||||||
error,
|
error,
|
||||||
@ -644,7 +633,7 @@ impl Vm {
|
|||||||
OperatorExpression::Not(expression) => {
|
OperatorExpression::Not(expression) => {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(expression, collect_garbage)?
|
.run_expression(expression, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
let not = value.not().map_err(|error| RuntimeError::ValueError {
|
let not = value.not().map_err(|error| RuntimeError::ValueError {
|
||||||
error,
|
error,
|
||||||
@ -661,11 +650,11 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let left_position = left.position();
|
let left_position = left.position();
|
||||||
let left_value = self
|
let left_value = self
|
||||||
.run_expression(left, collect_garbage)?
|
.run_expression(left, context, collect_garbage)?
|
||||||
.expect_value(left_position)?;
|
.expect_value(left_position)?;
|
||||||
let right_position = right.position();
|
let right_position = right.position();
|
||||||
let right_value = self
|
let right_value = self
|
||||||
.run_expression(right, collect_garbage)?
|
.run_expression(right, context, collect_garbage)?
|
||||||
.expect_value(right_position)?;
|
.expect_value(right_position)?;
|
||||||
let outcome = match operator.inner {
|
let outcome = match operator.inner {
|
||||||
MathOperator::Add => left_value.add(&right_value),
|
MathOperator::Add => left_value.add(&right_value),
|
||||||
@ -689,11 +678,11 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let left_position = left.position();
|
let left_position = left.position();
|
||||||
let left_value = self
|
let left_value = self
|
||||||
.run_expression(left, collect_garbage)?
|
.run_expression(left, context, collect_garbage)?
|
||||||
.expect_value(left_position)?;
|
.expect_value(left_position)?;
|
||||||
let right_position = right.position();
|
let right_position = right.position();
|
||||||
let right_value = self
|
let right_value = self
|
||||||
.run_expression(right, collect_garbage)?
|
.run_expression(right, context, collect_garbage)?
|
||||||
.expect_value(right_position)?;
|
.expect_value(right_position)?;
|
||||||
let outcome = match operator.inner {
|
let outcome = match operator.inner {
|
||||||
LogicOperator::And => left_value.and(&right_value),
|
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 {
|
match loop_expression {
|
||||||
LoopExpression::Infinite {
|
LoopExpression::Infinite {
|
||||||
block: Node { inner, .. },
|
block: Node { inner, .. },
|
||||||
} => match inner {
|
} => match inner {
|
||||||
BlockExpression::Sync(statements) => 'outer: loop {
|
BlockExpression::Sync(ast) => 'outer: loop {
|
||||||
for statement in statements.clone() {
|
for statement in ast.statements.clone() {
|
||||||
let evaluation = self.run_statement(statement, false)?;
|
let evaluation = self.run_statement(statement, &ast.context, false)?;
|
||||||
|
|
||||||
if let 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));
|
||||||
@ -728,14 +721,14 @@ impl Vm {
|
|||||||
},
|
},
|
||||||
LoopExpression::While { condition, block } => {
|
LoopExpression::While { condition, block } => {
|
||||||
while self
|
while self
|
||||||
.run_expression(condition.clone(), false)?
|
.run_expression(condition.clone(), context, false)?
|
||||||
.expect_value(condition.position())?
|
.expect_value(condition.position())?
|
||||||
.as_boolean()
|
.as_boolean()
|
||||||
.ok_or_else(|| RuntimeError::ExpectedBoolean {
|
.ok_or_else(|| RuntimeError::ExpectedBoolean {
|
||||||
position: condition.position(),
|
position: condition.position(),
|
||||||
})?
|
})?
|
||||||
{
|
{
|
||||||
self.run_block(block.inner.clone(), false)?;
|
self.run_block(block.inner.clone(), context, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Evaluation::Return(None))
|
Ok(Evaluation::Return(None))
|
||||||
@ -764,18 +757,19 @@ impl Vm {
|
|||||||
fn run_list_index(
|
fn run_list_index(
|
||||||
&self,
|
&self,
|
||||||
list_index: ListIndexExpression,
|
list_index: ListIndexExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> 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();
|
||||||
let list_value = self
|
let list_value = self
|
||||||
.run_expression(list, collect_garbage)?
|
.run_expression(list, context, collect_garbage)?
|
||||||
.expect_value(list_position)?;
|
.expect_value(list_position)?;
|
||||||
|
|
||||||
let index_position = index.position();
|
let index_position = index.position();
|
||||||
let index_value = self
|
let index_value = self
|
||||||
.run_expression(index, collect_garbage)?
|
.run_expression(index, context, collect_garbage)?
|
||||||
.expect_value(index_position)?;
|
.expect_value(index_position)?;
|
||||||
|
|
||||||
let get_index =
|
let get_index =
|
||||||
@ -793,6 +787,7 @@ impl Vm {
|
|||||||
fn run_call(
|
fn run_call(
|
||||||
&self,
|
&self,
|
||||||
call_expression: CallExpression,
|
call_expression: CallExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let CallExpression { invoker, arguments } = call_expression;
|
let CallExpression { invoker, arguments } = call_expression;
|
||||||
@ -803,7 +798,7 @@ impl Vm {
|
|||||||
|
|
||||||
let container_position = container.position();
|
let container_position = container.position();
|
||||||
let container_value = self
|
let container_value = self
|
||||||
.run_expression(container, collect_garbage)?
|
.run_expression(container, context, collect_garbage)?
|
||||||
.expect_value(container_position)?;
|
.expect_value(container_position)?;
|
||||||
|
|
||||||
let function = if let Some(value) = container_value.get_field(&field.inner) {
|
let function = if let Some(value) = container_value.get_field(&field.inner) {
|
||||||
@ -848,7 +843,7 @@ impl Vm {
|
|||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
let position = argument.position();
|
let position = argument.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(argument, collect_garbage)?
|
.run_expression(argument, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
|
|
||||||
value_arguments.push(value);
|
value_arguments.push(value);
|
||||||
@ -866,7 +861,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let invoker_position = invoker.position();
|
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 {
|
match run_invoker {
|
||||||
Evaluation::Constructor(constructor) => {
|
Evaluation::Constructor(constructor) => {
|
||||||
@ -875,7 +870,10 @@ impl Vm {
|
|||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
let position = argument.position();
|
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);
|
fields.push(value);
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ExpectedValue { position });
|
return Err(RuntimeError::ExpectedValue { position });
|
||||||
@ -925,7 +923,7 @@ impl Vm {
|
|||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
let position = argument.position();
|
let position = argument.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(argument, collect_garbage)?
|
.run_expression(argument, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
|
|
||||||
if let Some(value_arguments) = &mut value_arguments {
|
if let Some(value_arguments) = &mut value_arguments {
|
||||||
@ -954,19 +952,22 @@ impl Vm {
|
|||||||
fn run_field_access(
|
fn run_field_access(
|
||||||
&self,
|
&self,
|
||||||
field_access: FieldAccessExpression,
|
field_access: FieldAccessExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> 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();
|
||||||
let container_value =
|
let container_value = if let Some(value) = self
|
||||||
if let Some(value) = self.run_expression(container, collect_garbage)?.value() {
|
.run_expression(container, context, collect_garbage)?
|
||||||
value
|
.value()
|
||||||
} else {
|
{
|
||||||
return Err(RuntimeError::ExpectedValue {
|
value
|
||||||
position: container_position,
|
} else {
|
||||||
});
|
return Err(RuntimeError::ExpectedValue {
|
||||||
};
|
position: container_position,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Evaluation::Return(container_value.get_field(&field.inner)))
|
Ok(Evaluation::Return(container_value.get_field(&field.inner)))
|
||||||
}
|
}
|
||||||
@ -974,6 +975,7 @@ impl Vm {
|
|||||||
fn run_list(
|
fn run_list(
|
||||||
&self,
|
&self,
|
||||||
list_expression: ListExpression,
|
list_expression: ListExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
match list_expression {
|
match list_expression {
|
||||||
@ -983,14 +985,14 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let position = length_operand.position();
|
let position = length_operand.position();
|
||||||
let length = self
|
let length = self
|
||||||
.run_expression(length_operand, collect_garbage)?
|
.run_expression(length_operand, context, collect_garbage)?
|
||||||
.expect_value(position)?
|
.expect_value(position)?
|
||||||
.as_integer()
|
.as_integer()
|
||||||
.ok_or(RuntimeError::ExpectedInteger { position })?;
|
.ok_or(RuntimeError::ExpectedInteger { position })?;
|
||||||
|
|
||||||
let position = repeat_operand.position();
|
let position = repeat_operand.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(repeat_operand, collect_garbage)?
|
.run_expression(repeat_operand, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
|
|
||||||
Ok(Evaluation::Return(Some(Value::list(vec![
|
Ok(Evaluation::Return(Some(Value::list(vec![
|
||||||
@ -1004,7 +1006,7 @@ impl Vm {
|
|||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let value = self
|
let value = self
|
||||||
.run_expression(expression, collect_garbage)?
|
.run_expression(expression, context, collect_garbage)?
|
||||||
.expect_value(position)?;
|
.expect_value(position)?;
|
||||||
|
|
||||||
values.push(value);
|
values.push(value);
|
||||||
@ -1018,20 +1020,16 @@ impl Vm {
|
|||||||
fn run_block(
|
fn run_block(
|
||||||
&self,
|
&self,
|
||||||
block: BlockExpression,
|
block: BlockExpression,
|
||||||
|
context: &Context,
|
||||||
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) => vm
|
BlockExpression::Async(ast) => Vm.run_async(ast).map(Evaluation::Return),
|
||||||
.run_async(AbstractSyntaxTree::with_statements(statements))
|
BlockExpression::Sync(ast) => {
|
||||||
.map(Evaluation::Return),
|
|
||||||
BlockExpression::Sync(statements) => {
|
|
||||||
let mut evaluation = Evaluation::Return(None);
|
let mut evaluation = Evaluation::Return(None);
|
||||||
|
|
||||||
for statement in statements {
|
for statement in ast.statements {
|
||||||
evaluation = vm.run_statement(statement, collect_garbage)?;
|
evaluation = Vm.run_statement(statement, &ast.context, collect_garbage)?;
|
||||||
|
|
||||||
if let Evaluation::Break(_) = evaluation {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
return Ok(evaluation);
|
return Ok(evaluation);
|
||||||
@ -1046,6 +1044,7 @@ impl Vm {
|
|||||||
fn run_if(
|
fn run_if(
|
||||||
&self,
|
&self,
|
||||||
if_expression: IfExpression,
|
if_expression: IfExpression,
|
||||||
|
context: &Context,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
match if_expression {
|
match if_expression {
|
||||||
@ -1055,13 +1054,13 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let position = condition.position();
|
let position = condition.position();
|
||||||
let boolean = self
|
let boolean = self
|
||||||
.run_expression(condition, collect_garbage)?
|
.run_expression(condition, context, collect_garbage)?
|
||||||
.expect_value(position)?
|
.expect_value(position)?
|
||||||
.as_boolean()
|
.as_boolean()
|
||||||
.ok_or(RuntimeError::ExpectedBoolean { position })?;
|
.ok_or(RuntimeError::ExpectedBoolean { position })?;
|
||||||
|
|
||||||
if boolean {
|
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 {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
return Ok(evaluation);
|
return Ok(evaluation);
|
||||||
@ -1077,20 +1076,20 @@ impl Vm {
|
|||||||
} => {
|
} => {
|
||||||
let position = condition.position();
|
let position = condition.position();
|
||||||
let boolean = self
|
let boolean = self
|
||||||
.run_expression(condition, collect_garbage)?
|
.run_expression(condition, context, collect_garbage)?
|
||||||
.expect_value(position)?
|
.expect_value(position)?
|
||||||
.as_boolean()
|
.as_boolean()
|
||||||
.ok_or(RuntimeError::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, context, collect_garbage)
|
||||||
} else {
|
} else {
|
||||||
match r#else {
|
match r#else {
|
||||||
ElseExpression::If(if_expression) => {
|
ElseExpression::If(if_expression) => {
|
||||||
self.run_if(*if_expression.inner, collect_garbage)
|
self.run_if(*if_expression.inner, context, collect_garbage)
|
||||||
}
|
}
|
||||||
ElseExpression::Block(block) => {
|
ElseExpression::Block(block) => {
|
||||||
self.run_block(block.inner, collect_garbage)
|
self.run_block(block.inner, context, collect_garbage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user