1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
use crate::grammar::{Decorate, ProductionAttribute, SymbolAttribute};
use crate::{Symbol, Terminal};
use anyhow::{anyhow, Result};
use std::fmt::{Debug, Display, Error, Formatter};
use std::hash::Hash;
// ---------------------------------------------------
// Part of the Public API
// *Changes will affect crate's version according to semver*
// ---------------------------------------------------
///
/// Right-hand side of a production.
/// A collection of [Symbol]s
///
pub type Rhs = Vec<Symbol>;
// ---------------------------------------------------
// Part of the Public API
// *Changes will affect crate's version according to semver*
// ---------------------------------------------------
///
/// Production type
///
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pr(pub Symbol, pub Rhs, pub ProductionAttribute);
impl Display for Pr {
///
/// The output format for a production roughly follows the Yacc format.
///
/// ```
/// use parol::{Pr, Symbol, SymbolAttribute, Terminal, TerminalKind};
///
/// macro_rules! terminal {
/// ($term:literal) => {Symbol::T(Terminal::Trm($term.to_string(), TerminalKind::Legacy,
/// vec![0], SymbolAttribute::None, None))};
/// }
///
/// let pr = Pr::new("S", vec![]);
/// assert_eq!("S: ;", format!("{}", pr));
/// let pr = Pr::new("S", vec![Symbol::n("N"), Symbol::n("L")]);
/// assert_eq!("S: N L;", format!("{}", pr));
/// let pr = Pr::new("S", vec![Symbol::n("I"), Symbol::n("L")]);
/// assert_eq!("S: I L;", format!("{}", pr));
/// let pr = Pr::new("S", vec![terminal!(","), Symbol::n("N")]);
/// assert_eq!(r#"S: "," N;"#, format!("{}", pr));
/// let pr = Pr::new("S", vec![terminal!("d")]);
/// assert_eq!(r#"S: "d";"#, format!("{}", pr));
/// let pr = Pr::new("S", vec![terminal!(r#"[0-9]"#), terminal!("e")]);
/// assert_eq!(r#"S: "[0-9]" "e";"#, format!("{}", 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 {
/// Creates a new item from a non-terminal name and a [Rhs]
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
}
/// Returns a clone of the non-terminal
pub fn get_n(&self) -> String {
self.0.get_n().unwrap()
}
/// Returns a reference of the non-terminal
pub fn get_n_str(&self) -> &str {
self.0.get_n_ref().unwrap()
}
/// Returns a reference of the ride-hand side
pub fn get_r(&self) -> &Rhs {
&self.1
}
/// Extracts the members of self while consuming self
pub fn take(self) -> (String, Rhs, ProductionAttribute) {
(self.0.get_n().unwrap(), self.1, self.2)
}
/// Sets the non-terminal
pub fn set_n(&mut self, n: String) {
self.0 = Symbol::N(n, SymbolAttribute::default(), None);
}
/// Checks if [Rhs] is empty
pub fn is_empty(&self) -> bool {
self.1.is_empty()
}
/// Returns the length of [Rhs]
pub fn len(&self) -> usize {
self.1.len()
}
fn is_allowed_symbol(s: &Symbol) -> bool {
!(matches!(s, Symbol::T(Terminal::Eps)))
}
/// Returns the length of [Rhs] while counting only parser relevant symbols
pub fn effective_len(&self) -> usize {
self.1.iter().fold(0, |count, s| {
if s.is_t() || s.is_n() {
count + 1
} else {
count
}
})
}
/// Returns the ProductionAttribute of self
pub(crate) fn get_attribute(&self) -> ProductionAttribute {
self.2
}
/// Formats self with the help of a scanner state resolver
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(" "))?
))
}
}