eta_core/
human.rs

1
2
3use alloc::{borrow::ToOwned, format, string::String};
4use core::str;
5use hashbrown::HashMap;
6
7use crate::theory::*;
8
9pub struct Dict {
10    map: HashMap<String, ID>,
11    rev: HashMap<ID, String>,
12    i: ID
13}
14impl Dict {
15    pub fn new() -> Self { Self {map: HashMap::new(), rev: HashMap::new(), i: 0} }
16    pub fn get(&mut self, name: &str) -> Option<ID> {
17        match self.map.get(name) {
18            Some(id) => Some(*id),
19            None => {
20                let owd = name.to_owned();
21                self.map.insert(owd.clone(), self.i);
22                self.rev.insert(self.i, owd);
23
24                let ret = self.i;
25                match self.i.checked_add(1) {
26                    Some(ni) => {
27                        self.i = ni;
28                        Some(ret)
29                    },
30                    None => None,
31                }
32            },
33        }
34    }
35    /* expensive (kinda) */
36    pub fn get_name(&self, id: ID) -> Option<String> {
37        self.rev.get(&id).cloned()
38    }
39}
40
41/* parse errors */
42#[derive(Clone, Debug)]
43pub struct PrsErr {
44    pub msg: &'static str,
45    pub byte: usize,
46}
47
48/* parser: binary s-expressions (s-pairs) */
49struct Prsr<'a> {
50    s: &'a [u8],
51    i: usize,
52}
53impl<'a> Prsr<'a> {
54    fn new(input: &'a str) -> Self {
55        Self { s: input.as_bytes(), i: 0 }
56    }
57
58    fn eof(&self) -> bool { self.i >= self.s.len() }
59    fn peek(&self) -> Option<u8> { self.s.get(self.i).copied() }
60
61    fn bump(&mut self) -> Option<u8> {
62        let b = self.peek()?;
63        self.i += 1;
64        Some(b)
65    }
66
67    fn skip_ws(&mut self) {
68        while let Some(b) = self.peek() {
69            match b {
70                b' ' | b'\t' | b'\r' | b'\n' => self.i += 1,
71                b';' => {
72                    /* comment to end-of-line */
73                    self.i += 1;
74                    while let Some(c) = self.peek() {
75                        self.i += 1;
76                        if c == b'\n' { break; }
77                    }
78                }
79                _ => break,
80            }
81        }
82    }
83
84    fn expect(&mut self, want: u8) -> Result<(), PrsErr> {
85        self.skip_ws();
86        match self.bump() {
87            Some(got) if got == want => Ok(()),
88            _ => Err(PrsErr {msg: "unexpected character", byte: self.i}),
89        }
90    }
91
92    fn is_sym_char(b: u8) -> bool {
93        matches!(
94            b,
95            b'a'..=b'z' |
96            b'A'..=b'Z' |
97            b'0'..=b'9' |
98            b'_' | b'-' | b'+' | b'*' | b'/' | b'=' | b'<' | b'>' | b'!' | b'?' | b'.'
99        )
100    }
101
102    fn parse_atom(&mut self) -> Result<&str, PrsErr> {
103        self.skip_ws();
104        let start = self.i;
105
106        while let Some(b) = self.peek() {
107            if Self::is_sym_char(b) { self.i += 1; } else { break; }
108        }
109
110        if self.i == start {
111            return Err(PrsErr {msg: "expected atom", byte: self.i});
112        }
113
114        match str::from_utf8(&self.s[start..self.i]) {
115            Ok(sym) => Ok(sym),
116            Err(_) => Err(PrsErr {msg: "invalid utf-8 in symbol", byte: start }),
117        }
118    }
119
120    fn parse_expr(&mut self, dict: &mut Dict) -> Result<Kind, PrsErr> {
121        self.skip_ws();
122        match self.peek() {
123            Some(b'(') => self.parse_blist(dict),
124            Some(_) => {
125                let sym = self.parse_atom()?;
126                match dict.get(sym) {
127                    Some(gsy) => Ok(Kind::from(gsy)),
128                    None => Err(PrsErr {msg: "internal namespace full", byte: self.i}),
129                }
130            }
131            None => Err(PrsErr {msg: "unexpected end of input", byte: self.i}),
132        }
133    }
134
135    // '(' expr expr ')', exactly two.
136    fn parse_blist(&mut self, dict: &mut Dict) -> Result<Kind, PrsErr> {
137        self.expect(b'(')?;
138        let l = self.parse_expr(dict)?;
139        let r = self.parse_expr(dict)?;
140        self.skip_ws();
141
142        match self.peek() {
143            Some(b')') => { self.i += 1; Ok(Kind::from((l, r))) }
144            Some(_) => Err(PrsErr {
145                msg: "binary list (s-pair) must contain exactly 2 binary s-expressions",
146                byte: self.i
147            }),
148            None => Err(PrsErr {msg: "missing ')'", byte: self.i}),
149        }
150    }
151}
152
153pub fn parse(input: &str, dict: &mut Dict) -> Result<Kind, PrsErr> {
154    let mut p = Prsr::new(input);
155    let k = p.parse_blist(dict)?;
156    p.skip_ws();
157    if !p.eof() {
158        return Err(PrsErr {msg: "trailing input", byte: p.i});
159    }
160    Ok(k)
161}
162
163pub fn unparse(root: &Kind, dict: &Dict) -> String {
164    match root {
165        Kind::Alp { id } => match dict.get_name(*id) {
166            Some(name) => name,
167            None => format!("#{root:?}"),
168        },
169        Kind::Zta { sid, .. } => match *sid {
170            None => format!("#{root:?}"),
171            Some(id) => match dict.get_name(id) {
172                Some(name) => name,
173                None => format!("#{root:?}"),
174            },
175        }
176        Kind::Pir { l, r } => format!(
177            "({} {})",
178            unparse(l, dict), unparse(r, dict)
179        )
180    }
181}