1
0

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!(
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)
)
}
}

View File

@ -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)

View File

@ -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()))
)

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)))
)
.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)))
)
}

View File

@ -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 {

View File

@ -11,16 +11,18 @@ use crate::{
};
#[derive(Clone, Debug)]
pub struct Context {
pub struct Context<'a> {
variables: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
is_clean: bool,
parent: Option<&'a Context<'a>>,
is_clean: Arc<RwLock<bool>>,
}
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<bool, RwLockPoisonError> {
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> {
@ -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<Option<Value>, RwLockPoisonError> {
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, 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<bool, RwLockPoisonError> {
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)
}

View File

@ -23,7 +23,7 @@ use rayon::prelude::*;
pub use value::Value;
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.run(Arc::from(source_id), Arc::from(source))
@ -33,18 +33,18 @@ pub fn interpret_without_std(
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.run(Arc::from(source_id.to_string()), Arc::from(source))
}
pub struct Interpreter {
context: Context,
pub struct Interpreter<'a> {
context: Context<'a>,
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
}
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())),

View File

@ -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",