eta_core/
lib.rs

1/* written by hand - by Hans - with love */
2/* BSD-3 License */
3
4#![no_std]
5
6extern crate alloc;
7extern crate core;
8
9use core::{fmt, mem};
10use alloc::{boxed::Box, format, string::String};
11use hashbrown::HashMap;
12
13#[deny(clippy::unwrap_used)]
14#[deny(clippy::expect_used)]
15#[deny(clippy::panic)]
16#[allow(clippy::empty_line_after_outer_attr)]
17
18/******************************************************************/
19/* remember to always give back what you dont use */
20
21pub type ID = usize;
22pub type ZtaFn = for<'a> fn(inp: &'a mut Kind) -> Result<Kind, &'a mut Kind>;
23
24#[derive(Clone)]
25pub enum Kind {
26    Alp {id: ID},
27    Zta {sid: Option<ID>, hid: ID, fnc: ZtaFn},
28    Pir {l: Box<Kind>, r: Box<Kind>}
29}
30impl From<ID> for Kind {
31    fn from(val: ID) -> Self {
32        Self::Alp {id: val}
33    }
34}
35impl TryFrom<(ZtaFn, ID)> for Kind {
36    type Error = ();
37    fn try_from(val: (ZtaFn, ID)) -> Result<Self, Self::Error> {
38        match val.1.checked_add(2) {
39            Some(hid) => Ok(Self::Zta {sid: None, hid, fnc: val.0}),
40            None => Err(()),
41        }
42    }
43}
44impl From<(Kind, Kind)> for Kind {
45    fn from(val: (Kind, Kind)) -> Self {
46        Self::Pir {l: Box::new(val.0), r: Box::new(val.1)}
47    }
48}
49impl fmt::Debug for Kind {
50    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51        match self {
52            Kind::Alp { id } => write!(f, "I:{id}"),
53            Kind::Zta { sid, hid, ..} => match sid {
54                Some(id) => write!(f, "Z:{hid}:{id}"),
55                None => write!(f, "Z:{hid}"),
56            },
57            Kind::Pir { l, r } => write!(f, "({l:?} {r:?})"),
58        }
59    }
60}
61
62/******************************************************************/
63/* remember to always give back what you dont use */
64
65struct MapIDK {
66    map: HashMap<ID, Option<Kind>>
67}
68impl MapIDK {
69    fn new() -> Self { Self {map: HashMap::new()} }
70    fn get(&mut self, id: ID) -> Option<Kind> {
71        self.map.get_mut(&id).and_then(|k| k.take())
72    }
73    fn set(&mut self, id: ID, v: Kind) {
74        self.map.insert(id, Some(v));
75    }
76}
77
78/******************************************************************/
79/* remember to always give back what you dont use */
80
81struct Mtc {
82    map: MapIDK
83}
84impl Mtc {
85    fn new() -> Self { Self { map: MapIDK::new() } }
86    fn alp(&mut self, x: &mut Kind, n: &mut Kind) -> bool {
87        match n {
88            Kind::Alp { id } => match self.map.get(*id) {
89                Some(mut ol) => {
90                    if self.mtc(x, &mut ol) {
91                        self.map.set(*id, ol); /* re-insert */
92                        return true
93                    }
94                    /* ol stays removed */
95                    false
96                },
97                None => {
98                    let mut k = x.clone();
99                    if let Kind::Zta { sid, ..} = &mut k {
100                        *sid = Some(*id);
101                    }
102
103                    self.map.set(*id, k);
104                    true
105                },
106            },
107            _ => false
108        }
109    }
110    fn zta(&mut self, x: &mut Kind, n: &mut Kind) -> bool {
111        match x {
112            Kind::Pir { l: mz, r: inp } => match mz.as_mut() {
113                Kind::Zta {fnc, ..}
114                => match fnc(inp) {
115                    Ok(xr) => {
116                        *x = xr;
117                        self.mtc(x, n)
118                    },
119                    Err(_) => false,
120                },
121                _ => false
122            },
123            _ => false
124        }
125    }
126    fn rec(&mut self, x: &mut Kind, n: &mut Kind) -> bool {
127        match (x, n) {
128            (
129                Kind::Zta {hid: xid, ..},
130                Kind::Zta {hid: nid, ..}
131            ) => {xid == nid},
132            (
133                Kind::Pir {l: xl, r: xr},
134                Kind::Pir {l: nl, r: nr}
135            ) => {
136                if !self.mtc(xl, nl) {return false}
137                self.mtc(xr, nr)
138            },
139            _ => false
140        }
141    }
142    fn mtc(&mut self, x: &mut Kind, n: &mut Kind) -> bool {
143        if self.alp(x, n) {return true}
144        if self.rec(x, n) {return true}
145        self.zta(x, n)
146    }
147    fn ins(&mut self, b: &mut Kind) {
148        match b {
149            Kind::Alp {id} => match self.map.get(*id) {
150                Some(k) => {
151                    self.map.set(*id, k.clone()); /* replace for next need */
152                    *b = k
153                },
154                None => (),
155            },
156            Kind::Pir {l, r} => {
157                self.ins(l);
158                self.ins(r)
159            },
160            _ => ()
161        }
162    }
163}
164
165/******************************************************************/
166/* remember to always give back what you dont use */
167
168pub fn eta<'a>(inp: &'a mut Kind) -> Result<Kind, &'a mut Kind> {
169    let (n, b, x) = match inp {
170        Kind::Pir {l: nb, r: x} => {
171            match nb.as_mut() {
172                Kind::Pir {l: n, r: b} => (n, b, x),
173                _ => return Err(inp)
174            }
175        },
176        _ => return Err(inp)
177    };
178
179    let mut mt = Mtc::new();
180    if !mt.mtc(x, n) {return Err(inp)}
181    mt.ins(b);
182
183    /* funny trick for performance */
184    let bb = mem::replace(b, Box::new(new_omi_kind()));
185
186    Ok(*bb)
187}
188
189/* omicron */
190pub fn omi<'a>(inp: &'a mut Kind) -> Result<Kind, &'a mut Kind> { Err(inp) }
191
192pub fn new_eta_kind() -> Kind { Kind::Zta {sid:None, hid:1, fnc:eta} }
193pub fn new_omi_kind() -> Kind { Kind::Zta {sid:None, hid:0, fnc:omi} }
194
195/******************************************************************/
196/* remember to always give back what you dont use */
197
198pub fn lore(end: Kind) -> Kind {
199    Kind::from((
200        Kind::from((new_omi_kind(), new_omi_kind())),
201        Kind::from((new_eta_kind(), end))
202    ))
203}
204
205pub fn lore_end() -> Kind {
206    Kind::from((
207        new_eta_kind(),
208        Kind::from((
209            Kind::from((new_omi_kind(), new_omi_kind())),
210            new_omi_kind()
211        ))
212    ))
213}
214
215/******************************************************************/
216/* remember to always give back what you dont use */
217
218pub struct Dict {
219    map: HashMap<String, ID>,
220    rev: HashMap<ID, String>,
221    i: ID
222}
223impl Dict {
224    pub fn new() -> Self { Self {map: HashMap::new(), rev: HashMap::new(), i: 0} }
225    pub fn get(&mut self, name: String) -> ID {
226        match self.map.get(&name) {
227            Some(id) => *id,
228            None => {
229                self.map.insert(name.clone(), self.i);
230                self.rev.insert(self.i, name);
231                let ret = self.i;
232                self.i += 1;
233                ret
234            },
235        }
236    }
237    /* expensive (kinda) */
238    pub fn get_name(&self, id: ID) -> Option<String> {
239        self.rev.get(&id).cloned()
240    }
241}
242
243pub fn pretty_string(root: &Kind, dict: &Dict) -> String {
244    match root {
245        Kind::Alp { id } => match dict.get_name(*id) {
246            Some(name) => name,
247            None => format!("#{root:?}"),
248        },
249        Kind::Zta { sid, .. } => match *sid {
250            None => format!("#{root:?}"),
251            Some(id) => match dict.get_name(id) {
252                Some(name) => name,
253                None => format!("#{root:?}"),
254            },
255        }
256        Kind::Pir { l, r } => format!(
257            "({} {})",
258            pretty_string(l, dict), pretty_string(r, dict)
259        )
260    }
261}