Improve context API
This commit is contained in:
parent
4f5ad1e4aa
commit
6c699ec900
@ -63,6 +63,8 @@ impl AbstractTree for Assignment {
|
|||||||
context.set_type(self.identifier.clone(), r#type)?;
|
context.set_type(self.identifier.clone(), r#type)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.identifier.validate(source, context)?;
|
||||||
|
|
||||||
if let Some(type_specification) = &self.type_specification {
|
if let Some(type_specification) = &self.type_specification {
|
||||||
match self.operator {
|
match self.operator {
|
||||||
AssignmentOperator::Equal => {
|
AssignmentOperator::Equal => {
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
built_in_identifiers::all_built_in_identifiers,
|
built_in_identifiers::all_built_in_identifiers,
|
||||||
built_in_values::all_built_in_values,
|
built_in_values::all_built_in_values,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Format, SyntaxNode, Type, Value, ValueData,
|
AbstractTree, Context, Format, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A string by which a variable is known to a context.
|
/// A string by which a variable is known to a context.
|
||||||
@ -61,9 +61,9 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
if let Some((_, counter)) = context.get_data_and_counter(self)? {
|
let variable_exists = context.add_allowance(self)?;
|
||||||
counter.add_allowance()?;
|
|
||||||
|
|
||||||
|
if variable_exists {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
for built_in_value in all_built_in_values() {
|
for built_in_value in all_built_in_values() {
|
||||||
@ -91,16 +91,8 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
if let Some((value_data, counter)) = context.get_data_and_counter(self)? {
|
if let Some(value) = context.get_value(self)? {
|
||||||
if let ValueData::Value(value) = value_data {
|
return Ok(value);
|
||||||
counter.add_runtime_use()?;
|
|
||||||
|
|
||||||
if counter.runtime_uses() == counter.allowances() {
|
|
||||||
context.unset(self)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(value.clone());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for built_in_value in all_built_in_values() {
|
for built_in_value in all_built_in_values() {
|
||||||
if built_in_value.name() == self.inner().as_ref() {
|
if built_in_value.name() == self.inner().as_ref() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! An execution context that stores variables and type data during the
|
//! A garbage-collecting execution context that stores variables and type data
|
||||||
//! [Interpreter][crate::Interpreter]'s abstraction and execution process.
|
//! during the [Interpreter][crate::Interpreter]'s abstraction and execution
|
||||||
|
//! process.
|
||||||
//!
|
//!
|
||||||
//! ## Setting values
|
//! ## Setting values
|
||||||
//!
|
//!
|
||||||
@ -27,6 +28,15 @@
|
|||||||
//! has been explicitly set. If nothing is found, it will then check the built-
|
//! has been explicitly set. If nothing is found, it will then check the built-
|
||||||
//! in values and type definitions for a match. This means that the user can
|
//! in values and type definitions for a match. This means that the user can
|
||||||
//! override the built-ins.
|
//! override the built-ins.
|
||||||
|
//!
|
||||||
|
//! ## Garbage Collection
|
||||||
|
//!
|
||||||
|
//! Every item stored in a Context has a counter attached to it. You must use
|
||||||
|
//! [Context::add_allowance][] to let the Context know not to drop the value.
|
||||||
|
//! Every time you use [Context::get_value][] it checks the number of times it
|
||||||
|
//! has been used and compares it to the number of allowances. If the limit
|
||||||
|
//! has been reached, the value will be removed from the context and can no
|
||||||
|
//! longer be found.
|
||||||
mod usage_counter;
|
mod usage_counter;
|
||||||
mod value_data;
|
mod value_data;
|
||||||
|
|
||||||
@ -45,8 +55,8 @@ use crate::{
|
|||||||
error::rw_lock_error::RwLockError, Identifier, Type, TypeDefinition, Value,
|
error::rw_lock_error::RwLockError, Identifier, Type, TypeDefinition, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An execution context that variable and type data during the [Interpreter]'s
|
/// An execution context stores that variable and type data during the
|
||||||
/// abstraction and execution process.
|
/// [Interpreter]'s abstraction and execution process.
|
||||||
///
|
///
|
||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -166,33 +176,42 @@ impl Context {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a [Value] and its [UsageCounter] from the context.
|
/// Increment the number of allowances a variable has. Return a boolean
|
||||||
pub fn get_data_and_counter(
|
/// representing whether or not the variable was found.
|
||||||
&self,
|
pub fn add_allowance(&self, identifier: &Identifier) -> Result<bool, RwLockError> {
|
||||||
identifier: &Identifier,
|
if let Some((_value_data, counter)) = self.inner.read()?.get(identifier) {
|
||||||
) -> Result<Option<(ValueData, UsageCounter)>, RwLockError> {
|
counter.add_allowance()?;
|
||||||
if let Some((value_data, counter)) = self.inner.read()?.get(identifier) {
|
|
||||||
return Ok(Some((value_data.clone(), counter.clone())));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a [Value] from the context.
|
/// Get a [Value] from the context.
|
||||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockError> {
|
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockError> {
|
||||||
if let Some((value_data, _counter)) = self.inner.read()?.get(identifier) {
|
let (value, counter) =
|
||||||
if let ValueData::Value(value) = value_data {
|
if let Some((value_data, counter)) = self.inner.read()?.get(identifier) {
|
||||||
return Ok(Some(value.clone()));
|
if let ValueData::Value(value) = value_data {
|
||||||
}
|
(value.clone(), counter.clone())
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for built_in_value in all_built_in_values() {
|
||||||
|
if built_in_value.name() == identifier.inner().as_ref() {
|
||||||
|
return Ok(Some(built_in_value.get().clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
if counter.allowances() == counter.runtime_uses() {
|
||||||
|
self.unset(identifier)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for built_in_value in all_built_in_values() {
|
Ok(Some(value))
|
||||||
if built_in_value.name() == identifier.inner().as_ref() {
|
|
||||||
return Ok(Some(built_in_value.get().clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a [Type] from the context.
|
/// Get a [Type] from the context.
|
||||||
@ -273,7 +292,7 @@ impl Context {
|
|||||||
/// Set a type definition.
|
/// Set a type definition.
|
||||||
///
|
///
|
||||||
/// This allows defined types (i.e. structs and enums) to be instantiated
|
/// This allows defined types (i.e. structs and enums) to be instantiated
|
||||||
/// later while using this context.
|
/// later while running the interpreter using this context.
|
||||||
pub fn set_definition(
|
pub fn set_definition(
|
||||||
&self,
|
&self,
|
||||||
key: Identifier,
|
key: Identifier,
|
||||||
|
@ -49,11 +49,6 @@ pub fn interpret(source: &str) -> Result<Value, Error> {
|
|||||||
|
|
||||||
/// Interpret the given source code with the given context.
|
/// Interpret the given source code with the given context.
|
||||||
///
|
///
|
||||||
/// A context is a [Map] instance, which is dust's
|
|
||||||
/// [BTreeMap][std::collections::btree_map::BTreeMap] that is used internally
|
|
||||||
/// for the `<map>` type. Any value can be set, including functions and nested
|
|
||||||
/// maps.
|
|
||||||
///
|
|
||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
pub fn interpret_with_context(source: &str, context: Context) -> Result<Value, Error> {
|
pub fn interpret_with_context(source: &str, context: Context) -> Result<Value, Error> {
|
||||||
let mut interpreter = Interpreter::new(context);
|
let mut interpreter = Interpreter::new(context);
|
||||||
@ -93,7 +88,7 @@ impl Interpreter {
|
|||||||
.expect("Language version is incompatible with tree sitter version.");
|
.expect("Language version is incompatible with tree sitter version.");
|
||||||
|
|
||||||
parser.set_logger(Some(Box::new(|_log_type, message| {
|
parser.set_logger(Some(Box::new(|_log_type, message| {
|
||||||
log::info!("{}", message)
|
log::debug!("{}", message)
|
||||||
})));
|
})));
|
||||||
|
|
||||||
Interpreter { parser, context }
|
Interpreter { parser, context }
|
||||||
@ -118,9 +113,8 @@ impl Interpreter {
|
|||||||
/// The order in which this function works is:
|
/// The order in which this function works is:
|
||||||
///
|
///
|
||||||
/// - parse the source into a syntax tree
|
/// - parse the source into a syntax tree
|
||||||
/// - check the syntax tree for errors
|
|
||||||
/// - generate an abstract tree from the source and syntax tree
|
/// - generate an abstract tree from the source and syntax tree
|
||||||
/// - check the abstract tree for type errors
|
/// - check the abstract tree for errors
|
||||||
pub fn validate(&mut self, source: &str) -> Result<Root, Error> {
|
pub fn validate(&mut self, source: &str) -> Result<Root, Error> {
|
||||||
let syntax_tree = self.parse(source)?;
|
let syntax_tree = self.parse(source)?;
|
||||||
let abstract_tree = Root::from_syntax(syntax_tree.root_node(), source, &self.context)?;
|
let abstract_tree = Root::from_syntax(syntax_tree.root_node(), source, &self.context)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user