Begin implementing new Context type
This commit is contained in:
parent
4479f340d7
commit
ddd5912248
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
88
src/context.rs
Normal 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(())
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user