Refactor context

This commit is contained in:
Jeff 2024-06-22 06:36:59 -04:00
parent 240c045a0c
commit 1cd101db3f
5 changed files with 110 additions and 95 deletions

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -8,11 +10,14 @@ use crate::{
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall { pub struct FunctionCall {
function: Box<Expression>, function: Box<Expression>,
type_arguments: Option<Vec<TypeConstructor>>, type_arguments: Option<Vec<TypeConstructor>>,
value_arguments: Vec<Expression>, value_arguments: Vec<Expression>,
#[serde(skip)]
context: Arc<Mutex<Option<Context>>>,
} }
impl FunctionCall { impl FunctionCall {
@ -25,6 +30,7 @@ impl FunctionCall {
function: Box::new(function), function: Box::new(function),
type_arguments, type_arguments,
value_arguments, value_arguments,
context: Arc::new(Mutex::new(None)),
} }
} }
@ -34,13 +40,15 @@ impl FunctionCall {
} }
impl AbstractNode for FunctionCall { impl AbstractNode for FunctionCall {
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { fn define_types(&self, context: &Context) -> Result<(), ValidationError> {
self.function.define_types(_context)?; *self.context.lock()? = Some(context.create_child());
self.function.define_types(context)?;
let mut previous = (); let mut previous = ();
for expression in &self.value_arguments { for expression in &self.value_arguments {
previous = expression.define_types(_context)?; previous = expression.define_types(context)?;
} }
Ok(previous) Ok(previous)
@ -128,7 +136,11 @@ impl AbstractNode for FunctionCall {
arguments.push(evalution); arguments.push(evalution);
} }
let mut function_context = Context::new(Some(&context)); let function_context = if let Some(context) = self.context.lock()?.clone() {
context
} else {
panic!("");
};
match (function.type_parameters(), self.type_arguments) { match (function.type_parameters(), self.type_arguments) {
(Some(type_parameters), Some(type_arguments)) => { (Some(type_parameters), Some(type_arguments)) => {
@ -145,7 +157,7 @@ impl AbstractNode for FunctionCall {
function function
.clone() .clone()
.call(arguments, &mut function_context, clear_variables) .call(arguments, &function_context, clear_variables)
} }
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
@ -220,3 +232,23 @@ impl AbstractNode for FunctionCall {
} }
} }
} }
impl Eq for FunctionCall {}
impl PartialEq for FunctionCall {
fn eq(&self, other: &Self) -> bool {
todo!()
}
}
impl PartialOrd for FunctionCall {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
todo!()
}
}
impl Ord for FunctionCall {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
todo!()
}
}

View File

@ -1,6 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, RwLock, RwLockReadGuard}, sync::{Arc, RwLock},
}; };
use crate::{ use crate::{
@ -11,37 +11,40 @@ use crate::{
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Context<'a> { pub struct Context {
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData)>>>, data: Arc<RwLock<ContextData>>,
parent: Option<&'a Context<'a>>,
is_clean: Arc<RwLock<bool>>, is_clean: Arc<RwLock<bool>>,
} }
impl<'a> Context<'a> { #[derive(Clone, Debug)]
pub fn new(parent: Option<&'a Context>) -> Self { struct ContextData {
Self { variables: HashMap<Identifier, (VariableData, UsageData)>,
variables: Arc::new(RwLock::new(HashMap::new())), parent: Option<Context>,
}
impl Context {
pub fn new(parent: Option<Context>) -> Self {
Context {
data: Arc::new(RwLock::new(ContextData {
variables: HashMap::new(),
parent, parent,
})),
is_clean: Arc::new(RwLock::new(true)), is_clean: Arc::new(RwLock::new(true)),
} }
} }
pub fn create_child<'b>(&'b self) -> Context<'b> { pub fn create_child(&self) -> Context {
Context::new(Some(self)) Context::new(Some(self.clone()))
}
pub fn inner(
&self,
) -> Result<RwLockReadGuard<HashMap<Identifier, (VariableData, UsageData)>>, PoisonError> {
Ok(self.variables.read()?)
} }
pub fn contains(&self, identifier: &Identifier) -> Result<bool, PoisonError> { pub fn contains(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
log::trace!("Checking that {identifier} exists."); log::trace!("Checking that {identifier} exists.");
if self.variables.read()?.contains_key(identifier) { let data = self.data.read()?;
if data.variables.contains_key(identifier) {
Ok(true) Ok(true)
} else if let Some(parent) = self.parent { } else if let Some(parent) = &data.parent {
parent.contains(identifier) parent.contains(identifier)
} else { } else {
Ok(false) Ok(false)
@ -49,16 +52,18 @@ impl<'a> Context<'a> {
} }
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
if let Some((data, _)) = self.variables.read()?.get(identifier) {
log::trace!("Getting {identifier}'s type."); log::trace!("Getting {identifier}'s type.");
let data = self.data.read()?;
if let Some((data, _)) = data.variables.get(identifier) {
let r#type = match data { let r#type = match data {
VariableData::Type(r#type) => r#type.clone(), VariableData::Type(r#type) => r#type.clone(),
VariableData::Value(value) => value.r#type(self)?, VariableData::Value(value) => value.r#type(self)?,
}; };
Ok(Some(r#type.clone())) Ok(Some(r#type.clone()))
} else if let Some(parent) = self.parent { } else if let Some(parent) = &data.parent {
parent.get_type(identifier) parent.get_type(identifier)
} else { } else {
Ok(None) Ok(None)
@ -66,16 +71,16 @@ impl<'a> Context<'a> {
} }
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> { pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
if let Some((VariableData::Value(value), usage_data)) =
self.variables.read()?.get(identifier)
{
log::trace!("Using {identifier}'s value."); log::trace!("Using {identifier}'s value.");
let data = self.data.read()?;
if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) {
usage_data.inner().write()?.actual += 1; usage_data.inner().write()?.actual += 1;
*self.is_clean.write()? = false; *self.is_clean.write()? = false;
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else if let Some(parent) = self.parent { } else if let Some(parent) = &data.parent {
parent.use_value(identifier) parent.use_value(identifier)
} else { } else {
Ok(None) Ok(None)
@ -83,27 +88,14 @@ impl<'a> Context<'a> {
} }
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> { pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
if let Some((VariableData::Value(value), _)) = self.variables.read()?.get(identifier) {
log::trace!("Getting {identifier}'s value."); log::trace!("Getting {identifier}'s value.");
let data = self.data.read()?;
if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) {
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else if let Some(parent) = self.parent { } else if let Some(parent) = &data.parent {
parent.get_value(identifier) parent.use_value(identifier)
} else {
Ok(None)
}
}
pub fn get_data(
&self,
identifier: &Identifier,
) -> Result<Option<(VariableData, UsageData)>, PoisonError> {
if let Some(full_data) = self.variables.read()?.get(identifier) {
log::trace!("Getting {identifier}'s value.");
Ok(Some(full_data.clone()))
} else if let Some(parent) = self.parent {
parent.get_data(identifier)
} else { } else {
Ok(None) Ok(None)
} }
@ -112,8 +104,9 @@ impl<'a> Context<'a> {
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> { pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to type {}.", r#type); log::debug!("Setting {identifier} to type {}.", r#type);
self.variables self.data
.write()? .write()?
.variables
.insert(identifier, (VariableData::Type(r#type), UsageData::new())); .insert(identifier, (VariableData::Type(r#type), UsageData::new()));
Ok(()) Ok(())
@ -122,27 +115,43 @@ impl<'a> Context<'a> {
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> { pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to value {value}."); log::debug!("Setting {identifier} to value {value}.");
let mut variables = self.variables.write()?; let mut data = self.data.write()?;
let old_usage_data = variables let usage_data = data
.variables
.remove(&identifier) .remove(&identifier)
.map(|(_, usage_data)| usage_data); .map(|(_, usage_data)| usage_data)
.unwrap_or(UsageData::new());
if let Some(usage_data) = old_usage_data { data.variables
variables.insert(identifier, (VariableData::Value(value), usage_data)); .insert(identifier, (VariableData::Value(value), usage_data));
} else {
variables.insert(identifier, (VariableData::Value(value), UsageData::new()));
}
Ok(()) Ok(())
} }
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
let data = self.data.read()?;
if let Some((_, usage_data)) = data.variables.get(identifier) {
log::trace!("Adding expected use for variable {identifier}.");
usage_data.inner().write()?.expected += 1;
Ok(true)
} else if let Some(parent) = &data.parent {
parent.add_expected_use(identifier)
} else {
Ok(false)
}
}
pub fn clean(&self) -> Result<(), PoisonError> { pub fn clean(&self) -> Result<(), PoisonError> {
if *self.is_clean.read()? { if *self.is_clean.read()? {
return Ok(()); return Ok(());
} }
self.variables self.data
.write()? .write()?
.variables
.retain(|identifier, (value_data, usage_data)| { .retain(|identifier, (value_data, usage_data)| {
if let VariableData::Value(_) = value_data { if let VariableData::Value(_) = value_data {
let usage = usage_data.inner().read().unwrap(); let usage = usage_data.inner().read().unwrap();
@ -165,33 +174,7 @@ impl<'a> Context<'a> {
} }
pub fn is_clean(&mut self) -> Result<bool, PoisonError> { pub fn is_clean(&mut self) -> Result<bool, PoisonError> {
if *self.is_clean.read()? { Ok(*self.is_clean.read()?)
Ok(true)
} else {
for (_, (_, usage_data)) in self.variables.read()?.iter() {
let usage_data = usage_data.inner().read().unwrap();
if usage_data.actual > usage_data.expected {
return Ok(false);
}
}
Ok(true)
}
}
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
if let Some((_, usage_data)) = self.variables.read()?.get(identifier) {
log::trace!("Adding expected use for variable {identifier}.");
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

@ -38,13 +38,13 @@ pub fn interpret_without_std(
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<'a> { pub struct Interpreter {
context: Context<'a>, context: Context,
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>, sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
} }
impl<'a> Interpreter<'a> { impl Interpreter {
pub fn new(context: Context<'a>) -> Self { pub fn new(context: Context) -> Self {
Interpreter { Interpreter {
context, context,
sources: Arc::new(RwLock::new(Vec::new())), sources: Arc::new(RwLock::new(Vec::new())),

View File

@ -731,7 +731,7 @@ impl Function {
pub fn call( pub fn call(
self, self,
value_arguments: Vec<Value>, value_arguments: Vec<Value>,
context: &mut Context, context: &Context,
manage_memory: bool, manage_memory: bool,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
for ((identifier, _), value) in self for ((identifier, _), value) in self

View File

@ -15,7 +15,7 @@ use reedline::{
SqliteBackedHistory, SqliteBackedHistory,
}; };
pub fn run_shell<'a>(context: Context<'a>) -> Result<(), io::Error> { pub fn run_shell(context: Context) -> Result<(), io::Error> {
let mut interpreter = Interpreter::new(context.clone()); let mut interpreter = Interpreter::new(context.clone());
let mut keybindings = default_emacs_keybindings(); let mut keybindings = default_emacs_keybindings();