From f7bc43d7e3747b99bde43431099a17126795455b Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 21 May 2024 16:29:54 -0400 Subject: [PATCH] Replace context inheritance with parental refs --- dust-lang/src/abstract_tree/block.rs | 7 +- dust-lang/src/abstract_tree/function_call.rs | 3 +- dust-lang/src/abstract_tree/if_else.rs | 2 +- dust-lang/src/abstract_tree/logic.rs | 22 +++---- dust-lang/src/abstract_tree/value_node.rs | 4 +- dust-lang/src/context.rs | 69 ++++++++------------ dust-lang/src/lib.rs | 12 ++-- dust-lang/tests/functions.rs | 43 +----------- 8 files changed, 56 insertions(+), 106 deletions(-) diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs index 3d5ed4d..65d850c 100644 --- a/dust-lang/src/abstract_tree/block.rs +++ b/dust-lang/src/abstract_tree/block.rs @@ -80,7 +80,7 @@ mod tests { ]); assert_eq!( - block.run(&mut Context::new(), true).unwrap(), + block.run(&mut Context::new(None), true).unwrap(), Action::Return(Value::integer(42)) ) } @@ -96,6 +96,9 @@ mod tests { )), ]); - assert_eq!(block.expected_type(&mut Context::new()), Ok(Type::Integer)) + assert_eq!( + block.expected_type(&mut Context::new(None)), + Ok(Type::Integer) + ) } } diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 5562e9c..84c32d9 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -133,7 +133,7 @@ impl AbstractNode for FunctionCall { arguments.push(value); } - let mut function_context = Context::new(); + let mut function_context = Context::new(Some(&context)); for (type_parameter, type_argument) in function .type_parameters() @@ -146,7 +146,6 @@ impl AbstractNode for FunctionCall { } } - function_context.inherit_data_from(&context)?; function .clone() .call(arguments, &mut function_context, clear_variables) diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index 0c75aa9..1556ba6 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -167,7 +167,7 @@ mod tests { Vec::with_capacity(0), None ) - .run(&mut Context::new(), true) + .run(&mut Context::new(None), true) .unwrap(), Action::Return(Value::string("foo".to_string())) ) diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index 502ec96..1f1985f 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -206,7 +206,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -218,7 +218,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -230,7 +230,7 @@ mod tests { Expression::Value(ValueNode::Integer(43).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -242,7 +242,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -254,7 +254,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(41).with_position((0, 0))) ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ); @@ -263,7 +263,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ); } @@ -275,7 +275,7 @@ mod tests { Expression::Value(ValueNode::Integer(41).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ); @@ -284,7 +284,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ); } @@ -296,7 +296,7 @@ mod tests { Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -308,7 +308,7 @@ mod tests { Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), Expression::Value(ValueNode::Boolean(false).with_position((0, 0))), ) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } @@ -319,7 +319,7 @@ mod tests { Logic::Not(Expression::Value( ValueNode::Boolean(false).with_position((0, 0)) )) - .run(&mut Context::new(), true), + .run(&mut Context::new(None), true), Ok(Action::Return(Value::boolean(true))) ) } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 2202434..ef4e314 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -117,9 +117,7 @@ impl AbstractNode for ValueNode { body, } = self { - let mut function_context = Context::new(); - - function_context.inherit_types_from(context)?; + let mut function_context = Context::new(Some(&context)); for r#type in type_arguments { if let Type::Argument(identifier) = &r#type.item { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 4913f6f..a7f71fa 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -11,16 +11,18 @@ use crate::{ }; #[derive(Clone, Debug)] -pub struct Context { +pub struct Context<'a> { variables: Arc>>, - is_clean: bool, + parent: Option<&'a Context<'a>>, + is_clean: Arc>, } -impl Context { - pub fn new() -> Self { +impl<'a> Context<'a> { + pub fn new(parent: Option<&'a Context>) -> Self { Self { variables: Arc::new(RwLock::new(BTreeMap::new())), - is_clean: true, + parent, + is_clean: Arc::new(RwLock::new(true)), } } @@ -31,36 +33,16 @@ impl Context { Ok(self.variables.read()?) } - pub fn inherit_types_from(&self, other: &Context) -> Result<(), RwLockPoisonError> { - let mut self_data = self.variables.write()?; - - for (identifier, (value_data, usage_data)) in other.variables.read()?.iter() { - if let ValueData::Type(Type::Function { .. }) = value_data { - log::trace!("Context inheriting type of {identifier}."); - - self_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone())); - } - } - - Ok(()) - } - - pub fn inherit_data_from(&self, other: &Context) -> Result<(), RwLockPoisonError> { - let mut self_data = self.variables.write()?; - - for (identifier, (value_data, usage_data)) in other.variables.read()?.iter() { - log::trace!("Context inheriting variable {identifier}."); - - self_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone())); - } - - Ok(()) - } - pub fn contains(&self, identifier: &Identifier) -> Result { log::trace!("Checking that {identifier} exists."); - Ok(self.variables.read()?.contains_key(identifier)) + if self.variables.read()?.contains_key(identifier) { + Ok(true) + } else if let Some(parent) = self.parent { + parent.contains(identifier) + } else { + Ok(false) + } } pub fn get_type(&self, identifier: &Identifier) -> Result, ValidationError> { @@ -73,23 +55,24 @@ impl Context { }; Ok(Some(r#type.clone())) + } else if let Some(parent) = self.parent { + parent.get_type(identifier) } else { Ok(None) } } - pub fn use_value( - &mut self, - identifier: &Identifier, - ) -> Result, RwLockPoisonError> { + pub fn use_value(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier) { log::trace!("Using {identifier}'s value."); usage_data.inner().write()?.actual += 1; - self.is_clean = false; + *self.is_clean.write()? = false; Ok(Some(value.clone())) + } else if let Some(parent) = self.parent { + parent.use_value(identifier) } else { Ok(None) } @@ -100,6 +83,8 @@ impl Context { log::trace!("Getting {identifier}'s value."); Ok(Some(value.clone())) + } else if let Some(parent) = self.parent { + parent.get_value(identifier) } else { Ok(None) } @@ -113,6 +98,8 @@ impl Context { log::trace!("Getting {identifier}'s value."); Ok(Some(full_data.clone())) + } else if let Some(parent) = self.parent { + parent.get_data(identifier) } else { Ok(None) } @@ -150,7 +137,7 @@ impl Context { } pub fn clean(&mut self) -> Result<(), RwLockPoisonError> { - if self.is_clean { + if *self.is_clean.read()? { return Ok(()); } @@ -172,13 +159,13 @@ impl Context { } }); - self.is_clean = true; + *self.is_clean.write()? = true; Ok(()) } pub fn is_clean(&mut self) -> Result { - if self.is_clean { + if *self.is_clean.read()? { Ok(true) } else { for (_, (_, usage_data)) in self.variables.read()?.iter() { @@ -200,6 +187,8 @@ impl Context { usage_data.inner().write()?.expected += 1; Ok(true) + } else if let Some(parent) = self.parent { + parent.add_expected_use(identifier) } else { Ok(false) } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index fc7d6c7..5632d0c 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -23,7 +23,7 @@ use rayon::prelude::*; pub use value::Value; pub fn interpret<'src>(source_id: &str, source: &str) -> Result, InterpreterError> { - let mut interpreter = Interpreter::new(Context::new()); + let mut interpreter = Interpreter::new(Context::new(None)); interpreter.load_std()?; interpreter.run(Arc::from(source_id), Arc::from(source)) @@ -33,18 +33,18 @@ pub fn interpret_without_std( source_id: &str, source: &str, ) -> Result, InterpreterError> { - let mut interpreter = Interpreter::new(Context::new()); + let mut interpreter = Interpreter::new(Context::new(None)); interpreter.run(Arc::from(source_id.to_string()), Arc::from(source)) } -pub struct Interpreter { - context: Context, +pub struct Interpreter<'a> { + context: Context<'a>, sources: Arc, Arc)>>>, } -impl Interpreter { - pub fn new(context: Context) -> Self { +impl<'a> Interpreter<'a> { + pub fn new(context: Context<'a>) -> Self { Interpreter { context, sources: Arc::new(RwLock::new(Vec::new())), diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs index 5324bb1..ad88d88 100644 --- a/dust-lang/tests/functions.rs +++ b/dust-lang/tests/functions.rs @@ -1,8 +1,4 @@ -use dust_lang::{ - error::{Error, ValidationError}, - identifier::Identifier, - *, -}; +use dust_lang::*; #[test] fn function_call_with_type_argument() { @@ -68,42 +64,7 @@ fn built_in_function_call() { } #[test] -fn function_context_does_not_capture_values() { - assert_eq!( - interpret( - "test", - " - x = 1 - - foo = fn () any { x } - " - ) - .unwrap_err() - .errors(), - &vec![Error::Validation { - error: ValidationError::VariableNotFound { - identifier: Identifier::new("x"), - position: (50, 51).into() - }, - position: (32, 53).into() - }] - ); - - assert_eq!( - interpret( - "test", - " - x = 1 - foo = fn (x: int) int { x } - foo(2) - " - ), - Ok(Some(Value::integer(2))) - ); -} - -#[test] -fn function_context_captures_functions() { +fn function_context_captures_values() { assert_eq!( interpret( "test",