Replace context inheritance with parental refs

This commit is contained in:
Jeff 2024-05-21 16:29:54 -04:00
parent aadb51e1f1
commit f7bc43d7e3
8 changed files with 56 additions and 106 deletions

View File

@ -80,7 +80,7 @@ mod tests {
]); ]);
assert_eq!( assert_eq!(
block.run(&mut Context::new(), true).unwrap(), block.run(&mut Context::new(None), true).unwrap(),
Action::Return(Value::integer(42)) 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)
)
} }
} }

View File

@ -133,7 +133,7 @@ impl AbstractNode for FunctionCall {
arguments.push(value); arguments.push(value);
} }
let mut function_context = Context::new(); let mut function_context = Context::new(Some(&context));
for (type_parameter, type_argument) in function for (type_parameter, type_argument) in function
.type_parameters() .type_parameters()
@ -146,7 +146,6 @@ impl AbstractNode for FunctionCall {
} }
} }
function_context.inherit_data_from(&context)?;
function function
.clone() .clone()
.call(arguments, &mut function_context, clear_variables) .call(arguments, &mut function_context, clear_variables)

View File

@ -167,7 +167,7 @@ mod tests {
Vec::with_capacity(0), Vec::with_capacity(0),
None None
) )
.run(&mut Context::new(), true) .run(&mut Context::new(None), true)
.unwrap(), .unwrap(),
Action::Return(Value::string("foo".to_string())) Action::Return(Value::string("foo".to_string()))
) )

View File

@ -206,7 +206,7 @@ mod tests {
Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
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))) 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(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(43).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))) 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(43).with_position((0, 0))),
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))) 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(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(43).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))) 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(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(41).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))) 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))),
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))) 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(41).with_position((0, 0))),
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))) 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))),
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))) 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))),
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))) 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(true).with_position((0, 0))),
Expression::Value(ValueNode::Boolean(false).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))) Ok(Action::Return(Value::boolean(true)))
) )
} }
@ -319,7 +319,7 @@ mod tests {
Logic::Not(Expression::Value( Logic::Not(Expression::Value(
ValueNode::Boolean(false).with_position((0, 0)) ValueNode::Boolean(false).with_position((0, 0))
)) ))
.run(&mut Context::new(), true), .run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true))) Ok(Action::Return(Value::boolean(true)))
) )
} }

View File

@ -117,9 +117,7 @@ impl AbstractNode for ValueNode {
body, body,
} = self } = self
{ {
let mut function_context = Context::new(); let mut function_context = Context::new(Some(&context));
function_context.inherit_types_from(context)?;
for r#type in type_arguments { for r#type in type_arguments {
if let Type::Argument(identifier) = &r#type.item { if let Type::Argument(identifier) = &r#type.item {

View File

@ -11,16 +11,18 @@ use crate::{
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Context { pub struct Context<'a> {
variables: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>, variables: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
is_clean: bool, parent: Option<&'a Context<'a>>,
is_clean: Arc<RwLock<bool>>,
} }
impl Context { impl<'a> Context<'a> {
pub fn new() -> Self { pub fn new(parent: Option<&'a Context>) -> Self {
Self { Self {
variables: Arc::new(RwLock::new(BTreeMap::new())), 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()?) 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<bool, RwLockPoisonError> { pub fn contains(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
log::trace!("Checking that {identifier} exists."); 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<Option<Type>, ValidationError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
@ -73,23 +55,24 @@ impl Context {
}; };
Ok(Some(r#type.clone())) Ok(Some(r#type.clone()))
} else if let Some(parent) = self.parent {
parent.get_type(identifier)
} else { } else {
Ok(None) Ok(None)
} }
} }
pub fn use_value( pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
&mut self,
identifier: &Identifier,
) -> Result<Option<Value>, RwLockPoisonError> {
if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier) if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier)
{ {
log::trace!("Using {identifier}'s value."); log::trace!("Using {identifier}'s value.");
usage_data.inner().write()?.actual += 1; usage_data.inner().write()?.actual += 1;
self.is_clean = false; *self.is_clean.write()? = false;
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else if let Some(parent) = self.parent {
parent.use_value(identifier)
} else { } else {
Ok(None) Ok(None)
} }
@ -100,6 +83,8 @@ impl Context {
log::trace!("Getting {identifier}'s value."); log::trace!("Getting {identifier}'s value.");
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else if let Some(parent) = self.parent {
parent.get_value(identifier)
} else { } else {
Ok(None) Ok(None)
} }
@ -113,6 +98,8 @@ impl Context {
log::trace!("Getting {identifier}'s value."); log::trace!("Getting {identifier}'s value.");
Ok(Some(full_data.clone())) Ok(Some(full_data.clone()))
} else if let Some(parent) = self.parent {
parent.get_data(identifier)
} else { } else {
Ok(None) Ok(None)
} }
@ -150,7 +137,7 @@ impl Context {
} }
pub fn clean(&mut self) -> Result<(), RwLockPoisonError> { pub fn clean(&mut self) -> Result<(), RwLockPoisonError> {
if self.is_clean { if *self.is_clean.read()? {
return Ok(()); return Ok(());
} }
@ -172,13 +159,13 @@ impl Context {
} }
}); });
self.is_clean = true; *self.is_clean.write()? = true;
Ok(()) Ok(())
} }
pub fn is_clean(&mut self) -> Result<bool, RwLockPoisonError> { pub fn is_clean(&mut self) -> Result<bool, RwLockPoisonError> {
if self.is_clean { if *self.is_clean.read()? {
Ok(true) Ok(true)
} else { } else {
for (_, (_, usage_data)) in self.variables.read()?.iter() { for (_, (_, usage_data)) in self.variables.read()?.iter() {
@ -200,6 +187,8 @@ impl Context {
usage_data.inner().write()?.expected += 1; usage_data.inner().write()?.expected += 1;
Ok(true) Ok(true)
} else if let Some(parent) = self.parent {
parent.add_expected_use(identifier)
} else { } else {
Ok(false) Ok(false)
} }

View File

@ -23,7 +23,7 @@ use rayon::prelude::*;
pub use value::Value; pub use value::Value;
pub fn interpret<'src>(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> { pub fn interpret<'src>(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
let mut interpreter = Interpreter::new(Context::new()); let mut interpreter = Interpreter::new(Context::new(None));
interpreter.load_std()?; interpreter.load_std()?;
interpreter.run(Arc::from(source_id), Arc::from(source)) interpreter.run(Arc::from(source_id), Arc::from(source))
@ -33,18 +33,18 @@ pub fn interpret_without_std(
source_id: &str, source_id: &str,
source: &str, source: &str,
) -> Result<Option<Value>, InterpreterError> { ) -> Result<Option<Value>, 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)) interpreter.run(Arc::from(source_id.to_string()), Arc::from(source))
} }
pub struct Interpreter { pub struct Interpreter<'a> {
context: Context, context: Context<'a>,
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>, sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
} }
impl Interpreter { impl<'a> Interpreter<'a> {
pub fn new(context: Context) -> Self { pub fn new(context: Context<'a>) -> Self {
Interpreter { Interpreter {
context, context,
sources: Arc::new(RwLock::new(Vec::new())), sources: Arc::new(RwLock::new(Vec::new())),

View File

@ -1,8 +1,4 @@
use dust_lang::{ use dust_lang::*;
error::{Error, ValidationError},
identifier::Identifier,
*,
};
#[test] #[test]
fn function_call_with_type_argument() { fn function_call_with_type_argument() {
@ -68,42 +64,7 @@ fn built_in_function_call() {
} }
#[test] #[test]
fn function_context_does_not_capture_values() { fn function_context_captures_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() {
assert_eq!( assert_eq!(
interpret( interpret(
"test", "test",