From 9e41c12768562c1c40bc7309a75dd230f384d71f Mon Sep 17 00:00:00 2001 From: Tim Fennis Date: Fri, 6 Dec 2024 14:37:55 +0100 Subject: [PATCH] Expanded scuffed implementation --- src/interpreter.rs | 1 + src/interpreter/function.rs | 11 ++- src/interpreter/heap.rs | 136 ++++++++++++++++++++++++++++++++++++ src/interpreter/iterator.rs | 9 +++ src/interpreter/sequence.rs | 18 +++++ src/interpreter/value.rs | 30 ++++++-- src/stdlib/hash_map.rs | 15 ++++ src/stdlib/math.rs | 10 ++- src/stdlib/sequence.rs | 70 +++++++++++-------- src/stdlib/value.rs | 30 ++++++++ 10 files changed, 293 insertions(+), 37 deletions(-) create mode 100644 src/interpreter/heap.rs diff --git a/src/interpreter.rs b/src/interpreter.rs index 5f2cbaa..77b8721 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -13,6 +13,7 @@ use crate::lexer::{Lexer, TokenLocation}; pub mod environment; pub mod evaluate; pub mod function; +pub(crate) mod heap; pub mod int; pub mod iterator; pub mod num; diff --git a/src/interpreter/function.rs b/src/interpreter/function.rs index c0c1ede..26df3e1 100644 --- a/src/interpreter/function.rs +++ b/src/interpreter/function.rs @@ -160,6 +160,9 @@ pub enum ParamType { Tuple, Map, Iterator, + MinHeap, + MaxHeap, + Deque, } impl ParamType { @@ -186,7 +189,10 @@ impl ParamType { | ValueType::String | ValueType::Map | ValueType::Tuple - | ValueType::Iterator, + | ValueType::Iterator + | ValueType::MinHeap + | ValueType::MaxHeap + | ValueType::Deque, ) => Some(1), _ => None, } @@ -209,6 +215,9 @@ impl From<&Value> for ParamType { Value::Function(_) => ParamType::Function, Value::Sequence(Sequence::Map(_, _)) => ParamType::Map, Value::Sequence(Sequence::Iterator(_)) => ParamType::Iterator, + Value::Sequence(Sequence::MaxHeap(_)) => ParamType::MaxHeap, + Value::Sequence(Sequence::MinHeap(_)) => ParamType::MinHeap, + Value::Sequence(Sequence::Deque(_)) => ParamType::Deque, } } } diff --git a/src/interpreter/heap.rs b/src/interpreter/heap.rs new file mode 100644 index 0000000..94ddf35 --- /dev/null +++ b/src/interpreter/heap.rs @@ -0,0 +1,136 @@ +use crate::interpreter::function::FunctionCarrier; +use crate::interpreter::value::{Value, ValueType}; +use std::cmp::{Ordering, Reverse}; +use std::collections::binary_heap::Iter; +use std::collections::BinaryHeap; + +pub type MinHeap = CheckedHeap>; +pub type MaxHeap = CheckedHeap; +pub struct CheckedHeap { + heap: BinaryHeap, + typ: Option, +} + +impl CheckedHeap +where + T: Ord, +{ + pub fn new() -> Self { + Self { + heap: BinaryHeap::default(), + typ: None, + } + } + + pub fn len(&self) -> usize { + self.heap.len() + } + + pub fn iter(&self) -> Iter<'_, T> { + self.heap.iter() + } + + pub fn peek(&self) -> Option<&T> { + self.heap.peek() + } + + fn check_push(&mut self, value: &Value) -> Result<(), HeapError> { + if value.value_type() == ValueType::Function { + return Err(HeapError::UnsupportedValueType { + typ: ValueType::Function, + }); + } + + if let Some(typ) = self.typ { + if value.value_type() != typ { + return Err(HeapError::InvalidValueType { + expected: typ, + actual: value.value_type(), + }); + } + } else { + self.typ = Some(value.value_type()); + } + + Ok(()) + } +} + +impl MinHeap { + pub fn push(&mut self, value: Value) -> Result<(), HeapError> { + self.check_push(&value)?; + self.heap.push(Reverse(HeapValue(value))); + Ok(()) + } + + pub fn pop(&mut self) -> Value { + let pop = self + .heap + .pop() + .map_or_else(Value::none, |hv| Value::some(hv.0 .0)); + if self.heap.is_empty() { + self.typ = None; + } + pop + } +} + +impl MaxHeap { + pub fn push(&mut self, value: Value) -> Result<(), HeapError> { + self.check_push(&value)?; + self.heap.push(HeapValue(value)); + Ok(()) + } + + pub fn pop(&mut self) -> Value { + let pop = self + .heap + .pop() + .map_or_else(Value::none, |hv| Value::some(hv.0)); + if self.heap.is_empty() { + self.typ = None; + } + pop + } +} + +pub struct HeapValue(pub Value); + +impl PartialEq for HeapValue { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for HeapValue {} +impl PartialOrd for HeapValue { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for HeapValue { + fn cmp(&self, other: &Self) -> Ordering { + self.0 + .partial_cmp(&other.0) + .expect("checked heap must guarantee this never happens") + } +} + +#[derive(thiserror::Error, Debug)] +pub enum HeapError { + // TODO: improve these error messages + #[error("This heap can only contain {expected} but you tried to insert {actual}")] + InvalidValueType { + expected: ValueType, + actual: ValueType, + }, + #[error("Values of type {typ} are not supported in this datastructure")] + UnsupportedValueType { typ: ValueType }, +} + +impl From for FunctionCarrier { + fn from(value: HeapError) -> Self { + FunctionCarrier::IntoEvaluationError(Box::new(value)) + } +} diff --git a/src/interpreter/iterator.rs b/src/interpreter/iterator.rs index 50916c7..a83b7ff 100644 --- a/src/interpreter/iterator.rs +++ b/src/interpreter/iterator.rs @@ -79,6 +79,15 @@ pub fn mut_seq_into_iterator(sequence: &mut Sequence) -> MutableValueIntoIterato Sequence::List(list) => { MutableValueIntoIterator::List(SharedVecIterator::from_shared_vec(list)) } + Sequence::MinHeap(_list) => { + todo!() + } + Sequence::MaxHeap(_list) => { + todo!() + } + Sequence::Deque(_deque) => { + todo!() + } Sequence::Tuple(tup) => MutableValueIntoIterator::Tuple(RcVecIterator::from_rc_vec(tup)), Sequence::Map(map, _) => { MutableValueIntoIterator::Map(SharedHashMapIterator::from_ref(map)) diff --git a/src/interpreter/sequence.rs b/src/interpreter/sequence.rs index 4ca91b2..63899f8 100644 --- a/src/interpreter/sequence.rs +++ b/src/interpreter/sequence.rs @@ -1,8 +1,10 @@ use crate::hash_map::HashMap; +use crate::interpreter::heap::{MaxHeap, MinHeap}; use crate::interpreter::iterator::ValueIterator; use crate::interpreter::value::Value; use std::cell::RefCell; use std::cmp::Ordering; +use std::collections::VecDeque; use std::fmt; use std::rc::Rc; @@ -16,6 +18,9 @@ pub enum Sequence { Tuple(Rc>), Map(Rc>>, Option>), Iterator(Rc>), + MaxHeap(Rc>), + MinHeap(Rc>), + Deque(Rc>>), } impl Sequence { @@ -27,6 +32,9 @@ impl Sequence { Sequence::Tuple(tup) => Some(tup.len()), Sequence::Map(map, _) => Some(map.borrow().len()), Sequence::Iterator(_iter) => None, + Sequence::MaxHeap(heap) => Some(heap.borrow().len()), + Sequence::MinHeap(heap) => Some(heap.borrow().len()), + Sequence::Deque(deque) => Some(deque.borrow().len()), } } } @@ -38,7 +46,13 @@ impl PartialEq for Sequence { (Sequence::List(a), Sequence::List(b)) => a == b, (Sequence::Tuple(a), Sequence::Tuple(b)) => a == b, (Sequence::Map(a, _), Sequence::Map(b, _)) => a == b, + (Sequence::Deque(a), Sequence::Deque(b)) => a == b, + + // TODO: These implementations are a little sussy + (Sequence::MaxHeap(a), Sequence::MaxHeap(b)) => Rc::ptr_eq(a, b), + (Sequence::MinHeap(a), Sequence::MinHeap(b)) => Rc::ptr_eq(a, b), (Sequence::Iterator(a), Sequence::Iterator(b)) => Rc::ptr_eq(a, b), + _ => false, } } @@ -111,6 +125,10 @@ impl fmt::Debug for Sequence { Sequence::Iterator(_) => { write!(f, "iterator") } + // TODO: create more sensible implementations?? + Sequence::MaxHeap(_) => write!(f, "max-heap"), + Sequence::MinHeap(_) => write!(f, "min-heap"), + Sequence::Deque(_) => write!(f, "deque"), } } } diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index fc5e95f..775caf3 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -128,6 +128,9 @@ impl Value { Value::Function(_) => ValueType::Function, Value::Sequence(Sequence::Map(_, _)) => ValueType::Map, Value::Sequence(Sequence::Iterator(_)) => ValueType::Iterator, + Value::Sequence(Sequence::MaxHeap(_)) => ValueType::MaxHeap, + Value::Sequence(Sequence::MinHeap(_)) => ValueType::MinHeap, + Value::Sequence(Sequence::Deque(_)) => ValueType::Deque, } } @@ -229,9 +232,23 @@ impl Hash for Value { state.write_u8(9); Rc::as_ptr(i).hash(state); } + Sequence::MaxHeap(h) => { + state.write_u8(10); + Rc::as_ptr(h).hash(state); // TODO: does this make sense? + } + Sequence::MinHeap(h) => { + state.write_u8(11); + Rc::as_ptr(h).hash(state); // TODO: does this make sense? + } + Sequence::Deque(list) => { + state.write_u8(12); + for item in list.borrow().iter() { + item.hash(state); + } + } }, Value::Function(f) => { - state.write_u8(9); + state.write_u8(13); Rc::as_ptr(f).hash(state); } } @@ -302,8 +319,7 @@ impl From for Value { impl From for Value { fn from(value: char) -> Self { - // Haha so many heap allocations and decorators for a single character - Self::Sequence(Sequence::String(Rc::new(RefCell::new(String::from(value))))) + Value::string(value) } } @@ -589,6 +605,9 @@ pub enum ValueType { Function, Map, Iterator, + MinHeap, + MaxHeap, + Deque, } impl From<&Value> for ValueType { @@ -609,6 +628,9 @@ impl fmt::Display for ValueType { Self::Function => write!(f, "function"), Self::Map => write!(f, "map"), Self::Iterator => write!(f, "iterator"), + Self::MinHeap => write!(f, "min-heap"), + Self::MaxHeap => write!(f, "max-heap"), + Self::Deque => write!(f, "deque"), } } } @@ -631,7 +653,7 @@ impl fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Option(Some(v)) => write!(f, "Some({v})"), - Self::Option(None) => write!(f, ""), + Self::Option(None) => write!(f, "None"), Self::Number(n) => write!(f, "{n}"), Self::Bool(b) => write!(f, "{b}"), Self::Function(_) => { diff --git a/src/stdlib/hash_map.rs b/src/stdlib/hash_map.rs index 51475d0..7a39eee 100644 --- a/src/stdlib/hash_map.rs +++ b/src/stdlib/hash_map.rs @@ -79,6 +79,21 @@ mod inner { } out } + Sequence::MaxHeap(h) => h + .borrow() + .iter() + .map(|value| (value.0.clone(), Value::unit())) + .collect(), + Sequence::MinHeap(h) => h + .borrow() + .iter() + .map(|value| (value.0 .0.clone(), Value::unit())) + .collect(), + Sequence::Deque(rc) => rc + .borrow() + .iter() + .map(|v| (v.to_owned(), Value::unit())) + .collect(), }; Value::Sequence(Sequence::Map(Rc::new(RefCell::new(out)), None)) diff --git a/src/stdlib/math.rs b/src/stdlib/math.rs index addd071..69cdfc3 100644 --- a/src/stdlib/math.rs +++ b/src/stdlib/math.rs @@ -37,7 +37,7 @@ where { fn try_product(&mut self) -> anyhow::Result { self.try_fold(Number::from(1), |acc, cur| match cur.borrow() { - Value::Number(n) => Ok(acc * n.clone()), + Value::Number(n) => Ok(acc * n.clone()), // TODO: we can probably lose this clone value => Err(anyhow::anyhow!( "cannot multiply {} and number", value.value_type() @@ -82,6 +82,10 @@ mod inner { Sequence::Tuple(tup) => tup.iter().try_sum(), Sequence::Map(map, _) => map.borrow().keys().try_sum(), Sequence::Iterator(iter) => iter.borrow_mut().try_sum(), + Sequence::MaxHeap(h) => h.borrow().iter().map(|v| v.0.clone()).try_sum(), + // TODO: This clone is pretty bad + Sequence::MinHeap(h) => h.borrow().iter().map(|v| v.0 .0.clone()).try_sum(), + Sequence::Deque(d) => d.borrow().iter().try_sum(), } } @@ -92,6 +96,10 @@ mod inner { Sequence::Tuple(tup) => tup.iter().try_product(), Sequence::Map(map, _) => map.borrow().keys().try_product(), Sequence::Iterator(iter) => iter.borrow_mut().try_product(), + Sequence::MaxHeap(h) => h.borrow().iter().map(|v| v.0.clone()).try_product(), + // TODO: This clone is pretty bad + Sequence::MinHeap(h) => h.borrow().iter().map(|v| v.0 .0.clone()).try_product(), + Sequence::Deque(d) => d.borrow().iter().try_product(), } } diff --git a/src/stdlib/sequence.rs b/src/stdlib/sequence.rs index 568fa93..b7a77a0 100644 --- a/src/stdlib/sequence.rs +++ b/src/stdlib/sequence.rs @@ -91,6 +91,19 @@ mod inner { Sequence::Tuple(l) => l.iter().try_max(), Sequence::Map(map, _) => map.borrow().keys().try_max(), Sequence::Iterator(iter) => iter.borrow_mut().try_max(), + Sequence::MaxHeap(h) => h + .borrow() + .peek() + .map(|hv| hv.0.clone()) + .ok_or_else(|| anyhow::anyhow!("empty input to max")), + // TODO: can this be improved? + Sequence::MinHeap(h) => h + .borrow() + .iter() + .last() + .map(|v| v.0 .0.clone()) + .ok_or_else(|| anyhow::anyhow!("empty input to max")), + Sequence::Deque(d) => d.try_borrow()?.iter().try_max(), } } pub fn min(seq: &Sequence) -> anyhow::Result { @@ -105,6 +118,19 @@ mod inner { Sequence::Tuple(l) => l.iter().try_min(), Sequence::Map(map, _) => map.borrow().keys().try_min(), Sequence::Iterator(iter) => iter.borrow_mut().try_min(), + Sequence::MaxHeap(h) => h + .borrow() + .iter() + .last() + .map(|hv| hv.0.clone()) + .ok_or_else(|| anyhow::anyhow!("empty input to max")), + // TODO: can this be improved? + Sequence::MinHeap(h) => h + .borrow() + .peek() + .map(|hv| hv.0 .0.clone()) + .ok_or_else(|| anyhow::anyhow!("empty input to max")), + Sequence::Deque(d) => d.try_borrow()?.iter().try_min(), } } @@ -123,6 +149,9 @@ mod inner { Sequence::Tuple(_) => Err(anyhow!("tuple cannot be sorted in place")), Sequence::Map(_, _) => Err(anyhow!("map cannot be sorted in place")), Sequence::Iterator(_) => Err(anyhow!("iterator cannot be sorted in place")), + Sequence::MaxHeap(_) => Err(anyhow!("heap is already sorted")), + Sequence::MinHeap(_) => Err(anyhow!("heap is already sorted")), + Sequence::Deque(_) => Err(anyhow!("deque cannot be sorted in place")), } } @@ -156,16 +185,12 @@ mod inner { } pub fn len(seq: &Sequence) -> anyhow::Result { - match seq { - Sequence::String(s) => Ok(s.borrow().chars().count()), - Sequence::List(l) => Ok(l.borrow().len()), - Sequence::Tuple(t) => Ok(t.len()), - Sequence::Map(d, _) => Ok(d.borrow().len()), - Sequence::Iterator(_) => Err(anyhow!("cannot determine the length of an iterator")), - } + // TODO: determine the type programmatically instead of hardcoding it to iterator (in case we add more types) + seq.length() + .ok_or_else(|| anyhow!("cannot determine the length of an iterator")) } - pub fn enumerate(seq: &Sequence) -> Value { + pub fn enumerate(seq: &mut Sequence) -> Value { match seq { Sequence::String(s) => s .borrow() @@ -179,29 +204,6 @@ mod inner { }) .collect::>() .into(), - Sequence::List(list) => list - .borrow() - .iter() - .enumerate() - .map(|(index, value)| { - Value::Sequence(Sequence::Tuple(Rc::new(vec![ - Value::from(index), - Value::clone(value), - ]))) - }) - .collect::>() - .into(), - Sequence::Tuple(tuple) => tuple - .iter() - .enumerate() - .map(|(index, value)| { - Value::Sequence(Sequence::Tuple(Rc::new(vec![ - Value::from(index), - Value::clone(value), - ]))) - }) - .collect::>() - .into(), Sequence::Map(map, _) => map .borrow() .iter() @@ -230,6 +232,12 @@ mod inner { out.into() } + seq => Value::list( + mut_seq_into_iterator(seq) + .enumerate() + .map(|(idx, value)| Value::tuple(vec![Value::from(idx), value])) + .collect::>(), + ), } } diff --git a/src/stdlib/value.rs b/src/stdlib/value.rs index d9b6ae6..58360ac 100644 --- a/src/stdlib/value.rs +++ b/src/stdlib/value.rs @@ -2,6 +2,8 @@ use andy_cpp_macros::export_module; #[export_module] mod inner { + use crate::interpreter::evaluate::EvaluationResult; + use crate::interpreter::heap::{MaxHeap, MinHeap}; use crate::interpreter::sequence::Sequence; use crate::interpreter::value::Value; use std::cell::RefCell; @@ -53,6 +55,34 @@ mod inner { Value::Sequence(Sequence::Iterator(iterator.clone())) } Value::Function(f) => Value::from(f.borrow().to_owned()), + _ => todo!("implement cloning for new types"), } } + + #[function(name = "MinHeap")] + pub fn create_min_heap() -> Value { + Value::Sequence(Sequence::MinHeap(Rc::new(RefCell::new(MinHeap::new())))) + } + + pub fn pop(seq: &Sequence) -> Value { + match seq { + Sequence::MinHeap(heap) => heap.borrow_mut().pop(), + + Sequence::MaxHeap(heap) => heap.borrow_mut().pop(), + _ => todo!("not implemented"), + } + } + + pub fn push(seq: &Sequence, val: Value) -> EvaluationResult { + match seq { + Sequence::MinHeap(heap) => heap.borrow_mut().push(val)?, + Sequence::MaxHeap(heap) => heap.borrow_mut().push(val)?, + _ => todo!("not implemented"), + } + Ok(Value::unit()) + } + #[function(name = "MaxHeap")] + pub fn create_max_heap() -> Value { + Value::Sequence(Sequence::MaxHeap(Rc::new(RefCell::new(MaxHeap::new())))) + } }