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