1use crate::builder::Builder;
18use crate::builder::Regex;
19
20#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
21enum Level {
22 None,
23 Binary,
24 Unary,
25 Atom,
26}
27
28#[derive(Copy, Clone, Eq, PartialEq)]
29enum Context {
30 Inner,
31 Left,
32}
33
34impl<B: Builder> std::fmt::Display for Regex<B>
35where
36 B::Symbol: std::fmt::Display,
37{
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 self.fmt(f, Context::Inner, Level::None)
40 }
41}
42
43impl<B: Builder> Regex<B>
44where
45 B::Symbol: std::fmt::Display,
46{
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: Context, level: Level) -> std::fmt::Result {
48 match ctx {
49 Context::Inner | Context::Left if self.level() <= level => {
50 write!(f, "(")?;
51 }
52 _ => {}
53 }
54 match self {
55 Regex::EmptySet => write!(f, "∅")?,
56 Regex::EmptyString => write!(f, "ε")?,
57 Regex::Symbol(value) => write!(f, "{}", value)?,
58 Regex::Concat(left, right) => {
59 self.fmt_left(f, left, level)?;
60 write!(f, " ")?;
61 self.fmt_right_or_inner(f, right)?;
62 }
63 Regex::Closure(inner) => {
64 self.fmt_right_or_inner(f, inner)?;
65 write!(f, "*")?;
66 }
67 Regex::Or(left, right) => {
68 self.fmt_left(f, left, level)?;
69 write!(f, " | ")?;
70 self.fmt_right_or_inner(f, right)?;
71 }
72 Regex::And(left, right) => {
73 self.fmt_left(f, left, level)?;
74 write!(f, " & ")?;
75 self.fmt_right_or_inner(f, right)?;
76 }
77 Regex::Complement(inner) => {
78 write!(f, "¬")?;
79 self.fmt_right_or_inner(f, inner)?;
80 }
81 };
82 match ctx {
83 Context::Inner if self.level() <= level => {
84 write!(f, ")")?;
85 }
86 _ => {}
87 }
88 Ok(())
89 }
90
91 fn fmt_left(
92 &self,
93 f: &mut std::fmt::Formatter<'_>,
94 left: &Regex<B>,
95 outer_level: Level,
96 ) -> std::fmt::Result {
97 match (self, left) {
98 (Self::Concat(_, _), Self::Concat(_, _))
99 | (Self::Or(_, _), Self::Or(_, _))
100 | (Self::And(_, _), Self::And(_, _)) => left.fmt(f, Context::Left, outer_level),
101 _ => left.fmt(f, Context::Inner, self.level()),
102 }
103 }
104
105 fn fmt_right_or_inner(
106 &self,
107 f: &mut std::fmt::Formatter<'_>,
108 right_or_inner: &Regex<B>,
109 ) -> std::fmt::Result {
110 right_or_inner.fmt(f, Context::Inner, self.level())
111 }
112}
113
114impl<B: Builder> Regex<B> {
115 fn level(&self) -> Level {
116 match self {
117 Regex::EmptySet | Regex::EmptyString | Regex::Symbol(_) => Level::Atom,
118 Regex::Concat(_, _) | Regex::Or(_, _) | Regex::And(_, _) => Level::Binary,
119 Regex::Closure(_) | Regex::Complement(_) => Level::Unary,
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use crate::builder::Pure;
127 use crate::builder::Regex;
128 use crate::ops::*;
129
130 #[test]
131 fn test_display() {
132 let tests: Vec<(&str, Regex<Pure<usize>>)> = vec![
133 ("∅", ().r()),
134 ("¬∅", !().r()),
135 ("¬(11*)", !11.s().c()),
136 ("ε | 11*", [].r() | 11.s().c()),
137 ("¬∅ & (11 7)", !().r() & [11.s(), 7.s()].r()),
138 ("1 & 2 & 4", 1.s() & 2.s() & 4.s()),
139 ("1 & (2 & 4)", 1.s() & (2.s() & 4.s())),
140 ("(1 & 2) | 4", (1.s() & 2.s()) | 4.s()),
141 ("¬(1 2)", !(1.s() + 2.s())),
142 ];
143 for (expected, r) in tests {
144 assert_eq!(expected, r.to_string());
145 }
146 }
147}