use std::any::TypeId;
use std::collections::BTreeMap;
use derivative::Derivative;
use crate::lex::{Map, TokenSrc};
use crate::Lexicon;
use super::{FirstSet, TerminalSet};
#[derive(Derivative, Debug)]
#[derivative(Default(new = "true", bound = ""))]
pub struct Jump<L: Lexicon> {
map: BTreeMap<TypeId, JumpTable<L>>,
}
impl<L: Lexicon> Jump<L> {
pub fn register(&mut self, t: TypeId, first: &FirstSet<L>, id: usize) {
let entry = self.map.entry(t).or_default();
first.add_to_jump_table(entry, id);
}
#[inline]
pub fn look_up(&self, t: &TypeId, token: Option<TokenSrc<'_, L>>) -> Option<usize> {
self.map.get(t).and_then(|entry| entry.look_up(token))
}
}
#[doc(hidden)]
pub struct DebugJump<'a, 'b, L: Lexicon>(pub &'a Jump<L>, pub &'b BTreeMap<TypeId, String>);
impl<L: Lexicon> std::fmt::Debug for DebugJump<'_, '_, L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut fmt = f.debug_struct("Jump");
for (ty, jump_table) in &self.0.map {
let name = self.1.get(ty).map(|x| x.as_str()).unwrap_or("<unknown>");
fmt.field(name, jump_table);
}
fmt.finish()
}
}
#[derive(Derivative)]
#[derivative(Default(bound = ""))]
pub struct JumpTable<L: Lexicon> {
epsilon: Option<usize>,
map: Map<L, LitJumpTable>,
}
pub type LitJumpTable = (Option<usize>, BTreeMap<&'static str, usize>);
impl<L: Lexicon> std::fmt::Debug for JumpTable<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut map = BTreeMap::<usize, TerminalSet<L>>::new();
if let Some(id) = self.epsilon {
map.entry(id).or_default().insert_e();
}
for (ty, (id, lit_map)) in self.map.iter_zip() {
if let Some(id) = id {
map.entry(*id).or_default().insert(ty, None);
}
for (lit, id) in lit_map {
map.entry(*id).or_default().insert(ty, Some(lit));
}
}
map.fmt(f)
}
}
impl<L: Lexicon> JumpTable<L> {
#[inline]
pub fn look_up(&self, token: Option<TokenSrc<'_, L>>) -> Option<usize> {
token
.map(|token| self.look_up_token(&token))
.unwrap_or(self.epsilon)
}
#[inline]
pub fn look_up_token(&self, token: &TokenSrc<L>) -> Option<usize> {
let entry = self.map.get(token.ty);
match entry.1.get(token.src).copied() {
Some(value) => Some(value),
None => entry.0,
}
}
#[inline]
pub fn register_epsilon(&mut self, value: usize) {
self.epsilon = Some(value);
}
#[inline]
pub fn register(&mut self, value: usize, ty: L) {
self.map.get_mut(ty).0 = Some(value);
}
#[inline]
pub fn register_lit(&mut self, value: usize, ty: L, lit: &'static str) {
self.map.get_mut(ty).1.insert(lit, value);
}
}