//! This file defines the behaviour of the Atomic languages, and //! provides a default implementation. //! //! Here I do not to substitute external packages' implementations in //! the future, so why define a trait for the atomic languages? //! Because this way I can easily substitute other implementations if //! I have better ideas in the future. use grammar::{Error as GrammarError, Grammar, TNT}; use nfa::{DOption, LabelType, Nfa}; use std::ops::Deref; /// The expected behaviours of an atomic language. pub trait Atom: Nfa> + Deref { /// Return the index of a node representing the derivative of the /// left-linear null closure of `nt` with respect to `t`. fn atom(&self, nt: usize, t: usize) -> Result, GrammarError>; /// Return the index of the empty state. fn empty(&self) -> usize; /// Tell whether a node is accepting. fn is_accepting(&self, node_id: usize) -> Result; } pub mod default; pub use default::DefaultAtom; #[cfg(test)] mod tests { use super::*; use grammar::test_grammar_helper::*; #[test] fn atom() -> Result<(), Box> { let grammar = new_notes_grammar()?; let atom = DefaultAtom::from_grammar(grammar)?; println!("atom = {atom}"); Ok(()) } }