use std::collections::BTreeSet;
use derivative::Derivative;
use crate::lex::TokenSrc;
use crate::syntax::{JumpTable, TerminalSet};
use crate::Lexicon;
#[derive(Debug, Derivative, PartialEq, Clone)]
#[derivative(Default(new = "true", bound = ""))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct FirstSet<L: Lexicon>(TerminalSet<L>);
impl<L: Lexicon> std::fmt::Display for FirstSet<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<L: Lexicon> From<TerminalSet<L>> for FirstSet<L> {
fn from(set: TerminalSet<L>) -> Self {
Self(set)
}
}
impl<L: Lexicon> FirstSet<L> {
#[inline]
pub fn one(ty: L, lit: Option<&'static str>) -> Self {
let mut set = Self::default();
set.insert(ty, lit);
set
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
#[inline]
pub fn insert_epsilon(&mut self) -> bool {
self.0.insert_e()
}
#[inline]
pub fn contains_epsilon(&self) -> bool {
self.0.contains_e()
}
#[inline]
pub fn insert(&mut self, ty: L, lit: Option<&'static str>) -> bool {
self.0.insert(ty, lit)
}
#[inline]
pub fn contains(&self, token: Option<TokenSrc<'_, L>>) -> bool {
self.0.contains(token)
}
#[inline]
pub fn union(&mut self, other: &Self) -> bool {
self.0.union(&other.0, true)
}
#[inline]
pub fn union_minus_epsilon(&mut self, other: &Self) -> bool {
self.0.union(&other.0, false)
}
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
self.0.intersects(&other.0, true)
}
#[inline]
pub fn intersects_minus_epsilon(&self, other: &Self) -> bool {
self.0.intersects(&other.0, false)
}
#[inline]
pub fn intersection_repr(&self, other: &Self) -> BTreeSet<String> {
self.0.intersection_repr(&other.0, true)
}
#[inline]
pub fn intersection_repr_minus_epsilon(&self, other: &Self) -> BTreeSet<String> {
self.0.intersection_repr(&other.0, false)
}
pub fn add_to_jump_table(&self, table: &mut JumpTable<L>, value: usize) {
if self.contains_epsilon() {
table.register_epsilon(value);
}
for (ty, set) in self.0.map.iter_zip() {
match set.iter() {
None => table.register(value, ty),
Some(lits) => {
for lit in lits {
table.register_lit(value, ty, lit);
}
}
}
}
}
#[inline]
pub(crate) fn as_terminal_set(&self) -> &TerminalSet<L> {
&self.0
}
}