1
0

Add memory management

This commit is contained in:
Jeff 2024-03-11 21:57:27 -04:00
parent 4be32d0a5d
commit fdf286cb51
12 changed files with 116 additions and 134 deletions

1
Cargo.lock generated
View File

@ -204,6 +204,7 @@ dependencies = [
"clap", "clap",
"colored", "colored",
"env_logger", "env_logger",
"log",
"stanza", "stanza",
] ]

View File

@ -18,4 +18,5 @@ chumsky = { version = "1.0.0-alpha.6", features = ["pratt", "label"] }
clap = { version = "4.5.2", features = ["derive"] } clap = { version = "4.5.2", features = ["derive"] }
colored = "2.1.0" colored = "2.1.0"
env_logger = "0.11.3" env_logger = "0.11.3"
log = "0.4.21"
stanza = "0.5.1" stanza = "0.5.1"

View File

@ -52,6 +52,7 @@ impl AbstractTree for Assignment {
context.set_type(self.identifier.clone(), statement_type)?; context.set_type(self.identifier.clone(), statement_type)?;
} }
self.identifier.validate(context)?;
self.statement.validate(context)?; self.statement.validate(context)?;
Ok(()) Ok(())

View File

@ -38,12 +38,12 @@ impl AbstractTree for FunctionCall {
} }
fn run(self, context: &Context) -> Result<Action, RuntimeError> { fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let value = self.function.run(context)?.as_value()?; let value = self.function.run(context)?.as_return_value()?;
let function = value.as_function()?; let function = value.as_function()?;
let mut arguments = Vec::with_capacity(self.arguments.len()); let mut arguments = Vec::with_capacity(self.arguments.len());
for expression in self.arguments { for expression in self.arguments {
let value = expression.run(context)?.as_value()?; let value = expression.run(context)?.as_return_value()?;
arguments.push(value); arguments.push(value);
} }

View File

@ -6,7 +6,6 @@ use std::{
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
Value,
}; };
use super::{AbstractTree, Action, Type}; use super::{AbstractTree, Action, Type};
@ -34,7 +33,7 @@ impl AbstractTree for Identifier {
} }
fn validate(&self, context: &Context) -> Result<(), ValidationError> { fn validate(&self, context: &Context) -> Result<(), ValidationError> {
if let Some(_) = context.get_data(self)? { if context.add_allowance(self)? {
Ok(()) Ok(())
} else { } else {
Err(ValidationError::VariableNotFound(self.clone())) Err(ValidationError::VariableNotFound(self.clone()))
@ -42,12 +41,15 @@ impl AbstractTree for Identifier {
} }
fn run(self, context: &Context) -> Result<Action, RuntimeError> { fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let value = context let return_action = context.get_value(&self)?.map(|value| Action::Return(value));
.get_value(&self)?
.unwrap_or_else(Value::none)
.clone();
Ok(Action::Return(value)) if let Some(action) = return_action {
Ok(action)
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound(self.clone()),
))
}
} }
} }

View File

@ -1,7 +1,6 @@
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
Value,
}; };
use super::{AbstractTree, Action, Expression, Type, ValueNode}; use super::{AbstractTree, Action, Expression, Type, ValueNode};
@ -63,11 +62,13 @@ impl AbstractTree for Index {
let right_value = self.right.run(_context)?.as_return_value()?; let right_value = self.right.run(_context)?.as_return_value()?;
if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) { if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) {
Ok(Action::Return( let found_item = list.get(index as usize);
list.get(index as usize)
.cloned() if let Some(item) = found_item {
.unwrap_or_else(Value::none), Ok(Action::Return(item.clone()))
)) } else {
Ok(Action::None)
}
} else { } else {
Err(RuntimeError::ValidationFailure( Err(RuntimeError::ValidationFailure(
ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()), ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()),

View File

@ -44,19 +44,12 @@ pub trait AbstractTree {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub enum Action { pub enum Action {
Break,
Return(Value), Return(Value),
Break,
None, None,
} }
impl Action { impl Action {
pub fn as_value(self) -> Result<Value, ValidationError> {
match self {
Action::Return(value) => Ok(value),
_ => Err(ValidationError::ExpectedValue),
}
}
pub fn as_return_value(self) -> Result<Value, ValidationError> { pub fn as_return_value(self) -> Result<Value, ValidationError> {
if let Action::Return(value) = self { if let Action::Return(value) = self {
Ok(value) Ok(value)

View File

@ -17,7 +17,6 @@ pub enum ValueNode {
Map(Vec<(Identifier, Option<Type>, Expression)>), Map(Vec<(Identifier, Option<Type>, Expression)>),
Range(Range<i64>), Range(Range<i64>),
String(String), String(String),
Enum(Identifier, Identifier),
Function { Function {
parameters: Vec<(Identifier, Type)>, parameters: Vec<(Identifier, Type)>,
return_type: Type, return_type: Type,
@ -43,7 +42,6 @@ impl AbstractTree for ValueNode {
ValueNode::Map(_) => Type::Map, ValueNode::Map(_) => Type::Map,
ValueNode::Range(_) => Type::Range, ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String, ValueNode::String(_) => Type::String,
ValueNode::Enum(name, _) => Type::Custom(name.clone()),
ValueNode::Function { ValueNode::Function {
parameters, parameters,
return_type, return_type,
@ -123,13 +121,6 @@ impl AbstractTree for ValueNode {
} }
ValueNode::Range(range) => Value::range(range), ValueNode::Range(range) => Value::range(range),
ValueNode::String(string) => Value::string(string), ValueNode::String(string) => Value::string(string),
ValueNode::Enum(name, variant) => {
if name.as_str() == "Option" && variant.as_str() == "None" {
Value::none()
} else {
Value::r#enum(name, variant)
}
}
ValueNode::Function { ValueNode::Function {
parameters, parameters,
return_type, return_type,
@ -176,16 +167,6 @@ impl Ord for ValueNode {
(Range(_), _) => Ordering::Greater, (Range(_), _) => Ordering::Greater,
(String(left), String(right)) => left.cmp(right), (String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater, (String(_), _) => Ordering::Greater,
(Enum(left_name, left_variant), Enum(right_name, right_variant)) => {
let name_cmp = left_name.cmp(right_name);
if name_cmp.is_eq() {
left_variant.cmp(right_variant)
} else {
name_cmp
}
}
(Enum(_, _), _) => Ordering::Greater,
( (
Function { Function {
parameters: left_parameters, parameters: left_parameters,

View File

@ -27,15 +27,15 @@ impl AbstractTree for While {
self.block.validate(_context) self.block.validate(_context)
} }
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, context: &Context) -> Result<Action, RuntimeError> {
while self while self
.expression .expression
.clone() .clone()
.run(_context)? .run(context)?
.as_return_value()? .as_return_value()?
.as_boolean()? .as_boolean()?
{ {
if let Action::Break = self.block.clone().run(_context)? { if let Action::Break = self.block.clone().run(context)? {
break; break;
} }
} }

View File

@ -11,7 +11,25 @@ use crate::{
}; };
pub struct Context { pub struct Context {
inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>, inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
}
#[derive(Clone, Debug)]
pub struct UsageData(Arc<RwLock<UsageDataInner>>);
#[derive(Clone, Debug)]
pub struct UsageDataInner {
pub allowances: usize,
pub uses: usize,
}
impl Default for UsageData {
fn default() -> Self {
UsageData(Arc::new(RwLock::new(UsageDataInner {
allowances: 0,
uses: 0,
})))
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -27,7 +45,7 @@ impl Context {
} }
} }
pub fn with_data(data: BTreeMap<Identifier, ValueData>) -> Self { pub fn with_data(data: BTreeMap<Identifier, (ValueData, UsageData)>) -> Self {
Self { Self {
inner: Arc::new(RwLock::new(data)), inner: Arc::new(RwLock::new(data)),
} }
@ -36,10 +54,10 @@ impl Context {
pub fn inherit_types_from(other: &Context) -> Result<Self, RwLockPoisonError> { pub fn inherit_types_from(other: &Context) -> Result<Self, RwLockPoisonError> {
let mut new_data = BTreeMap::new(); let mut new_data = BTreeMap::new();
for (identifier, value_data) in other.inner.read()?.iter() { for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
if let ValueData::Type(r#type) = value_data { if let ValueData::Type(r#type) = value_data {
if let Type::Function { .. } = r#type { if let Type::Function { .. } = r#type {
new_data.insert(identifier.clone(), value_data.clone()); new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
} }
} }
} }
@ -50,15 +68,15 @@ impl Context {
pub fn inherit_data_from(other: &Context) -> Result<Self, RwLockPoisonError> { pub fn inherit_data_from(other: &Context) -> Result<Self, RwLockPoisonError> {
let mut new_data = BTreeMap::new(); let mut new_data = BTreeMap::new();
for (identifier, value_data) in other.inner.read()?.iter() { for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
if let ValueData::Type(r#type) = value_data { if let ValueData::Type(r#type) = value_data {
if let Type::Function { .. } = r#type { if let Type::Function { .. } = r#type {
new_data.insert(identifier.clone(), value_data.clone()); new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
} }
} }
if let ValueData::Value(value) = value_data { if let ValueData::Value(value) = value_data {
if let ValueInner::Function { .. } = value.inner().as_ref() { if let ValueInner::Function { .. } = value.inner().as_ref() {
new_data.insert(identifier.clone(), value_data.clone()); new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
} }
} }
} }
@ -66,12 +84,41 @@ impl Context {
Ok(Self::with_data(new_data)) Ok(Self::with_data(new_data))
} }
pub fn add_allowance(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
if let Some((_, usage_data)) = self.inner.read()?.get(identifier) {
usage_data.0.write()?.allowances += 1;
Ok(true)
} else {
Ok(false)
}
}
pub fn get_data( pub fn get_data(
&self, &self,
identifier: &Identifier, identifier: &Identifier,
) -> Result<Option<ValueData>, RwLockPoisonError> { ) -> Result<Option<ValueData>, RwLockPoisonError> {
if let Some(value_data) = self.inner.read()?.get(identifier) { let should_remove =
return Ok(Some(value_data.clone())); if let Some((value_data, usage_data)) = self.inner.read()?.get(identifier) {
let mut usage_data = usage_data.0.write()?;
log::trace!("Adding use for variable: {identifier}");
usage_data.uses += 1;
if usage_data.uses == usage_data.allowances {
true
} else {
return Ok(Some(value_data.clone()));
}
} else {
false
};
if should_remove {
log::trace!("Removing varialble: {identifier}");
self.inner.write()?.remove(identifier);
} }
let value_data = match identifier.as_str() { let value_data = match identifier.as_str() {
@ -83,7 +130,11 @@ impl Context {
} }
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
if let Some(ValueData::Type(r#type)) = self.inner.read()?.get(identifier) { if let Some((ValueData::Type(r#type), usage_data)) = self.inner.read()?.get(identifier) {
log::trace!("Adding use for variable: {identifier}");
usage_data.0.write()?.uses += 1;
return Ok(Some(r#type.clone())); return Ok(Some(r#type.clone()));
} }
@ -96,8 +147,28 @@ impl Context {
} }
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> { pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) { let should_remove = if let Some((ValueData::Value(value), usage_data)) =
return Ok(Some(value.clone())); self.inner.read()?.get(identifier)
{
let mut usage_data = usage_data.0.write()?;
log::trace!("Adding use for variable: {identifier}");
usage_data.uses += 1;
if usage_data.uses == usage_data.allowances {
true
} else {
return Ok(Some(value.clone()));
}
} else {
false
};
if should_remove {
log::trace!("Removing varialble: {identifier}");
self.inner.write()?.remove(identifier);
} }
let value = match identifier.as_str() { let value = match identifier.as_str() {
@ -111,15 +182,19 @@ impl Context {
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> { pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
self.inner self.inner
.write()? .write()?
.insert(identifier, ValueData::Type(r#type)); .insert(identifier, (ValueData::Type(r#type), UsageData::default()));
Ok(()) Ok(())
} }
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> { pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> {
self.inner let mut inner = self.inner.write()?;
.write()?
.insert(identifier, ValueData::Value(value)); if let Some((_value_data, usage_data)) = inner.remove(&identifier) {
inner.insert(identifier, (ValueData::Value(value), usage_data));
} else {
inner.insert(identifier, (ValueData::Value(value), UsageData::default()));
}
Ok(()) Ok(())
} }

View File

@ -169,13 +169,6 @@ pub fn parser<'src>() -> DustParser<'src> {
) )
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list))); .map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
let r#enum = identifier
.clone()
.then_ignore(just(Token::Control(Control::DoubleColon)))
.then(identifier.clone())
.map(|(name, variant)| Expression::Value(ValueNode::Enum(name, variant)))
.boxed();
let function = identifier let function = identifier
.clone() .clone()
.then(type_specification.clone()) .then(type_specification.clone())
@ -219,7 +212,6 @@ pub fn parser<'src>() -> DustParser<'src> {
identifier_expression.clone(), identifier_expression.clone(),
basic_value.clone(), basic_value.clone(),
list.clone(), list.clone(),
r#enum.clone(),
expression.clone().delimited_by( expression.clone().delimited_by(
just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)), just(Token::Control(Control::ParenClose)),
@ -289,7 +281,6 @@ pub fn parser<'src>() -> DustParser<'src> {
choice(( choice((
function, function,
range, range,
r#enum,
logic_math_and_index, logic_math_and_index,
identifier_expression, identifier_expression,
list, list,
@ -661,22 +652,6 @@ mod tests {
); );
} }
#[test]
fn assignment_with_custom_type() {
assert_eq!(
parse(&lex("foobar: Foo = Foo::Bar").unwrap()).unwrap()[0].0,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Some(Type::Custom(Identifier::new("Foo"))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Enum(
Identifier::new("Foo"),
Identifier::new("Bar")
)))
)),
);
}
#[test] #[test]
fn assignment_with_list_types() { fn assignment_with_list_types() {
assert_eq!( assert_eq!(
@ -755,17 +730,6 @@ mod tests {
); );
} }
#[test]
fn r#enum() {
assert_eq!(
parse(&lex("Option::None").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::Enum(
Identifier::new("Option"),
Identifier::new("None")
)))
);
}
#[test] #[test]
fn list() { fn list() {
assert_eq!( assert_eq!(

View File

@ -18,17 +18,6 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
pub static NONE: OnceLock<Value> = OnceLock::new();
fn get_none<'a>() -> &'a Value {
NONE.get_or_init(|| {
Value(Arc::new(ValueInner::Enum(
Identifier::new("Option"),
Identifier::new("None"),
)))
})
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Value(Arc<ValueInner>); pub struct Value(Arc<ValueInner>);
@ -37,10 +26,6 @@ impl Value {
&self.0 &self.0
} }
pub fn none() -> Self {
get_none().clone()
}
pub fn boolean(boolean: bool) -> Self { pub fn boolean(boolean: bool) -> Self {
Value(Arc::new(ValueInner::Boolean(boolean))) Value(Arc::new(ValueInner::Boolean(boolean)))
} }
@ -69,10 +54,6 @@ impl Value {
Value(Arc::new(ValueInner::String(string))) Value(Arc::new(ValueInner::String(string)))
} }
pub fn r#enum(name: Identifier, variant: Identifier) -> Self {
Value(Arc::new(ValueInner::Enum(name, variant)))
}
pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self { pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self {
Value(Arc::new(ValueInner::Function(Function::Parsed( Value(Arc::new(ValueInner::Function(Function::Parsed(
ParsedFunction { ParsedFunction {
@ -104,7 +85,6 @@ impl Value {
ValueInner::Map(_) => Type::Map, ValueInner::Map(_) => Type::Map,
ValueInner::Range(_) => Type::Range, ValueInner::Range(_) => Type::Range,
ValueInner::String(_) => Type::String, ValueInner::String(_) => Type::String,
ValueInner::Enum(name, _) => Type::Custom(name.clone()),
ValueInner::Function(_) => todo!(), ValueInner::Function(_) => todo!(),
} }
} }
@ -149,10 +129,6 @@ impl Value {
} }
} }
pub fn is_none(&self) -> bool {
self == get_none()
}
pub fn add(&self, other: &Self) -> Result<Value, ValidationError> { pub fn add(&self, other: &Self) -> Result<Value, ValidationError> {
match (self.inner().as_ref(), other.inner().as_ref()) { match (self.inner().as_ref(), other.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => { (ValueInner::Integer(left), ValueInner::Integer(right)) => {
@ -236,8 +212,6 @@ impl Display for Value {
} }
ValueInner::Range(_) => todo!(), ValueInner::Range(_) => todo!(),
ValueInner::String(string) => write!(f, "{string}"), ValueInner::String(string) => write!(f, "{string}"),
ValueInner::Enum(_, _) => todo!(),
ValueInner::Function(Function::Parsed(ParsedFunction { ValueInner::Function(Function::Parsed(ParsedFunction {
parameters, parameters,
return_type, return_type,
@ -282,7 +256,6 @@ pub enum ValueInner {
Map(BTreeMap<Identifier, Value>), Map(BTreeMap<Identifier, Value>),
Range(Range<i64>), Range(Range<i64>),
String(String), String(String),
Enum(Identifier, Identifier),
} }
impl Eq for ValueInner {} impl Eq for ValueInner {}
@ -320,16 +293,6 @@ impl Ord for ValueInner {
(Range(_), _) => Ordering::Greater, (Range(_), _) => Ordering::Greater,
(String(left), String(right)) => left.cmp(right), (String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater, (String(_), _) => Ordering::Greater,
(Enum(name_left, variant_left), Enum(name_right, variant_right)) => {
let name_cmp = name_left.cmp(name_right);
if name_cmp.is_eq() {
variant_left.cmp(variant_right)
} else {
name_cmp
}
}
(Enum(..), _) => Ordering::Greater,
(Function(left), Function(right)) => left.cmp(right), (Function(left), Function(right)) => left.cmp(right),
(Function(_), _) => Ordering::Greater, (Function(_), _) => Ordering::Greater,
} }