Begin implementing new Context type

This commit is contained in:
Jeff 2024-02-10 18:29:11 -05:00
parent 4479f340d7
commit ddd5912248
6 changed files with 109 additions and 16 deletions

View File

@ -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<Self, SyntaxError> {
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 {

View File

@ -20,6 +20,7 @@ use crate::{
pub struct Block {
is_async: bool,
statements: Vec<Statement>,
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

View File

@ -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 {

View File

@ -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<Self, SyntaxError> {
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
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<Value, RuntimeError> {
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
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<Type, ValidationError> {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
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<Self, SyntaxError>;
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError>;
/// 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<Type, ValidationError>;
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
/// 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<Value, RuntimeError>;
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError>;
}
pub trait Format {

88
src/context.rs Normal file
View File

@ -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<RwLock<u16>>,
},
ExpectedType {
inner: Type,
},
}
pub struct Context {
inner: Arc<RwLock<HashMap<String, ValueData>>>,
}
impl Context {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn inherit_from(other: &Context) -> Result<Context, RwLockError> {
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<RwLockReadGuard<HashMap<String, ValueData>>, RwLockError> {
Ok(self.inner.read()?)
}
pub fn get_value(&self, key: &str) -> Result<Option<&Value>, 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<Option<Type>, 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(())
}
}

View File

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