Refactor context
This commit is contained in:
parent
240c045a0c
commit
1cd101db3f
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -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())),
|
||||
parent,
|
||||
#[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.");
|
||||
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.");
|
||||
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.");
|
||||
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()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())),
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user