use std::fmt;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Kind {
Basic,
Incremental,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rule {
name: String,
node: Node,
kind: Kind,
}
impl Rule {
pub fn new(name: &str, node: Node) -> Rule {
Rule {
name: name.into(),
node,
kind: Kind::Basic,
}
}
pub fn incremental(name: &str, node: Node) -> Rule {
Rule {
name: name.into(),
node,
kind: Kind::Incremental,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn node(&self) -> &Node {
&self.node
}
pub fn kind(&self) -> Kind {
self.kind
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Node {
Alternation(Vec<Node>),
Concatenation(Vec<Node>),
Repetition(Repetition),
Rulename(String),
Group(Box<Node>),
Optional(Box<Node>),
String(String),
TerminalValues(TerminalValues),
Prose(String),
}
impl Node {
pub fn alternation(nodes: &[Node]) -> Node {
Node::Alternation(nodes.to_vec())
}
pub fn concatenation(nodes: &[Node]) -> Node {
Node::Concatenation(nodes.to_vec())
}
pub fn repeat(repeat: Repeat, node: Node) -> Node {
Node::Repetition(Repetition {
repeat,
node: Box::new(node),
})
}
pub fn repetition(repetition: Repetition) -> Node {
Node::Repetition(repetition)
}
pub fn rulename<S: AsRef<str>>(name: S) -> Node {
Node::Rulename(name.as_ref().to_string())
}
pub fn group(node: Node) -> Node {
Node::Group(Box::new(node))
}
pub fn optional(node: Node) -> Node {
Node::Optional(Box::new(node))
}
pub fn string<S: AsRef<str>>(string: S) -> Node {
Node::String(string.as_ref().to_string())
}
pub fn terminal_values(terminal_values: TerminalValues) -> Node {
Node::TerminalValues(terminal_values)
}
pub fn prose<S: AsRef<str>>(prose: S) -> Node {
Node::Prose(prose.as_ref().to_string())
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Repetition {
repeat: Repeat,
node: Box<Node>,
}
impl Repetition {
pub fn new(repeat: Repeat, node: Node) -> Self {
Self {
repeat,
node: Box::new(node),
}
}
pub fn repeat(&self) -> &Repeat {
&self.repeat
}
pub fn node(&self) -> &Node {
&self.node
}
}
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct Repeat {
min: Option<usize>,
max: Option<usize>,
}
impl Repeat {
pub fn unbounded() -> Self {
Self {
min: None,
max: None,
}
}
pub fn with(min: Option<usize>, max: Option<usize>) -> Self {
Self { min, max }
}
pub fn min(&self) -> Option<usize> {
self.min
}
pub fn max(&self) -> Option<usize> {
self.max
}
pub fn min_max(&self) -> (Option<usize>, Option<usize>) {
(self.min, self.max)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TerminalValues {
Range(u32, u32),
Concatenation(Vec<u32>),
}
impl TerminalValues {
pub fn range(from: u32, to: u32) -> TerminalValues {
TerminalValues::Range(from, to)
}
pub fn sequence(alts: &[u32]) -> TerminalValues {
TerminalValues::Concatenation(alts.to_owned())
}
}
impl fmt::Display for Rule {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)?;
match self.kind {
Kind::Basic => write!(f, " = ")?,
Kind::Incremental => write!(f, " =/ ")?,
}
write!(f, "{}", self.node)
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Node::Alternation(nodes) => {
if let Some((last, elements)) = nodes.split_last() {
for item in elements {
write!(f, "{} / ", item)?;
}
write!(f, "{}", last)?;
}
}
Node::Concatenation(nodes) => {
if let Some((last, elements)) = nodes.split_last() {
for item in elements {
write!(f, "{} ", item)?;
}
write!(f, "{}", last)?;
}
}
Node::Repetition(Repetition { repeat, node }) => {
if let Some(min) = repeat.min {
write!(f, "{}", min)?;
}
write!(f, "*")?;
if let Some(max) = repeat.max {
write!(f, "{}", max)?;
}
write!(f, "{}", node)?;
}
Node::Rulename(name) => {
write!(f, "{}", name)?;
}
Node::Group(node) => {
write!(f, "({})", node)?;
}
Node::Optional(node) => {
write!(f, "[{}]", node)?;
}
Node::String(str) => {
write!(f, "\"{}\"", str)?;
}
Node::TerminalValues(range) => {
write!(f, "%x")?;
match range {
TerminalValues::Concatenation(allowed) => {
if let Some((last, elements)) = allowed.split_last() {
for item in elements {
write!(f, "{:02X}.", item)?;
}
write!(f, "{:02X}", last)?;
}
}
TerminalValues::Range(from, to) => {
write!(f, "{:02X}-{:02X}", from, to)?;
}
}
}
Node::Prose(str) => {
write!(f, "<{}>", str)?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_rule() {
let test = Rule::new("rule", Node::rulename("A"));
let expected = "rule = A";
let got = test.to_string();
assert_eq!(expected, got);
let test = Rule::incremental("rule", Node::rulename("A"));
let expected = "rule =/ A";
let got = test.to_string();
assert_eq!(expected, got);
}
#[test]
fn test_display_prose() {
let rule = Rule::new("rule", Node::prose("test"));
assert_eq!("rule = <test>", rule.to_string());
}
#[test]
fn test_impl_trait() {
trait Foo {
fn foo(&self);
}
impl Foo for Rule {
fn foo(&self) {
println!("{}", self.name);
}
}
}
}