Try embedding contexts in the AST

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

View File

@ -17,8 +17,8 @@ use crate::{
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, 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) {

View File

@ -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, " ")?;
} }

View File

@ -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(),
} }
} }
} }

View File

@ -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);
} }
} }

View File

@ -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};

View File

@ -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)),

View File

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

View File

@ -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)
} }
} }
} }