From e1b04328d51e8c343ad182507768b8c92451dc9f Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 9 Aug 2024 20:52:13 -0400 Subject: [PATCH] Add context --- dust-lang/src/abstract_tree.rs | 20 ++++----- dust-lang/src/context.rs | 80 ++++++++++++++++++++++++++++++++++ dust-lang/src/lib.rs | 2 + dust-lang/src/value.rs | 16 +++---- 4 files changed, 99 insertions(+), 19 deletions(-) create mode 100644 dust-lang/src/context.rs diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index 957f79e..9bce093 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -6,7 +6,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{BuiltInFunction, Identifier, Span, Type, Value}; +use crate::{BuiltInFunction, Context, Identifier, Span, Type, Value}; /// In-memory representation of a Dust program. #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -75,18 +75,16 @@ pub enum Statement { } impl Statement { - pub fn expected_type(&self, variables: &HashMap) -> Option { + pub fn expected_type(&self, context: &Context) -> Option { match self { - Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(variables), - Statement::BinaryOperation { left, .. } => left.inner.expected_type(variables), + Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context), + Statement::BinaryOperation { left, .. } => left.inner.expected_type(context), Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(), - Statement::Constant(value) => Some(value.r#type(variables)), - Statement::FunctionCall { function, .. } => function.inner.expected_type(variables), - Statement::Identifier(identifier) => variables - .get(identifier) - .map(|value| value.r#type(variables)), + Statement::Constant(value) => Some(value.r#type(context)), + Statement::FunctionCall { function, .. } => function.inner.expected_type(context), + Statement::Identifier(identifier) => context.get_type(identifier).cloned(), Statement::List(nodes) => { - let item_type = nodes.first().unwrap().inner.expected_type(variables)?; + let item_type = nodes.first().unwrap().inner.expected_type(context)?; Some(Type::List { length: nodes.len(), @@ -98,7 +96,7 @@ impl Statement { for (identifier, item) in nodes { if let Statement::Identifier(identifier) = &identifier.inner { - types.insert(identifier.clone(), item.inner.expected_type(variables)?); + types.insert(identifier.clone(), item.inner.expected_type(context)?); } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs new file mode 100644 index 0000000..ea0f0a1 --- /dev/null +++ b/dust-lang/src/context.rs @@ -0,0 +1,80 @@ +use std::collections::HashMap; + +use crate::{Identifier, Type, Value}; + +pub struct Context { + pub variables: HashMap, +} + +impl Context { + pub fn new() -> Self { + Self { + variables: HashMap::new(), + } + } + + pub fn contains(&self, identifier: &Identifier) -> bool { + self.variables.contains_key(identifier) + } + + pub fn get(&self, identifier: &Identifier) -> Option<&(VariableData, UsageData)> { + self.variables.get(identifier) + } + + pub fn get_type(&self, identifier: &Identifier) -> Option<&Type> { + match self.variables.get(identifier) { + Some((VariableData::Type(r#type), _)) => Some(r#type), + _ => None, + } + } + + pub fn get_value(&self, identifier: &Identifier) -> Option<&Value> { + match self.variables.get(identifier) { + Some((VariableData::Value(value), _)) => Some(value), + _ => None, + } + } + + pub fn get_variable_data(&self, identifier: &Identifier) -> Option<&VariableData> { + match self.variables.get(identifier) { + Some((variable_data, _)) => Some(variable_data), + _ => None, + } + } + + pub fn set_type(&mut self, identifier: Identifier, r#type: Type) { + self.variables.insert( + identifier, + (VariableData::Type(r#type), UsageData::default()), + ); + } + + pub fn set_value(&mut self, identifier: Identifier, value: Value) { + self.variables.insert( + identifier, + (VariableData::Value(value), UsageData::default()), + ); + } + + pub fn collect_garbage(&mut self) { + self.variables + .retain(|_, (_, usage_data)| usage_data.used < usage_data.allowed_uses); + } +} + +impl Default for Context { + fn default() -> Self { + Self::new() + } +} + +pub enum VariableData { + Value(Value), + Type(Type), +} + +#[derive(Default)] +pub struct UsageData { + pub allowed_uses: u16, + pub used: u16, +} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 81e6369..b3cbdc8 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -4,6 +4,7 @@ pub mod abstract_tree; pub mod analyzer; pub mod built_in_function; +pub mod context; pub mod dust_error; pub mod identifier; pub mod lex; @@ -16,6 +17,7 @@ pub mod vm; pub use abstract_tree::{AbstractSyntaxTree, Node, Statement}; pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; +pub use context::{Context, UsageData, VariableData}; pub use dust_error::DustError; pub use identifier::Identifier; pub use lex::{lex, LexError, Lexer}; diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index ea0d45b..3f8679f 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -14,7 +14,7 @@ use serde::{ Deserialize, Deserializer, Serialize, }; -use crate::{identifier::Identifier, AbstractSyntaxTree, Type, Vm, VmError}; +use crate::{identifier::Identifier, AbstractSyntaxTree, Context, Type, Vm, VmError}; /// Dust value representation /// @@ -89,8 +89,8 @@ impl Value { Value(Arc::new(ValueInner::String(to_string.to_string()))) } - pub fn r#type(&self, variables: &HashMap) -> Type { - self.0.r#type(variables) + pub fn r#type(&self, context: &Context) -> Type { + self.0.r#type(context) } pub fn as_boolean(&self) -> Option { @@ -626,18 +626,18 @@ pub enum ValueInner { } impl ValueInner { - pub fn r#type(&self, variables: &HashMap) -> Type { + pub fn r#type(&self, context: &Context) -> Type { match self { ValueInner::Boolean(_) => Type::Boolean, ValueInner::Float(_) => Type::Float, ValueInner::Function(function) => Type::Function { type_parameters: function.type_parameters.clone(), value_parameters: function.value_parameters.clone(), - return_type: function.return_type(variables).map(Box::new), + return_type: function.return_type(context).map(Box::new), }, ValueInner::Integer(_) => Type::Integer, ValueInner::List(values) => { - let item_type = values.first().unwrap().r#type(variables); + let item_type = values.first().unwrap().r#type(context); Type::List { length: values.len(), @@ -648,7 +648,7 @@ impl ValueInner { let mut type_map = BTreeMap::new(); for (identifier, value) in value_map { - let r#type = value.r#type(variables); + let r#type = value.r#type(context); type_map.insert(identifier.clone(), r#type); } @@ -732,7 +732,7 @@ impl Function { vm.run(&mut new_variables) } - pub fn return_type(&self, variables: &HashMap) -> Option { + pub fn return_type(&self, variables: &Context) -> Option { self.body .nodes .iter()