//! This file implements a type of labels that could be used as the //! labels of a parse forest. use super::*; /// The actual label of a grammar label. #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum GrammarLabelType { /// A terminal or a non-terminal. TNT(TNT), /// A rule position. Rule(usize), } impl Display for GrammarLabelType { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::TNT(tnt) => write!(f, "{tnt}"), Self::Rule(pos) => write!(f, "R({pos})"), } } } // Some convenient conversions impl From for GrammarLabelType { #[inline] fn from(r: usize) -> Self { Self::Rule(r) } } impl From for GrammarLabelType { #[inline] fn from(tnt: TNT) -> Self { Self::TNT(tnt) } } impl GrammarLabelType { /// Return the name of this label with the help of the associated /// grammar. #[inline] pub fn name(&self, grammar: &Grammar) -> Result { match self { Self::TNT(tnt) => grammar.name_of_tnt(*tnt), Self::Rule(pos) => grammar.rule_pos_to_string(*pos), } } /// Return the contained TNT, if any. #[inline] pub fn tnt(&self) -> Option { match self { Self::TNT(tnt) => Some(*tnt), Self::Rule(_) => None, } } /// Return the contained rule position, if any. #[inline] pub fn rule(&self) -> Option { match self { Self::TNT(_) => None, Self::Rule(pos) => Some(*pos), } } } /// The label to be used in a forest. #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct GrammarLabel { /// The actual label. label: GrammarLabelType, /// The start in the input that this label correponds to. start: usize, /// The end in the input that this label correponds to. end: Option, } impl core::fmt::Display for GrammarLabel { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "{}, {}, {}", self.label, self.start, if let Some(end) = self.end { format!("{end}") } else { "ε".to_owned() } ) } } impl GrammarLabel { /// Construct a new label. #[inline] pub fn new(label: impl Into, start: usize) -> Self { let label = label.into(); let end = None; Self { label, start, end } } /// Construct a new label with an ending position. #[inline] pub fn new_closed(label: impl Into, start: usize, end: usize) -> Self { let label = label.into(); let end = Some(end); Self { label, start, end } } /// Return the end in the input. #[inline] pub fn end(&self) -> Option { self.end } /// Return the start in the input. #[inline] pub fn start(&self) -> usize { self.start } /// Return the actual label. #[inline] pub fn label(&self) -> GrammarLabelType { self.label } /// Update the end. #[inline] pub fn set_end(&mut self, end: usize) { self.end = Some(end); } /// Remove the ending boundary. #[inline] pub fn open_end(&mut self) { self.end = None; } /// Return a string description with the help of the associated /// grammar. pub fn to_string(&self, grammar: &Grammar) -> Result { // First calculate the length of the resulting string. let mut num = 16 + 6; num += self.label().name(grammar)?.len(); num += format!("{} ", self.start()).len(); if let Some(end) = self.end() { num += format!("to {end}").len(); } else { num += 7; } let num = num; let mut s = String::with_capacity(num); s.push_str("a node labelled "); s.push_str(&self.label().name(grammar)?); s.push_str(" from "); s.push_str(&format!("{} ", self.start())); if let Some(end) = self.end() { s.push_str(&format!("to {end}")); } else { s.push_str("onwards"); } Ok(s) } }