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 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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>,
|
||||||
parent,
|
}
|
||||||
|
|
||||||
|
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)),
|
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)) =
|
log::trace!("Using {identifier}'s value.");
|
||||||
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;
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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())),
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user