eta_core/
theory.rs

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