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 crate::{
@ -8,11 +10,14 @@ use crate::{
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall {
function: Box<Expression>,
type_arguments: Option<Vec<TypeConstructor>>,
value_arguments: Vec<Expression>,
#[serde(skip)]
context: Arc<Mutex<Option<Context>>>,
}
impl FunctionCall {
@ -25,6 +30,7 @@ impl FunctionCall {
function: Box::new(function),
type_arguments,
value_arguments,
context: Arc::new(Mutex::new(None)),
}
}
@ -34,13 +40,15 @@ impl FunctionCall {
}
impl AbstractNode for FunctionCall {
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
self.function.define_types(_context)?;
fn define_types(&self, context: &Context) -> Result<(), ValidationError> {
*self.context.lock()? = Some(context.create_child());
self.function.define_types(context)?;
let mut previous = ();
for expression in &self.value_arguments {
previous = expression.define_types(_context)?;
previous = expression.define_types(context)?;
}
Ok(previous)
@ -128,7 +136,11 @@ impl AbstractNode for FunctionCall {
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) {
(Some(type_parameters), Some(type_arguments)) => {
@ -145,7 +157,7 @@ impl AbstractNode for FunctionCall {
function
.clone()
.call(arguments, &mut function_context, clear_variables)
.call(arguments, &function_context, clear_variables)
}
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::{
collections::HashMap,
sync::{Arc, RwLock, RwLockReadGuard},
sync::{Arc, RwLock},
};
use crate::{
@ -11,37 +11,40 @@ use crate::{
};
#[derive(Clone, Debug)]
pub struct Context<'a> {
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData)>>>,
parent: Option<&'a Context<'a>>,
pub struct Context {
data: Arc<RwLock<ContextData>>,
is_clean: Arc<RwLock<bool>>,
}
impl<'a> Context<'a> {
pub fn new(parent: Option<&'a Context>) -> Self {
Self {
variables: Arc::new(RwLock::new(HashMap::new())),
#[derive(Clone, Debug)]
struct ContextData {
variables: HashMap<Identifier, (VariableData, UsageData)>,
parent: Option<Context>,
}
impl Context {
pub fn new(parent: Option<Context>) -> Self {
Context {
data: Arc::new(RwLock::new(ContextData {
variables: HashMap::new(),
parent,
})),
is_clean: Arc::new(RwLock::new(true)),
}
}
pub fn create_child<'b>(&'b self) -> Context<'b> {
Context::new(Some(self))
}
pub fn inner(
&self,
) -> Result<RwLockReadGuard<HashMap<Identifier, (VariableData, UsageData)>>, PoisonError> {
Ok(self.variables.read()?)
pub fn create_child(&self) -> Context {
Context::new(Some(self.clone()))
}
pub fn contains(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
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)
} else if let Some(parent) = self.parent {
} else if let Some(parent) = &data.parent {
parent.contains(identifier)
} else {
Ok(false)
@ -49,16 +52,18 @@ impl<'a> Context<'a> {
}
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.");
let data = self.data.read()?;
if let Some((data, _)) = data.variables.get(identifier) {
let r#type = match data {
VariableData::Type(r#type) => r#type.clone(),
VariableData::Value(value) => value.r#type(self)?,
};
Ok(Some(r#type.clone()))
} else if let Some(parent) = self.parent {
} else if let Some(parent) = &data.parent {
parent.get_type(identifier)
} else {
Ok(None)
@ -66,16 +71,16 @@ impl<'a> Context<'a> {
}
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.");
let data = self.data.read()?;
if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) {
usage_data.inner().write()?.actual += 1;
*self.is_clean.write()? = false;
Ok(Some(value.clone()))
} else if let Some(parent) = self.parent {
} else if let Some(parent) = &data.parent {
parent.use_value(identifier)
} else {
Ok(None)
@ -83,27 +88,14 @@ impl<'a> Context<'a> {
}
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.");
let data = self.data.read()?;
if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) {
Ok(Some(value.clone()))
} else if let Some(parent) = self.parent {
parent.get_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 if let Some(parent) = &data.parent {
parent.use_value(identifier)
} else {
Ok(None)
}
@ -112,8 +104,9 @@ impl<'a> Context<'a> {
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to type {}.", r#type);
self.variables
self.data
.write()?
.variables
.insert(identifier, (VariableData::Type(r#type), UsageData::new()));
Ok(())
@ -122,27 +115,43 @@ impl<'a> Context<'a> {
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> {
log::debug!("Setting {identifier} to value {value}.");
let mut variables = self.variables.write()?;
let old_usage_data = variables
let mut data = self.data.write()?;
let usage_data = data
.variables
.remove(&identifier)
.map(|(_, usage_data)| usage_data);
.map(|(_, usage_data)| usage_data)
.unwrap_or(UsageData::new());
if let Some(usage_data) = old_usage_data {
variables.insert(identifier, (VariableData::Value(value), usage_data));
} else {
variables.insert(identifier, (VariableData::Value(value), UsageData::new()));
}
data.variables
.insert(identifier, (VariableData::Value(value), usage_data));
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> {
if *self.is_clean.read()? {
return Ok(());
}
self.variables
self.data
.write()?
.variables
.retain(|identifier, (value_data, usage_data)| {
if let VariableData::Value(_) = value_data {
let usage = usage_data.inner().read().unwrap();
@ -165,33 +174,7 @@ impl<'a> Context<'a> {
}
pub fn is_clean(&mut self) -> Result<bool, PoisonError> {
if *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)
}
Ok(*self.is_clean.read()?)
}
}

View File

@ -38,13 +38,13 @@ pub fn interpret_without_std(
interpreter.run(Arc::from(source_id.to_string()), Arc::from(source))
}
pub struct Interpreter<'a> {
context: Context<'a>,
pub struct Interpreter {
context: Context,
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
}
impl<'a> Interpreter<'a> {
pub fn new(context: Context<'a>) -> Self {
impl Interpreter {
pub fn new(context: Context) -> Self {
Interpreter {
context,
sources: Arc::new(RwLock::new(Vec::new())),

View File

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

View File

@ -15,7 +15,7 @@ use reedline::{
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 keybindings = default_emacs_keybindings();