use crate::grammar::{Decorate, ProductionAttribute, SymbolAttribute};
use crate::{Symbol, Terminal};
use anyhow::{Result, anyhow};
use std::fmt::{Debug, Display, Error, Formatter};
use std::hash::Hash;
pub type Rhs = Vec<Symbol>;
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pr(pub Symbol, pub Rhs, pub ProductionAttribute);
impl Display for Pr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> {
write!(
f,
"{}: {};",
self.0,
self.1
.iter()
.fold(Vec::new(), |mut acc, s| {
acc.push(format!("{s}"));
acc
})
.join(" ")
)
}
}
impl Default for Pr {
fn default() -> Self {
Self(
Symbol::n(""),
Rhs::default(),
ProductionAttribute::default(),
)
}
}
impl Pr {
pub fn new(n: &str, r: Rhs) -> Self {
if !r.iter().all(Self::is_allowed_symbol) {
panic!("Unexpected symbol kind!");
}
Self(Symbol::n(n), r, ProductionAttribute::default())
}
pub(crate) fn with_attribute(mut self, attribute: ProductionAttribute) -> Self {
self.2 = attribute;
self
}
pub fn get_n(&self) -> String {
self.0.get_n().unwrap()
}
pub fn get_n_str(&self) -> &str {
self.0.get_n_ref().unwrap()
}
pub fn get_r(&self) -> &Rhs {
&self.1
}
pub fn take(self) -> (String, Rhs, ProductionAttribute) {
(self.0.get_n().unwrap(), self.1, self.2)
}
pub fn set_n(&mut self, n: String) {
self.0 = Symbol::N(n, SymbolAttribute::default(), None, None);
}
pub fn is_empty(&self) -> bool {
self.1.is_empty()
}
pub fn len(&self) -> usize {
self.1.len()
}
fn is_allowed_symbol(s: &Symbol) -> bool {
!(matches!(s, Symbol::T(Terminal::Eps)))
}
pub fn effective_len(&self) -> usize {
self.1.iter().fold(0, |count, s| {
if s.is_t() || s.is_n() {
count + 1
} else {
count
}
})
}
pub(crate) fn get_attribute(&self) -> ProductionAttribute {
self.2
}
pub fn format<R, S>(&self, scanner_state_resolver: &R, user_type_resolver: &S) -> Result<String>
where
R: Fn(&[usize]) -> String,
S: Fn(&str) -> Option<String>,
{
let mut s = String::new();
self.2
.decorate(&mut s, &self.0)
.map_err(|e| anyhow!("Decorate error!: {}", e))?;
Ok(format!(
"{}: {};",
s,
self.1
.iter()
.try_fold(Vec::new(), |mut acc: Vec<String>, s| {
s.format(scanner_state_resolver, user_type_resolver)
.map(|s| {
acc.push(s);
acc
})
})
.map(|v| v.join(" "))?
))
}
}