diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 184dd57..8bd5771 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::{ + context::Context, error::{RuntimeError, SyntaxError, ValidationError}, AbstractTree, AssignmentOperator, Format, Identifier, Map, SourcePosition, Statement, SyntaxNode, Type, TypeSpecification, Value, @@ -21,7 +22,7 @@ impl AbstractTree for Assignment { fn from_syntax( syntax_node: SyntaxNode, source: &str, - context: &Map, + context: &Context, ) -> Result { SyntaxError::expect_syntax_node(source, "assignment", syntax_node)?; @@ -52,7 +53,7 @@ impl AbstractTree for Assignment { }) } - fn validate(&self, source: &str, context: &Map) -> Result<(), ValidationError> { + fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> { if let AssignmentOperator::Equal = self.operator { let key = self.identifier.inner().clone(); let r#type = if let Some(definition) = &self.type_specification { diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index aaeeeca..b00c34f 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -20,6 +20,7 @@ use crate::{ pub struct Block { is_async: bool, statements: Vec, + context: Map, } impl AbstractTree for Block { @@ -35,12 +36,13 @@ impl AbstractTree for Block { node.child_count() - 2 }; let mut statements = Vec::with_capacity(statement_count); + let block_context = Map::clone_from(context)?; for index in 1..node.child_count() - 1 { let child_node = node.child(index).unwrap(); if child_node.kind() == "statement" { - let statement = Statement::from_syntax(child_node, source, context)?; + let statement = Statement::from_syntax(child_node, source, &block_context)?; statements.push(statement); } @@ -49,15 +51,16 @@ impl AbstractTree for Block { Ok(Block { is_async, statements, + context: block_context, }) } fn validate(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { for statement in &self.statements { if let Statement::Return(inner_statement) = statement { - return inner_statement.validate(_source, _context); + return inner_statement.validate(_source, &self.context); } else { - statement.validate(_source, _context)?; + statement.validate(_source, &self.context)?; } } @@ -73,7 +76,7 @@ impl AbstractTree for Block { .into_par_iter() .enumerate() .find_map_first(|(index, statement)| { - let result = statement.run(source, context); + let result = statement.run(source, &self.context); let is_last_statement = index == statements.len() - 1; let is_return_statement = if let Statement::Return(_) = statement { true diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 415e132..4106da4 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -11,7 +11,7 @@ use crate::{ /// /// Every variable is a key-value pair. An identifier holds the key part of that /// pair. Its inner value can be used to retrieve a Value instance from a Map. -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct Identifier(String); impl Identifier { diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 1d2dd56..f8e0fe0 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -45,6 +45,7 @@ pub use { use serde::{Deserialize, Serialize}; use crate::{ + context::Context, error::{RuntimeError, SyntaxError, ValidationError}, Map, SyntaxNode, Value, }; @@ -81,7 +82,7 @@ pub struct Root { // instead of indexes. This will be more performant when there are a lot of // top-level statements in the tree. impl AbstractTree for Root { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result { SyntaxError::expect_syntax_node(source, "root", node)?; let statement_count = node.child_count(); @@ -97,7 +98,7 @@ impl AbstractTree for Root { Ok(Root { statements }) } - fn validate(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { for statement in &self.statements { if let Statement::Return(inner_statement) = statement { return inner_statement.validate(_source, _context); @@ -109,7 +110,7 @@ impl AbstractTree for Root { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Context) -> Result { let mut value = Value::none(); for statement in &self.statements { @@ -123,7 +124,7 @@ impl AbstractTree for Root { Ok(value) } - fn expected_type(&self, context: &Map) -> Result { + fn expected_type(&self, context: &Context) -> Result { self.statements.last().unwrap().expected_type(context) } } @@ -153,18 +154,18 @@ pub trait AbstractTree: Sized + Format { /// /// If necessary, the source code can be accessed directly by getting the /// node's byte range. - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result; + fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result; /// Return the type of the value that this abstract node will create when run. Returns a /// validation error if the tree is invalid. - fn expected_type(&self, context: &Map) -> Result; + fn expected_type(&self, context: &Context) -> Result; /// Verify the type integrity of the node. Returns a validation error if the tree is invalid. - fn validate(&self, source: &str, context: &Map) -> Result<(), ValidationError>; + fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError>; /// Execute this node's logic and return a value. Returns a runtime error if the node cannot /// resolve to a value. - fn run(&self, source: &str, context: &Map) -> Result; + fn run(&self, source: &str, context: &Context) -> Result; } pub trait Format { diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..69b15b7 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,88 @@ +use std::{ + collections::HashMap, + sync::{Arc, RwLock, RwLockReadGuard}, +}; + +use crate::{error::rw_lock_error::RwLockError, Type, Value}; + +#[derive(Clone)] +pub enum ValueData { + Value { + inner: Value, + runtime_uses: Arc>, + }, + ExpectedType { + inner: Type, + }, +} + +pub struct Context { + inner: Arc>>, +} + +impl Context { + pub fn new() -> Self { + Self { + inner: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub fn inherit_from(other: &Context) -> Result { + let mut new_variables = HashMap::new(); + + for (identifier, value_data) in other.variables()?.iter() { + new_variables.insert(identifier.clone(), value_data.clone()); + } + + Ok(Context { + inner: Arc::new(RwLock::new(new_variables)), + }) + } + + pub fn variables(&self) -> Result>, RwLockError> { + Ok(self.inner.read()?) + } + + pub fn get_value(&self, key: &str) -> Result, RwLockError> { + if let Some(value_data) = self.inner.read()?.get(key) { + if let ValueData::Value { inner, .. } = value_data { + Ok(Some(inner)) + } else { + Ok(None) + } + } else { + Ok(None) + } + } + + pub fn get_type(&self, key: &str) -> Result, RwLockError> { + if let Some(value_data) = self.inner.read()?.get(key) { + match value_data { + ValueData::Value { inner, .. } => Ok(Some(inner.r#type())), + ValueData::ExpectedType { inner, .. } => Ok(Some(inner.clone())), + } + } else { + Ok(None) + } + } + + pub fn set_value(&self, key: String, value: Value) -> Result<(), RwLockError> { + self.inner.write()?.insert( + key, + ValueData::Value { + inner: value, + runtime_uses: Arc::new(RwLock::new(0)), + }, + ); + + Ok(()) + } + + pub fn set_type(&self, key: String, r#type: Type) -> Result<(), RwLockError> { + self.inner + .write()? + .insert(key, ValueData::ExpectedType { inner: r#type }); + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7c50ec8..fcac506 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -#![warn(missing_docs)] //! The Dust library is used to parse, format and run dust source code. //! //! See the [interpret] module for more information. @@ -13,6 +12,7 @@ pub use tree_sitter::Node as SyntaxNode; pub mod abstract_tree; pub mod built_in_functions; +pub mod context; pub mod error; pub mod interpret; pub mod value;