Mainly worked on the rule matcher

Also fixed the name collector, and lambda parameters are no longer
resolved at parsing to support planned macro-based pattern matching.
The rule matcher clones a lot, the number of clones could be zero.
This commit is contained in:
2022-08-06 18:12:51 +02:00
parent 119f41076e
commit 329dea72b7
24 changed files with 777 additions and 134 deletions

View File

@@ -4,16 +4,21 @@ use mappable_rc::Mrc;
/// Cache the return values of an effectless closure in a hashmap
/// Inspired by the closure_cacher crate.
pub struct Cache<I, O: 'static> where O: Clone {
pub struct Cache<'a, I, O: 'static> /*where O: Clone*/ {
store: RefCell<HashMap<I, Mrc<O>>>,
closure: RefCell<Box<dyn FnMut (I) -> O + 'static>>
closure: RefCell<Box<dyn FnMut (I, &Self) -> Mrc<O> + 'a>>
}
impl<I, O> Cache<I, O> where
I: Eq + Hash + Clone,
O: Clone
impl<'a, I, O> Cache<'a, I, O> where
I: Eq + Hash + Clone
{
pub fn new<F: 'static>(closure: F) -> Self where F: FnMut(I) -> O {
pub fn new<F: 'a>(mut closure: F) -> Self where F: FnMut(I, &Self) -> O {
Self::new_raw(move |o, s| Mrc::new(closure(o, s)))
}
/// Take an Mrc<O> closure rather than an O closure
/// Used internally to derive caches from other systems working with Mrc-s
pub fn new_raw<F: 'a>(closure: F) -> Self where F: FnMut(I, &Self) -> Mrc<O> {
Self {
store: RefCell::new(HashMap::new()),
closure: RefCell::new(Box::new(closure))
@@ -25,7 +30,7 @@ impl<I, O> Cache<I, O> where
let mut closure = self.closure.borrow_mut();
let mut store = self.store.borrow_mut();
Mrc::clone(store.raw_entry_mut().from_key(i)
.or_insert_with(|| (i.clone(), Mrc::new(closure(i.clone())))).1)
.or_insert_with(|| (i.clone(), closure(i.clone(), self))).1)
}
#[allow(dead_code)]
/// Return the result if it has already been computed
@@ -40,9 +45,9 @@ impl<I, O> Cache<I, O> where
}
}
impl<I, O, E> Cache<I, Result<O, E>> where
impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where
I: Eq + Hash + Clone,
O: Clone,
// O: Clone,
E: Clone
{
/// Sink the ref from a Result into the Ok value, such that cloning only occurs on the sad path
@@ -54,9 +59,9 @@ impl<I, O, E> Cache<I, Result<O, E>> where
}
}
impl<I, O> Cache<I, Option<O>> where
impl<'a, I, O> Cache<'a, I, Option<O>> where
I: Eq + Hash + Clone,
O: Clone
// O: Clone
{
#[allow(dead_code)]
/// Sink the ref from an Option into the Some value such that the return value can be
@@ -65,4 +70,4 @@ impl<I, O> Cache<I, Option<O>> where
let ent = self.find(i);
Mrc::try_map(ent, |o| o.as_ref()).ok()
}
}
}

27
src/utils/merge_sorted.rs Normal file
View File

@@ -0,0 +1,27 @@
use std::mem;
// use itertools::Itertools;
/// Merge two sorted iterators into a sorted iterator.
pub fn merge_sorted<T, I, J, F, O>(mut i: I, mut j: J, mut f: F) -> impl Iterator<Item = T>
where
I: Iterator<Item = T>, J: Iterator<Item = T>,
F: FnMut(&T) -> O, O: Ord,
{
let mut i_item: Option<T> = None;
let mut j_item: Option<T> = None;
std::iter::from_fn(move || {
match (&mut i_item, &mut j_item) {
(&mut None, &mut None) => None,
(&mut None, j_item @ &mut Some(_)) => Some((j_item, None)),
(i_item @ &mut Some(_), &mut None) => Some((i_item, i.next())),
(Some(i_val), Some(j_val)) => Some(
if f(i_val) < f(j_val) {
(&mut i_item, i.next())
} else {
(&mut j_item, j.next())
}
)
}.and_then(|(dest, value)| mem::replace(dest, value))
})
}

View File

@@ -1,6 +1,12 @@
mod cache;
mod substack;
mod side;
mod merge_sorted;
mod sorted_pairs;
mod unwrap_or_continue;
pub use cache::Cache;
pub use substack::Substack;
pub use substack::Stackframe;
pub use side::Side;
pub use merge_sorted::merge_sorted;
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;

53
src/utils/side.rs Normal file
View File

@@ -0,0 +1,53 @@
use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Side {Left, Right}
impl Display for Side {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Left => write!(f, "Left"),
Self::Right => write!(f, "Right"),
}
}
}
impl Side {
pub fn opposite(&self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left
}
}
/// Shorthand for opposite
pub fn inv(&self) -> Self { self.opposite() }
/// take N elements from this end of a slice
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
match self {
Side::Left => &slice[..size],
Side::Right => &slice[slice.len() - size..]
}
}
/// ignore N elements from this end of a slice
pub fn crop<'a, T>(&self, margin: usize, slice: &'a [T]) -> &'a [T] {
self.opposite().slice(slice.len() - margin, slice)
}
/// ignore N elements from this end and M elements from the other end of a slice
pub fn crop_both<'a, T>(&self, margin: usize, opposite: usize, slice: &'a [T]) -> &'a [T] {
self.crop(margin, self.opposite().crop(opposite, slice))
}
/// Pick this side from a pair of things
pub fn pick<T>(&self, pair: (T, T)) -> T {
match self {
Side::Left => pair.0,
Side::Right => pair.1
}
}
/// Make a pair with the first element on this side
pub fn pair<T>(&self, this: T, opposite: T) -> (T, T) {
match self {
Side::Left => (this, opposite),
Side::Right => (opposite, this)
}
}
}

35
src/utils/sorted_pairs.rs Normal file
View File

@@ -0,0 +1,35 @@
use std::ops::Add;
/// Combine two sorted iterators with their mapper function into a sorted iterator of pairs
pub struct SortedPairs<L, R, IL, IR, ML, MR, O> {
left: IL, right: IR,
left_map: ML, right_map: MR,
left_buf: Vec<(L, O)>, right_buf: Vec<(R, O)>
}
impl<L, R, IL, IR, ML, MR, O> SortedPairs<L, R, IL, IR, ML, MR, O>
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
ML: Fn(L) -> O, MR: Fn(R) -> O,
O: Ord + Add + Clone
{
pub fn new(left: IL, right: IR, left_map: ML, right_map: MR) -> Self {
Self {
left, right, left_map, right_map,
left_buf: Vec::new(),
right_buf: Vec::new()
}
}
}
impl<'a, L: 'a, R: 'a, IL: 'a, IR: 'a, ML: 'a, MR: 'a, O: 'a> Iterator
for &'a mut SortedPairs<L, R, IL, IR, ML, MR, O>
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
ML: Fn(L) -> O, MR: Fn(R) -> O,
O: Ord + Add + Clone,
{
type Item = (&'a L, &'a R);
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}

View File

@@ -1,45 +1,55 @@
use std::fmt::Debug;
/// Implement a FILO stack that lives on the regular call stack as a linked list.
/// Mainly useful to detect loops in recursive algorithms where the recursion isn't
/// deep enough to warrant a heap-allocated set
#[derive(Debug, Clone, Copy)]
pub struct Substack<'a, T> {
#[derive(Clone, Copy)]
pub struct Stackframe<'a, T> {
pub item: T,
pub prev: Option<&'a Self>
pub prev: Option<&'a Stackframe<'a, T>>
}
impl<'a, T> Substack<'a, T> {
#[allow(dead_code)]
pub fn item(&self) -> &T { &self.item }
#[allow(dead_code)]
pub fn prev(&self) -> Option<&'a Substack<'a, T>> { self.prev }
impl<'a, T: 'a> Stackframe<'a, T> {
pub fn new(item: T) -> Self {
Self {
item,
prev: None
}
}
pub fn push(&'a self, item: T) -> Self {
Self {
/// Get the item owned by this listlike, very fast O(1)
pub fn item(&self) -> &T { &self.item }
/// Get the next link in the list, very fast O(1)
pub fn prev(&self) -> Option<&'a Stackframe<T>> { self.prev }
/// Construct an iterator over the listlike, very fast O(1)
pub fn iter(&self) -> StackframeIterator<T> {
StackframeIterator { curr: Some(self) }
}
pub fn push(&self, item: T) -> Stackframe<'_, T> {
Stackframe {
item,
prev: Some(self)
}
}
pub fn iter(&'a self) -> SubstackIterator<'a, T> {
SubstackIterator { curr: Some(self) }
}
impl<'a, T> Debug for Stackframe<'a, T> where T: Debug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Substack")?;
f.debug_list().entries(self.iter()).finish()
}
}
pub struct SubstackIterator<'a, T> {
curr: Option<&'a Substack<'a, T>>
pub struct StackframeIterator<'a, T> {
curr: Option<&'a Stackframe<'a, T>>
}
impl<'a, T> Iterator for SubstackIterator<'a, T> {
impl<'a, T> Iterator for StackframeIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
let Substack{ item, prev } = self.curr?;
self.curr = *prev;
let curr = self.curr?;
let item = curr.item();
let prev = curr.prev();
self.curr = prev;
Some(item)
}
}
}

View File

@@ -0,0 +1,6 @@
#[macro_export]
macro_rules! unwrap_or_continue {
($m:expr) => {
{ if let Some(res) = ($m) {res} else {continue} }
}
}