Replace context inheritance with parental refs
This commit is contained in:
parent
aadb51e1f1
commit
f7bc43d7e3
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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()))
|
||||
)
|
||||
|
@ -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)))
|
||||
)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())),
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user