1use crate::ast::Expr;
6use crate::value::Ternary;
7
8#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
10pub enum ParseError {
11 #[error("表达式在第 {line} 行第 {column} 列意外结束")]
13 UnexpectedEof {
14 line: usize,
16 column: usize,
18 },
19 #[error("第 {line} 行第 {column} 列出现无法识别的字符 {ch:?}")]
21 UnexpectedChar {
22 line: usize,
24 column: usize,
26 ch: char,
28 },
29 #[error("第 {line} 行第 {column} 列缺少右括号 ')'")]
31 UnclosedParen {
32 line: usize,
34 column: usize,
36 },
37 #[error("第 {line} 行第 {column} 列的标识符不合法:{name:?}")]
39 InvalidIdentifier {
40 line: usize,
42 column: usize,
44 name: String,
46 },
47 #[error("表达式为空")]
49 Empty,
50}
51
52pub struct Parser {
54 input: Vec<char>,
55 pos: usize,
56 line: usize,
57 column: usize,
58}
59
60impl Parser {
61 pub fn new(input: &str) -> Self {
63 Self {
64 input: input.chars().collect(),
65 pos: 0,
66 line: 1,
67 column: 1,
68 }
69 }
70
71 pub fn parse(input: &str) -> Result<Expr, ParseError> {
73 let mut p = Parser::new(input);
74 p.skip_ws();
75 if p.peek().is_none() {
76 return Err(ParseError::Empty);
77 }
78 let expr = p.parse_equiv()?;
79 if let Some(ch) = p.peek() {
80 return Err(ParseError::UnexpectedChar {
81 line: p.line,
82 column: p.column,
83 ch,
84 });
85 }
86 Ok(expr)
87 }
88
89 fn peek(&self) -> Option<char> {
90 self.input.get(self.pos).copied()
91 }
92
93 fn bump(&mut self) -> Option<char> {
94 let ch = self.input.get(self.pos).copied()?;
95 self.pos += 1;
96 if ch == '\n' {
97 self.line += 1;
98 self.column = 1;
99 } else {
100 self.column += 1;
101 }
102 Some(ch)
103 }
104
105 fn skip_ws(&mut self) {
106 while let Some(ch) = self.peek() {
107 if ch.is_whitespace() {
108 self.bump();
109 } else {
110 break;
111 }
112 }
113 }
114
115 fn eat_op(&mut self, ops: &[&str]) -> bool {
117 self.skip_ws();
118 for op in ops {
119 let chars: Vec<char> = op.chars().collect();
120 if self.input.len() >= self.pos + chars.len()
121 && self.input[self.pos..self.pos + chars.len()] == chars[..]
122 {
123 for _ in 0..chars.len() {
124 self.bump();
125 }
126 return true;
127 }
128 }
129 false
130 }
131
132 fn parse_equiv(&mut self) -> Result<Expr, ParseError> {
133 let mut left = self.parse_implies()?;
134 loop {
135 self.skip_ws();
136 if self.eat_op(&["<=>", "≡", "=="]) {
137 let right = self.parse_implies()?;
138 left = Expr::equiv(left, right);
139 } else {
140 return Ok(left);
141 }
142 }
143 }
144
145 fn parse_implies(&mut self) -> Result<Expr, ParseError> {
146 let left = self.parse_or()?;
147 self.skip_ws();
148 if self.eat_op(&["=>", "→", "⇒"]) {
149 let right = self.parse_implies()?;
151 return Ok(Expr::implies(left, right));
152 }
153 Ok(left)
154 }
155
156 fn parse_or(&mut self) -> Result<Expr, ParseError> {
157 let mut left = self.parse_xor()?;
158 loop {
159 self.skip_ws();
160 if self.eat_op(&["||", "∨", "|"]) {
161 let right = self.parse_xor()?;
162 left = Expr::or(left, right);
163 } else {
164 return Ok(left);
165 }
166 }
167 }
168
169 fn parse_xor(&mut self) -> Result<Expr, ParseError> {
170 let mut left = self.parse_and()?;
171 loop {
172 self.skip_ws();
173 if self.eat_op(&["⊕", "^"]) {
174 let right = self.parse_and()?;
175 left = Expr::xor(left, right);
176 } else {
177 return Ok(left);
178 }
179 }
180 }
181
182 fn parse_and(&mut self) -> Result<Expr, ParseError> {
183 let mut left = self.parse_unary()?;
184 loop {
185 self.skip_ws();
186 if self.eat_op(&["&&", "∧", "&"]) {
187 let right = self.parse_unary()?;
188 left = Expr::and(left, right);
189 } else {
190 return Ok(left);
191 }
192 }
193 }
194
195 fn parse_unary(&mut self) -> Result<Expr, ParseError> {
196 self.skip_ws();
197 if self.eat_op(&["!", "~", "¬"]) {
198 let inner = self.parse_unary()?;
199 return Ok(Expr::logical_not(inner));
200 }
201 self.parse_primary()
202 }
203
204 fn parse_primary(&mut self) -> Result<Expr, ParseError> {
205 self.skip_ws();
206 let Some(ch) = self.peek() else {
207 return Err(ParseError::UnexpectedEof {
208 line: self.line,
209 column: self.column,
210 });
211 };
212
213 if ch == '(' {
214 self.bump();
215 let inner = self.parse_equiv()?;
216 self.skip_ws();
217 if self.peek() != Some(')') {
218 return Err(ParseError::UnclosedParen {
219 line: self.line,
220 column: self.column,
221 });
222 }
223 self.bump();
224 return Ok(inner);
225 }
226
227 if ch == ')' {
228 return Err(ParseError::UnexpectedChar {
229 line: self.line,
230 column: self.column,
231 ch,
232 });
233 }
234
235 if is_ident_start(ch) {
236 let start_line = self.line;
237 let start_col = self.column;
238 let mut name = String::new();
239 while let Some(c) = self.peek() {
240 if is_ident_char(c) {
241 name.push(c);
242 self.bump();
243 } else {
244 break;
245 }
246 }
247 if name.is_empty() {
248 return Err(ParseError::InvalidIdentifier {
249 line: start_line,
250 column: start_col,
251 name,
252 });
253 }
254 return Ok(match name.as_str() {
255 "0" | "False" | "false" | "FALSE" => Expr::Const(Ternary::False),
256 "1" | "True" | "true" | "TRUE" => Expr::Const(Ternary::True),
257 "X" | "x" | "?" | "Unknown" | "unknown" => Expr::Const(Ternary::Unknown),
258 _ => Expr::Var(name),
259 });
260 }
261
262 if let Some(v) = Ternary::parse_char(ch) {
263 self.bump();
264 return Ok(Expr::Const(v));
265 }
266
267 Err(ParseError::UnexpectedChar {
268 line: self.line,
269 column: self.column,
270 ch,
271 })
272 }
273}
274
275fn is_ident_start(c: char) -> bool {
277 c.is_alphabetic() || c == '_'
278}
279
280fn is_ident_char(c: char) -> bool {
282 c.is_alphanumeric() || c == '_'
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn parses_variables() {
291 assert_eq!(Parser::parse("a").unwrap(), Expr::Var("a".into()));
292 assert_eq!(Parser::parse("a_1").unwrap(), Expr::Var("a_1".into()));
293 }
294
295 #[test]
296 fn parses_constants() {
297 assert_eq!(Parser::parse("0").unwrap(), Expr::Const(Ternary::False));
298 assert_eq!(Parser::parse("1").unwrap(), Expr::Const(Ternary::True));
299 assert_eq!(Parser::parse("X").unwrap(), Expr::Const(Ternary::Unknown));
300 assert_eq!(Parser::parse("?").unwrap(), Expr::Const(Ternary::Unknown));
301 }
302
303 #[test]
304 fn operator_precedence() {
305 let e = Parser::parse("a & b | c").unwrap();
307 assert_eq!(
308 e,
309 Expr::or(
310 Expr::and(Expr::Var("a".into()), Expr::Var("b".into())),
311 Expr::Var("c".into())
312 )
313 );
314 }
315
316 #[test]
317 fn not_binds_tighter_than_and() {
318 let e = Parser::parse("!a & b").unwrap();
319 assert_eq!(
320 e,
321 Expr::and(
322 Expr::logical_not(Expr::Var("a".into())),
323 Expr::Var("b".into())
324 )
325 );
326 }
327
328 #[test]
329 fn implies_is_right_associative() {
330 let e = Parser::parse("a => b => c").unwrap();
331 assert_eq!(
332 e,
333 Expr::implies(
334 Expr::Var("a".into()),
335 Expr::implies(Expr::Var("b".into()), Expr::Var("c".into()))
336 )
337 );
338 }
339
340 #[test]
341 fn parentheses_override_precedence() {
342 let e = Parser::parse("(a | b) & c").unwrap();
343 assert_eq!(
344 e,
345 Expr::and(
346 Expr::or(Expr::Var("a".into()), Expr::Var("b".into())),
347 Expr::Var("c".into())
348 )
349 );
350 }
351
352 #[test]
353 fn unicode_operators() {
354 let e = Parser::parse("a ∧ b ∨ c").unwrap();
355 assert_eq!(
356 e,
357 Expr::or(
358 Expr::and(Expr::Var("a".into()), Expr::Var("b".into())),
359 Expr::Var("c".into())
360 )
361 );
362 let e2 = Parser::parse("a → b").unwrap();
363 assert!(matches!(e2, Expr::Implies(_, _)));
364 }
365
366 #[test]
367 fn reports_unexpected_char() {
368 let err = Parser::parse("a & @").unwrap_err();
369 assert!(matches!(err, ParseError::UnexpectedChar { .. }));
370 }
371
372 #[test]
373 fn reports_unclosed_paren() {
374 let err = Parser::parse("(a & b").unwrap_err();
375 assert!(matches!(err, ParseError::UnclosedParen { .. }));
376 }
377
378 #[test]
379 fn reports_empty() {
380 assert_eq!(Parser::parse(" ").unwrap_err(), ParseError::Empty);
381 }
382}