1use super::formula::{Tree, Zipper};
7use crate::parser::Match;
8#[cfg(feature = "python")]
9use pyo3::prelude::*;
10use std::fmt::Display;
11use std::hash::Hash;
12use std::ops::{Deref, DerefMut};
13
14pub trait Symbolic:
16 Copy + PartialEq + Eq + PartialOrd + Ord + Clone + Display + Hash + Default
17{
18}
19
20#[derive(Copy, PartialEq, Hash, Eq, PartialOrd, Ord, Clone, Debug)]
21pub enum Symbol<B, U, A>
22where
23 B: Symbolic,
24 U: Symbolic,
25 A: Symbolic,
26{
27 Binary(B),
28 Unary(U),
29 Atom(A),
30 Left,
31 Right, }
33
34impl<B, U, A> Display for Symbol<B, U, A>
35where
36 B: Symbolic,
37 U: Symbolic,
38 A: Symbolic,
39{
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 match self {
42 Symbol::Binary(x) => {
43 write!(f, "{}", x.to_string())
44 }
45 Symbol::Unary(x) => {
46 write!(f, "{}", x.to_string())
47 }
48 Symbol::Atom(x) => {
49 write!(f, "{}", x.to_string())
50 }
51 Symbol::Left => {
52 write!(f, "(")
53 }
54 Symbol::Right => {
55 write!(f, ")")
56 }
57 }
58 }
59}
60
61impl<B, U, A> Symbol<B, U, A>
66where
67 B: Symbolic,
68 U: Symbolic,
69 A: Symbolic,
70{
71 pub fn from_tree(t: &Tree<B, U, A>) -> Self {
72 match t {
73 Tree::Binary {
74 conn,
75 left: _,
76 right: _,
77 } => Symbol::Binary(*conn),
78 Tree::Unary { conn, next: _ } => Symbol::Unary(*conn),
79 Tree::Atom(a) => Symbol::Atom(*a),
80 }
81 }
82
83 pub fn from_zipper(z: &Zipper<B, U, A>) -> Option<Self> {
85 match z {
86 Zipper::Top => None,
87 Zipper::Right { bin, .. } => Some(Symbol::Binary(*bin)),
88 Zipper::Left { bin, .. } => Some(Symbol::Binary(*bin)),
89 Zipper::Up { un, .. } => Some(Symbol::Unary(*un)),
90 }
91 }
92}
93
94impl<B, U, A> Match for Symbol<B, U, A>
95where
96 B: Symbolic + Match,
97 U: Symbolic + Match,
98 A: Symbolic + Match,
99{
100 fn match_str(s: &str) -> Option<Self> {
101 if s == "(" {
102 Some(Symbol::Left)
103 } else if s == ")" {
104 Some(Symbol::Right)
105 } else if let Some(b) = B::match_str(s) {
106 Some(Symbol::Binary(b))
107 } else if let Some(u) = U::match_str(s) {
108 Some(Symbol::Unary(u))
109 } else if let Some(a) = A::match_str(s) {
110 Some(Symbol::Atom(a))
111 } else {
112 None
113 }
114 }
115
116 fn get_matches(&self) -> Vec<String> {
117 match self {
118 Symbol::Binary(s) => s.get_matches(),
119 Symbol::Unary(s) => s.get_matches(),
120 Symbol::Atom(s) => s.get_matches(),
121 Symbol::Left => vec!["(".to_string()],
122 Symbol::Right => vec![")".to_string()],
123 }
124 }
125}
126
127pub static ATOMS: [&'static str; 52] = [
128 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
129 "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
130 "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
131];
132
133#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug, Default)]
140#[cfg_attr(feature = "python", pyclass)]
141pub struct Atom(pub usize);
142
143impl Deref for Atom {
144 type Target = usize;
145
146 fn deref(&self) -> &Self::Target {
147 &self.0
148 }
149}
150
151impl DerefMut for Atom {
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 &mut self.0
154 }
155}
156
157impl Display for Atom {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 if **self < ATOMS.len() {
160 write!(f, "{}", ATOMS[**self])
161 } else {
162 write!(f, "{}", self.to_string())
163 }
164 }
165}
166
167impl Symbolic for Atom {}
168
169impl Match for Atom {
170 fn match_str(s: &str) -> Option<Self> {
171 if let Some(i) = ATOMS.iter().position(|val| &s == val) {
172 Some(Atom(i))
173 } else if let Ok(i) = s.parse::<usize>() {
174 Some(Atom(i))
175 } else {
176 None
177 }
178 }
179
180 fn get_matches(&self) -> Vec<String> {
181 match self.0 {
182 ..=51 => vec![self.0.to_string(), ATOMS[self.0].to_string()],
183 _ => vec![self.0.to_string()],
184 }
185 }
186}