//! This file implements the extected behaviours of grammars. // NOTE: We shall first start with a parser that works at the level of // characters. The purpose is to first experiment with the workings // and the performance of the algorithms, before optimising by using // regular expressions to classify inputs into tokens. In other // words, the current focus is not on the optimisations, whereas // scanners are for optimisations only, so to speak. /// The type of a terminal. /// /// For the time being this is a wrapper around a string, but in the /// future it may hold more information of scanners. pub struct Terminal { // If we want to use scanners, per chance add them as a new field // here. name: String, } impl Terminal { /// Create a terminal with the given name. #[inline] pub fn new(name: String) -> Self { Self { name } } /// Return the name of the terminal. #[inline] pub fn name(&self) -> &str { &self.name } } /// The type of a non-terminal. /// /// This is just a wrapper around a string. pub struct Nonterminal(String); impl Nonterminal { /// Return the name of the nonterminal. /// /// Just to improve readability. #[inline] pub fn name(&self) -> &str { &self.0 } } /// The type of a terminal or a non-terminal. /// /// Only an index is stored here. Actual data are stored in two other /// arrays. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, Ord, PartialOrd)] pub enum TNT { /// Terminal variant Ter(usize), /// Nonterminal variant Non(usize), }