From 698e05081aa3dc7b2f858c9d7bb39738d07c9a67 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 31 Jan 2024 00:24:18 -0800 Subject: [PATCH] starting ebnf representation --- src/lib.rs | 1 + src/representation.rs | 62 ++++++++++++++++++++++++++++++++++++++++--- src/util.rs | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/util.rs diff --git a/src/lib.rs b/src/lib.rs index 7aba179..2ff5434 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ mod parser; mod primitives; mod representation; mod sequence; +mod util; #[cfg(test)] mod test; diff --git a/src/representation.rs b/src/representation.rs index 8516a0f..acd33e7 100644 --- a/src/representation.rs +++ b/src/representation.rs @@ -1,12 +1,66 @@ +use std::fmt; + +use crate::util::intersperse_option; + #[derive(Debug)] -pub struct Representation {} +pub struct Representation { + production_output: EBNF, +} impl Representation { - pub fn show(&self) { - println!("Not done"); + pub fn show(&self) -> String { + self.production_output.to_string() } pub fn new() -> Self { - Self {} + Self { + production_output: EBNF::None, + } + } + + pub fn with_production(production_output: EBNF) -> Self { + Self { production_output } + } +} + +#[derive(Debug)] +pub enum EBNF { + None, + CharTerminal(char), + Alternation(Vec), +} + +impl fmt::Display for EBNF { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EBNF::None => write!(f, "none"), + EBNF::CharTerminal(ch) => write!(f, "'{ch}'"), + EBNF::Alternation(items) => { + for item in intersperse_option(items.iter()) { + match item { + None => write!(f, " | ")?, + Some(item) => write!(f, "{item}")?, + } + } + write!(f, "") + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ebnf_print() { + let example = EBNF::Alternation(vec![ + EBNF::CharTerminal('f'), + EBNF::CharTerminal('a'), + EBNF::CharTerminal('k'), + EBNF::CharTerminal('e'), + ]); + + assert_eq!(example.to_string(), "'f' | 'a' | 'k' | 'e'"); } } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..53897e7 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,46 @@ +use std::iter::Peekable; + +pub(crate) fn intersperse_option(iterator: I) -> impl Iterator> +where + I::Item: Clone, +{ + intersperse(iterator.map(Some), None) +} + +pub(crate) fn intersperse(iterator: I, separator: I::Item) -> Intersperse +where + I::Item: Clone, +{ + Intersperse { + inner: iterator.peekable(), + separator, + needs_sep: false, + } +} + +pub struct Intersperse +where + I: Iterator, +{ + inner: Peekable, + separator: I::Item, + needs_sep: bool, +} + +impl Iterator for Intersperse +where + I: Iterator, + I::Item: Clone, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + if self.needs_sep && self.inner.peek().is_some() { + self.needs_sep = false; + Some(self.separator.clone()) + } else { + self.needs_sep = true; + self.inner.next() + } + } +}