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