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 {
Alternatives(Vec<Node>),
Concatenation(Vec<Node>),
Repetition {
repeat: Repeat,
node: Box<Node>,
},
Rulename(String),
Group(Box<Node>),
Optional(Box<Node>),
String(StringLiteral),
TerminalValues(TerminalValues),
Prose(String),
}
impl Node {
pub fn alternatives(nodes: &[Node]) -> Node {
Node::Alternatives(nodes.to_vec())
}
pub fn concatenation(nodes: &[Node]) -> Node {
Node::Concatenation(nodes.to_vec())
}
pub fn repetition(repeat: Repeat, node: Node) -> Node {
Node::Repetition {
repeat,
node: Box::new(node),
}
}
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, case_sensitive: bool) -> Node {
Node::String(StringLiteral::new(
string.as_ref().to_owned(),
case_sensitive,
))
}
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 StringLiteral {
value: String,
case_sensitive: bool,
}
impl StringLiteral {
pub fn new(string: String, case_sensitive: bool) -> Self {
Self {
value: string,
case_sensitive,
}
}
pub fn case_insensitive(string: String) -> Self {
Self {
value: string,
case_sensitive: false,
}
}
pub fn case_sensitive(string: String) -> Self {
Self {
value: string,
case_sensitive: true,
}
}
pub fn is_case_sensitive(&self) -> bool {
self.case_sensitive
}
pub fn set_case_sensitive(&mut self, case_sensitive: bool) {
self.case_sensitive = case_sensitive
}
pub fn value(&self) -> &str {
&self.value
}
pub fn as_str(&self) -> &str {
&self.value
}
pub fn value_mut(&mut self) -> &mut String {
&mut self.value
}
pub fn set_value(&mut self, value: String) {
self.value = value
}
pub fn into_value(self) -> String {
self.value
}
pub fn into_parts(self) -> (String, bool) {
(self.value, self.case_sensitive)
}
}
impl From<String> for StringLiteral {
fn from(s: String) -> Self {
Self::case_insensitive(s)
}
}
impl fmt::Display for StringLiteral {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.case_sensitive {
write!(f, "%s\"{}\"", self.value)
} else {
write!(f, "\"{}\"", self.value)
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Repeat {
Specific(usize),
Variable {
min: Option<usize>,
max: Option<usize>,
},
}
impl Repeat {
pub fn unbounded() -> Self {
Self::Variable {
min: None,
max: None,
}
}
pub fn specific(n: usize) -> Self {
Self::Specific(n)
}
pub fn variable(min: Option<usize>, max: Option<usize>) -> Self {
Self::Variable { min, max }
}
pub fn min(&self) -> Option<usize> {
match *self {
Self::Specific(n) => Some(n),
Self::Variable { min, .. } => min,
}
}
pub fn max(&self) -> Option<usize> {
match *self {
Self::Specific(n) => Some(n),
Self::Variable { max, .. } => 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::Alternatives(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 { repeat, node } => {
match *repeat {
Repeat::Specific(n) => {
write!(f, "{}", n)?;
}
Repeat::Variable { min, max } => {
if let Some(min) = min {
write!(f, "{}", min)?;
}
write!(f, "*")?;
if let Some(max) = 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) => {
str.fmt(f)?;
}
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);
}
}
}
}