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 pub fn get_name(&self, id: ID) -> Option<String> {
37 self.rev.get(&id).cloned()
38 }
39}
40
41#[derive(Clone, Debug)]
43pub struct PrsErr {
44 pub msg: &'static str,
45 pub byte: usize,
46}
47
48struct 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 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 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}