diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 638dd0c..6a1c065 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::{ @@ -8,11 +10,14 @@ use crate::{ use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct FunctionCall { function: Box, type_arguments: Option>, value_arguments: Vec, + + #[serde(skip)] + context: Arc>>, } impl FunctionCall { @@ -25,6 +30,7 @@ impl FunctionCall { function: Box::new(function), type_arguments, value_arguments, + context: Arc::new(Mutex::new(None)), } } @@ -34,13 +40,15 @@ impl FunctionCall { } impl AbstractNode for FunctionCall { - fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { - self.function.define_types(_context)?; + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { + *self.context.lock()? = Some(context.create_child()); + + self.function.define_types(context)?; let mut previous = (); for expression in &self.value_arguments { - previous = expression.define_types(_context)?; + previous = expression.define_types(context)?; } Ok(previous) @@ -128,7 +136,11 @@ impl AbstractNode for FunctionCall { arguments.push(evalution); } - let mut function_context = Context::new(Some(&context)); + let function_context = if let Some(context) = self.context.lock()?.clone() { + context + } else { + panic!(""); + }; match (function.type_parameters(), self.type_arguments) { (Some(type_parameters), Some(type_arguments)) => { @@ -145,7 +157,7 @@ impl AbstractNode for FunctionCall { function .clone() - .call(arguments, &mut function_context, clear_variables) + .call(arguments, &function_context, clear_variables) } fn expected_type(&self, context: &Context) -> Result, ValidationError> { @@ -220,3 +232,23 @@ impl AbstractNode for FunctionCall { } } } + +impl Eq for FunctionCall {} + +impl PartialEq for FunctionCall { + fn eq(&self, other: &Self) -> bool { + todo!() + } +} + +impl PartialOrd for FunctionCall { + fn partial_cmp(&self, other: &Self) -> Option { + todo!() + } +} + +impl Ord for FunctionCall { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + todo!() + } +} diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 355c3c3..def8209 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - sync::{Arc, RwLock, RwLockReadGuard}, + sync::{Arc, RwLock}, }; use crate::{ @@ -11,37 +11,40 @@ use crate::{ }; #[derive(Clone, Debug)] -pub struct Context<'a> { - variables: Arc>>, - parent: Option<&'a Context<'a>>, +pub struct Context { + data: Arc>, is_clean: Arc>, } -impl<'a> Context<'a> { - pub fn new(parent: Option<&'a Context>) -> Self { - Self { - variables: Arc::new(RwLock::new(HashMap::new())), - parent, +#[derive(Clone, Debug)] +struct ContextData { + variables: HashMap, + parent: Option, +} + +impl Context { + pub fn new(parent: Option) -> Self { + Context { + data: Arc::new(RwLock::new(ContextData { + variables: HashMap::new(), + parent, + })), is_clean: Arc::new(RwLock::new(true)), } } - pub fn create_child<'b>(&'b self) -> Context<'b> { - Context::new(Some(self)) - } - - pub fn inner( - &self, - ) -> Result>, PoisonError> { - Ok(self.variables.read()?) + pub fn create_child(&self) -> Context { + Context::new(Some(self.clone())) } pub fn contains(&self, identifier: &Identifier) -> Result { log::trace!("Checking that {identifier} exists."); - if self.variables.read()?.contains_key(identifier) { + let data = self.data.read()?; + + if data.variables.contains_key(identifier) { Ok(true) - } else if let Some(parent) = self.parent { + } else if let Some(parent) = &data.parent { parent.contains(identifier) } else { Ok(false) @@ -49,16 +52,18 @@ impl<'a> Context<'a> { } pub fn get_type(&self, identifier: &Identifier) -> Result, ValidationError> { - if let Some((data, _)) = self.variables.read()?.get(identifier) { - log::trace!("Getting {identifier}'s type."); + log::trace!("Getting {identifier}'s type."); + let data = self.data.read()?; + + if let Some((data, _)) = data.variables.get(identifier) { let r#type = match data { VariableData::Type(r#type) => r#type.clone(), VariableData::Value(value) => value.r#type(self)?, }; Ok(Some(r#type.clone())) - } else if let Some(parent) = self.parent { + } else if let Some(parent) = &data.parent { parent.get_type(identifier) } else { Ok(None) @@ -66,16 +71,16 @@ impl<'a> Context<'a> { } pub fn use_value(&self, identifier: &Identifier) -> Result, PoisonError> { - if let Some((VariableData::Value(value), usage_data)) = - self.variables.read()?.get(identifier) - { - log::trace!("Using {identifier}'s value."); + log::trace!("Using {identifier}'s value."); + let data = self.data.read()?; + + if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) { usage_data.inner().write()?.actual += 1; *self.is_clean.write()? = false; Ok(Some(value.clone())) - } else if let Some(parent) = self.parent { + } else if let Some(parent) = &data.parent { parent.use_value(identifier) } else { Ok(None) @@ -83,27 +88,14 @@ impl<'a> Context<'a> { } pub fn get_value(&self, identifier: &Identifier) -> Result, PoisonError> { - if let Some((VariableData::Value(value), _)) = self.variables.read()?.get(identifier) { - log::trace!("Getting {identifier}'s value."); + log::trace!("Getting {identifier}'s value."); + let data = self.data.read()?; + + if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) { Ok(Some(value.clone())) - } else if let Some(parent) = self.parent { - parent.get_value(identifier) - } else { - Ok(None) - } - } - - pub fn get_data( - &self, - identifier: &Identifier, - ) -> Result, PoisonError> { - if let Some(full_data) = self.variables.read()?.get(identifier) { - log::trace!("Getting {identifier}'s value."); - - Ok(Some(full_data.clone())) - } else if let Some(parent) = self.parent { - parent.get_data(identifier) + } else if let Some(parent) = &data.parent { + parent.use_value(identifier) } else { Ok(None) } @@ -112,8 +104,9 @@ impl<'a> Context<'a> { pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> { log::debug!("Setting {identifier} to type {}.", r#type); - self.variables + self.data .write()? + .variables .insert(identifier, (VariableData::Type(r#type), UsageData::new())); Ok(()) @@ -122,27 +115,43 @@ impl<'a> Context<'a> { pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> { log::debug!("Setting {identifier} to value {value}."); - let mut variables = self.variables.write()?; - let old_usage_data = variables + let mut data = self.data.write()?; + let usage_data = data + .variables .remove(&identifier) - .map(|(_, usage_data)| usage_data); + .map(|(_, usage_data)| usage_data) + .unwrap_or(UsageData::new()); - if let Some(usage_data) = old_usage_data { - variables.insert(identifier, (VariableData::Value(value), usage_data)); - } else { - variables.insert(identifier, (VariableData::Value(value), UsageData::new())); - } + data.variables + .insert(identifier, (VariableData::Value(value), usage_data)); Ok(()) } + pub fn add_expected_use(&self, identifier: &Identifier) -> Result { + let data = self.data.read()?; + + if let Some((_, usage_data)) = data.variables.get(identifier) { + log::trace!("Adding expected use for variable {identifier}."); + + usage_data.inner().write()?.expected += 1; + + Ok(true) + } else if let Some(parent) = &data.parent { + parent.add_expected_use(identifier) + } else { + Ok(false) + } + } + pub fn clean(&self) -> Result<(), PoisonError> { if *self.is_clean.read()? { return Ok(()); } - self.variables + self.data .write()? + .variables .retain(|identifier, (value_data, usage_data)| { if let VariableData::Value(_) = value_data { let usage = usage_data.inner().read().unwrap(); @@ -165,33 +174,7 @@ impl<'a> Context<'a> { } pub fn is_clean(&mut self) -> Result { - if *self.is_clean.read()? { - Ok(true) - } else { - for (_, (_, usage_data)) in self.variables.read()?.iter() { - let usage_data = usage_data.inner().read().unwrap(); - - if usage_data.actual > usage_data.expected { - return Ok(false); - } - } - - Ok(true) - } - } - - pub fn add_expected_use(&self, identifier: &Identifier) -> Result { - if let Some((_, usage_data)) = self.variables.read()?.get(identifier) { - log::trace!("Adding expected use for variable {identifier}."); - - usage_data.inner().write()?.expected += 1; - - Ok(true) - } else if let Some(parent) = self.parent { - parent.add_expected_use(identifier) - } else { - Ok(false) - } + Ok(*self.is_clean.read()?) } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index fbd6cf4..23761c0 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -38,13 +38,13 @@ pub fn interpret_without_std( interpreter.run(Arc::from(source_id.to_string()), Arc::from(source)) } -pub struct Interpreter<'a> { - context: Context<'a>, +pub struct Interpreter { + context: Context, sources: Arc, Arc)>>>, } -impl<'a> Interpreter<'a> { - pub fn new(context: Context<'a>) -> Self { +impl Interpreter { + pub fn new(context: Context) -> Self { Interpreter { context, sources: Arc::new(RwLock::new(Vec::new())), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 78e78bc..b589286 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -731,7 +731,7 @@ impl Function { pub fn call( self, value_arguments: Vec, - context: &mut Context, + context: &Context, manage_memory: bool, ) -> Result, RuntimeError> { for ((identifier, _), value) in self diff --git a/dust-shell/src/cli.rs b/dust-shell/src/cli.rs index 0bf2ab0..2650c50 100644 --- a/dust-shell/src/cli.rs +++ b/dust-shell/src/cli.rs @@ -15,7 +15,7 @@ use reedline::{ SqliteBackedHistory, }; -pub fn run_shell<'a>(context: Context<'a>) -> Result<(), io::Error> { +pub fn run_shell(context: Context) -> Result<(), io::Error> { let mut interpreter = Interpreter::new(context.clone()); let mut keybindings = default_emacs_keybindings();