use std::{cell::RefCell, fmt::Debug, hash::Hash};
use rustc_hash::FxHashMap;
use crate::{lexer::Cursor, Error, LexIt, ParserState};
pub struct Memo<P: Clone + Eq + Hash, T: Clone> {
map: RefCell<FxHashMap<P, (T, P)>>,
}
impl<P: Clone + Eq + Hash, T: Clone> Default for Memo<P, T> {
fn default() -> Self {
Self {
map: RefCell::new(FxHashMap::default()),
}
}
}
impl<P: Clone + Eq + Hash + Debug, T: Clone + Debug> Debug for Memo<P, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.map.borrow().fmt(f)
}
}
impl<P: Clone + Eq + Hash, T: Clone> Memo<P, T> {
pub fn get(&self, pos: &P) -> Option<(T, P)> {
self.map.borrow().get(pos).cloned()
}
pub fn insert(&self, pos: P, value: (T, P)) {
self.map.borrow_mut().insert(pos, value);
}
}
#[inline]
pub fn memorize<L: LexIt + Clone, T: Clone>(
state: &mut ParserState<L>,
memo: &Memo<Cursor, T>,
parser: impl FnOnce(&mut ParserState<L>) -> Result<T, Error>,
) -> Result<T, Error> {
let pos = state.cursor();
if let Some((value, end)) = memo.get(&pos) {
state.advance_to_cursor(end);
Ok(value.clone())
} else {
let value = parser(state)?;
let end = state.cursor();
memo.insert(pos, (value.clone(), end));
Ok(value)
}
}
#[inline]
pub fn left_rec<L: LexIt + Clone, T: Clone>(
state: &mut ParserState<L>,
memo: &Memo<Cursor, Option<T>>,
mut parser: impl FnMut(&mut ParserState<L>) -> Result<T, Error>,
) -> Result<T, Error> {
let pos = state.cursor();
if let Some((value, end)) = memo.get(&pos) {
state.advance_to_cursor(end);
if let Some(value) = value {
Ok(value.clone())
} else {
Err(state.error())
}
} else {
memo.insert(pos, (None, pos));
let mut last = (None, pos);
loop {
let mut fork = state.fork();
let Ok(value) = parser(&mut fork) else { break };
let end = fork.cursor();
if end <= last.1 {
break;
}
last = (Some(value), end);
memo.insert(pos, last.clone());
}
state.advance_to_cursor(last.1);
last.0.ok_or_else(|| state.error())
}
}