Begin implementing new Context type
This commit is contained in:
parent
4479f340d7
commit
ddd5912248
@ -1,6 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
context::Context,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, AssignmentOperator, Format, Identifier, Map, SourcePosition, Statement,
|
AbstractTree, AssignmentOperator, Format, Identifier, Map, SourcePosition, Statement,
|
||||||
SyntaxNode, Type, TypeSpecification, Value,
|
SyntaxNode, Type, TypeSpecification, Value,
|
||||||
@ -21,7 +22,7 @@ impl AbstractTree for Assignment {
|
|||||||
fn from_syntax(
|
fn from_syntax(
|
||||||
syntax_node: SyntaxNode,
|
syntax_node: SyntaxNode,
|
||||||
source: &str,
|
source: &str,
|
||||||
context: &Map,
|
context: &Context,
|
||||||
) -> Result<Self, SyntaxError> {
|
) -> Result<Self, SyntaxError> {
|
||||||
SyntaxError::expect_syntax_node(source, "assignment", syntax_node)?;
|
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 {
|
if let AssignmentOperator::Equal = self.operator {
|
||||||
let key = self.identifier.inner().clone();
|
let key = self.identifier.inner().clone();
|
||||||
let r#type = if let Some(definition) = &self.type_specification {
|
let r#type = if let Some(definition) = &self.type_specification {
|
||||||
|
@ -20,6 +20,7 @@ use crate::{
|
|||||||
pub struct Block {
|
pub struct Block {
|
||||||
is_async: bool,
|
is_async: bool,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
|
context: Map,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Block {
|
impl AbstractTree for Block {
|
||||||
@ -35,12 +36,13 @@ impl AbstractTree for Block {
|
|||||||
node.child_count() - 2
|
node.child_count() - 2
|
||||||
};
|
};
|
||||||
let mut statements = Vec::with_capacity(statement_count);
|
let mut statements = Vec::with_capacity(statement_count);
|
||||||
|
let block_context = Map::clone_from(context)?;
|
||||||
|
|
||||||
for index in 1..node.child_count() - 1 {
|
for index in 1..node.child_count() - 1 {
|
||||||
let child_node = node.child(index).unwrap();
|
let child_node = node.child(index).unwrap();
|
||||||
|
|
||||||
if child_node.kind() == "statement" {
|
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);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
@ -49,15 +51,16 @@ impl AbstractTree for Block {
|
|||||||
Ok(Block {
|
Ok(Block {
|
||||||
is_async,
|
is_async,
|
||||||
statements,
|
statements,
|
||||||
|
context: block_context,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
if let Statement::Return(inner_statement) = statement {
|
if let Statement::Return(inner_statement) = statement {
|
||||||
return inner_statement.validate(_source, _context);
|
return inner_statement.validate(_source, &self.context);
|
||||||
} else {
|
} else {
|
||||||
statement.validate(_source, _context)?;
|
statement.validate(_source, &self.context)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,7 @@ impl AbstractTree for Block {
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map_first(|(index, statement)| {
|
.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_last_statement = index == statements.len() - 1;
|
||||||
let is_return_statement = if let Statement::Return(_) = statement {
|
let is_return_statement = if let Statement::Return(_) = statement {
|
||||||
true
|
true
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// Every variable is a key-value pair. An identifier holds the key part of that
|
/// 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.
|
/// 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);
|
pub struct Identifier(String);
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
|
@ -45,6 +45,7 @@ pub use {
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
context::Context,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Map, SyntaxNode, Value,
|
Map, SyntaxNode, Value,
|
||||||
};
|
};
|
||||||
@ -81,7 +82,7 @@ pub struct Root {
|
|||||||
// instead of indexes. This will be more performant when there are a lot of
|
// instead of indexes. This will be more performant when there are a lot of
|
||||||
// top-level statements in the tree.
|
// top-level statements in the tree.
|
||||||
impl AbstractTree for Root {
|
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)?;
|
SyntaxError::expect_syntax_node(source, "root", node)?;
|
||||||
|
|
||||||
let statement_count = node.child_count();
|
let statement_count = node.child_count();
|
||||||
@ -97,7 +98,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(Root { statements })
|
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 {
|
for statement in &self.statements {
|
||||||
if let Statement::Return(inner_statement) = statement {
|
if let Statement::Return(inner_statement) = statement {
|
||||||
return inner_statement.validate(_source, _context);
|
return inner_statement.validate(_source, _context);
|
||||||
@ -109,7 +110,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(())
|
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();
|
let mut value = Value::none();
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
@ -123,7 +124,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(value)
|
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)
|
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
|
/// If necessary, the source code can be accessed directly by getting the
|
||||||
/// node's byte range.
|
/// 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
|
/// Return the type of the value that this abstract node will create when run. Returns a
|
||||||
/// validation error if the tree is invalid.
|
/// 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.
|
/// 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
|
/// Execute this node's logic and return a value. Returns a runtime error if the node cannot
|
||||||
/// resolve to a value.
|
/// 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 {
|
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.
|
//! The Dust library is used to parse, format and run dust source code.
|
||||||
//!
|
//!
|
||||||
//! See the [interpret] module for more information.
|
//! See the [interpret] module for more information.
|
||||||
@ -13,6 +12,7 @@ pub use tree_sitter::Node as SyntaxNode;
|
|||||||
|
|
||||||
pub mod abstract_tree;
|
pub mod abstract_tree;
|
||||||
pub mod built_in_functions;
|
pub mod built_in_functions;
|
||||||
|
pub mod context;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod interpret;
|
pub mod interpret;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
Loading…
Reference in New Issue
Block a user