1use crate::ast::Expr;
6use crate::limits::Limits;
7use crate::value::Ternary;
8
9#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
11pub enum ParseError {
12 #[error("表达式在第 {line} 行第 {column} 列意外结束")]
14 UnexpectedEof {
15 line: usize,
17 column: usize,
19 },
20 #[error("第 {line} 行第 {column} 列出现无法识别的字符 {ch:?}")]
22 UnexpectedChar {
23 line: usize,
25 column: usize,
27 ch: char,
29 },
30 #[error("第 {line} 行第 {column} 列缺少右括号 ')'")]
32 UnclosedParen {
33 line: usize,
35 column: usize,
37 },
38 #[error("第 {line} 行第 {column} 列的标识符不合法:{name:?}")]
40 InvalidIdentifier {
41 line: usize,
43 column: usize,
45 name: String,
47 },
48 #[error("表达式为空")]
50 Empty,
51 #[error("表达式嵌套超过 {limit} 层")]
53 TooDeep {
54 limit: usize,
56 },
57 #[error("表达式 {bytes} 字节,超过上限 {limit}")]
59 InputTooLarge {
60 bytes: usize,
62 limit: usize,
64 },
65 #[error("表达式节点数超过 {limit}")]
67 TooManyNodes {
68 limit: usize,
70 },
71}
72
73pub const MAX_DEPTH: usize = 256;
75
76pub const MAX_INPUT_BYTES: usize = 1 << 20;
78
79type Parsed = (Expr, usize);
81
82pub struct Parser {
84 input: Vec<char>,
85 pos: usize,
86 line: usize,
87 column: usize,
88 depth: usize,
89 nodes: usize,
90 limits: Limits,
91}
92
93impl Parser {
94 pub fn new(input: &str) -> Self {
96 Self::with_limits(input, Limits::default())
97 }
98
99 pub fn with_limits(input: &str, limits: Limits) -> Self {
101 Self {
102 input: input.chars().collect(),
103 pos: 0,
104 line: 1,
105 column: 1,
106 depth: 0,
107 nodes: 0,
108 limits,
109 }
110 }
111
112 pub fn parse(input: &str) -> Result<Expr, ParseError> {
114 Self::parse_with_limits(input, Limits::default())
115 }
116
117 pub fn parse_with_limits(input: &str, limits: Limits) -> Result<Expr, ParseError> {
122 if input.len() > MAX_INPUT_BYTES {
123 return Err(ParseError::InputTooLarge {
124 bytes: input.len(),
125 limit: MAX_INPUT_BYTES,
126 });
127 }
128 let mut p = Parser::with_limits(input, limits);
129 p.skip_ws();
130 if p.peek().is_none() {
131 return Err(ParseError::Empty);
132 }
133 let (expr, _) = p.parse_equiv()?;
134 if let Some(ch) = p.peek() {
135 return Err(ParseError::UnexpectedChar {
136 line: p.line,
137 column: p.column,
138 ch,
139 });
140 }
141 Ok(expr)
142 }
143
144 fn take_node(&mut self) -> Result<(), ParseError> {
145 self.nodes += 1;
146 if self.nodes > self.limits.max_nodes {
147 return Err(ParseError::TooManyNodes {
148 limit: self.limits.max_nodes,
149 });
150 }
151 Ok(())
152 }
153
154 fn check_depth(&self, depth: usize) -> Result<(), ParseError> {
155 if depth > self.limits.max_depth {
156 return Err(ParseError::TooDeep {
157 limit: self.limits.max_depth,
158 });
159 }
160 Ok(())
161 }
162
163 fn leaf(&mut self, expr: Expr) -> Result<Parsed, ParseError> {
164 self.take_node()?;
165 Ok((expr, 1))
166 }
167
168 fn join(
169 &mut self,
170 left: Parsed,
171 right: Parsed,
172 f: impl FnOnce(Expr, Expr) -> Expr,
173 ) -> Result<Parsed, ParseError> {
174 let depth = 1 + left.1.max(right.1);
175 self.check_depth(depth)?;
176 self.take_node()?;
177 Ok((f(left.0, right.0), depth))
178 }
179
180 fn not(&mut self, inner: Parsed) -> Result<Parsed, ParseError> {
181 let depth = 1 + inner.1;
182 self.check_depth(depth)?;
183 self.take_node()?;
184 Ok((Expr::logical_not(inner.0), depth))
185 }
186
187 fn peek(&self) -> Option<char> {
188 self.input.get(self.pos).copied()
189 }
190
191 fn bump(&mut self) -> Option<char> {
192 let ch = self.input.get(self.pos).copied()?;
193 self.pos += 1;
194 if ch == '\n' {
195 self.line += 1;
196 self.column = 1;
197 } else {
198 self.column += 1;
199 }
200 Some(ch)
201 }
202
203 fn skip_ws(&mut self) {
204 while let Some(ch) = self.peek() {
205 if ch.is_whitespace() {
206 self.bump();
207 } else {
208 break;
209 }
210 }
211 }
212
213 fn eat_op(&mut self, ops: &[&str]) -> bool {
215 self.skip_ws();
216 for op in ops {
217 let chars: Vec<char> = op.chars().collect();
218 if self.input.len() >= self.pos + chars.len()
219 && self.input[self.pos..self.pos + chars.len()] == chars[..]
220 {
221 for _ in 0..chars.len() {
222 self.bump();
223 }
224 return true;
225 }
226 }
227 false
228 }
229
230 fn parse_equiv(&mut self) -> Result<Parsed, ParseError> {
231 let mut left = self.parse_implies()?;
232 loop {
233 self.skip_ws();
234 if self.eat_op(&["<=>", "≡", "=="]) {
235 let right = self.parse_implies()?;
236 left = self.join(left, right, Expr::equiv)?;
237 } else {
238 return Ok(left);
239 }
240 }
241 }
242
243 fn parse_implies(&mut self) -> Result<Parsed, ParseError> {
244 let mut operands = vec![self.parse_or()?];
246 loop {
247 self.skip_ws();
248 if self.eat_op(&["=>", "→", "⇒"]) {
249 operands.push(self.parse_or()?);
250 } else {
251 break;
252 }
253 }
254 let mut acc = operands.pop().expect("至少有一个操作数");
255 while let Some(left) = operands.pop() {
256 acc = self.join(left, acc, Expr::implies)?;
257 }
258 Ok(acc)
259 }
260
261 fn parse_or(&mut self) -> Result<Parsed, ParseError> {
262 let mut left = self.parse_xor()?;
263 loop {
264 self.skip_ws();
265 if self.eat_op(&["||", "∨", "|"]) {
266 let right = self.parse_xor()?;
267 left = self.join(left, right, Expr::or)?;
268 } else {
269 return Ok(left);
270 }
271 }
272 }
273
274 fn parse_xor(&mut self) -> Result<Parsed, ParseError> {
275 let mut left = self.parse_and()?;
276 loop {
277 self.skip_ws();
278 if self.eat_op(&["⊕", "^"]) {
279 let right = self.parse_and()?;
280 left = self.join(left, right, Expr::xor)?;
281 } else {
282 return Ok(left);
283 }
284 }
285 }
286
287 fn parse_and(&mut self) -> Result<Parsed, ParseError> {
288 let mut left = self.parse_unary()?;
289 loop {
290 self.skip_ws();
291 if self.eat_op(&["&&", "∧", "&"]) {
292 let right = self.parse_unary()?;
293 left = self.join(left, right, Expr::and)?;
294 } else {
295 return Ok(left);
296 }
297 }
298 }
299
300 fn parse_unary(&mut self) -> Result<Parsed, ParseError> {
301 self.depth += 1;
303 if self.depth > self.limits.max_depth {
304 self.depth -= 1;
305 return Err(ParseError::TooDeep {
306 limit: self.limits.max_depth,
307 });
308 }
309 let result = self.parse_unary_inner();
310 self.depth -= 1;
311 result
312 }
313
314 fn parse_unary_inner(&mut self) -> Result<Parsed, ParseError> {
315 self.skip_ws();
316 if self.eat_op(&["!", "~", "¬"]) {
317 let inner = self.parse_unary()?;
318 return self.not(inner);
319 }
320 self.parse_primary()
321 }
322
323 fn parse_primary(&mut self) -> Result<Parsed, ParseError> {
324 self.skip_ws();
325 let Some(ch) = self.peek() else {
326 return Err(ParseError::UnexpectedEof {
327 line: self.line,
328 column: self.column,
329 });
330 };
331
332 if ch == '(' {
333 self.bump();
334 let inner = self.parse_equiv()?;
335 self.skip_ws();
336 if self.peek() != Some(')') {
337 return Err(ParseError::UnclosedParen {
338 line: self.line,
339 column: self.column,
340 });
341 }
342 self.bump();
343 return Ok(inner);
344 }
345
346 if ch == ')' {
347 return Err(ParseError::UnexpectedChar {
348 line: self.line,
349 column: self.column,
350 ch,
351 });
352 }
353
354 if is_ident_start(ch) {
355 let start_line = self.line;
356 let start_col = self.column;
357 let mut name = String::new();
358 while let Some(c) = self.peek() {
359 if is_ident_char(c) {
360 name.push(c);
361 self.bump();
362 } else {
363 break;
364 }
365 }
366 if name.is_empty() {
367 return Err(ParseError::InvalidIdentifier {
368 line: start_line,
369 column: start_col,
370 name,
371 });
372 }
373 return self.leaf(match name.as_str() {
374 "0" | "False" | "false" | "FALSE" => Expr::Const(Ternary::False),
375 "1" | "True" | "true" | "TRUE" => Expr::Const(Ternary::True),
376 "X" | "x" | "?" | "Unknown" | "unknown" => Expr::Const(Ternary::Unknown),
377 _ => Expr::Var(name),
378 });
379 }
380
381 if let Some(v) = Ternary::parse_char(ch) {
382 self.bump();
383 return self.leaf(Expr::Const(v));
384 }
385
386 Err(ParseError::UnexpectedChar {
387 line: self.line,
388 column: self.column,
389 ch,
390 })
391 }
392}
393
394fn is_ident_start(c: char) -> bool {
396 c.is_alphabetic() || c == '_'
397}
398
399fn is_ident_char(c: char) -> bool {
401 c.is_alphanumeric() || c == '_'
402}
403
404#[cfg(test)]
405mod tests {
406 use super::*;
407
408 #[test]
409 fn parses_variables() {
410 assert_eq!(Parser::parse("a").unwrap(), Expr::Var("a".into()));
411 assert_eq!(Parser::parse("a_1").unwrap(), Expr::Var("a_1".into()));
412 }
413
414 #[test]
415 fn parses_constants() {
416 assert_eq!(Parser::parse("0").unwrap(), Expr::Const(Ternary::False));
417 assert_eq!(Parser::parse("1").unwrap(), Expr::Const(Ternary::True));
418 assert_eq!(Parser::parse("X").unwrap(), Expr::Const(Ternary::Unknown));
419 assert_eq!(Parser::parse("?").unwrap(), Expr::Const(Ternary::Unknown));
420 }
421
422 #[test]
423 fn operator_precedence() {
424 let e = Parser::parse("a & b | c").unwrap();
426 assert_eq!(
427 e,
428 Expr::or(
429 Expr::and(Expr::Var("a".into()), Expr::Var("b".into())),
430 Expr::Var("c".into())
431 )
432 );
433 }
434
435 #[test]
436 fn not_binds_tighter_than_and() {
437 let e = Parser::parse("!a & b").unwrap();
438 assert_eq!(
439 e,
440 Expr::and(
441 Expr::logical_not(Expr::Var("a".into())),
442 Expr::Var("b".into())
443 )
444 );
445 }
446
447 #[test]
448 fn implies_is_right_associative() {
449 let e = Parser::parse("a => b => c").unwrap();
450 assert_eq!(
451 e,
452 Expr::implies(
453 Expr::Var("a".into()),
454 Expr::implies(Expr::Var("b".into()), Expr::Var("c".into()))
455 )
456 );
457 }
458
459 #[test]
460 fn parentheses_override_precedence() {
461 let e = Parser::parse("(a | b) & c").unwrap();
462 assert_eq!(
463 e,
464 Expr::and(
465 Expr::or(Expr::Var("a".into()), Expr::Var("b".into())),
466 Expr::Var("c".into())
467 )
468 );
469 }
470
471 #[test]
472 fn unicode_operators() {
473 let e = Parser::parse("a ∧ b ∨ c").unwrap();
474 assert_eq!(
475 e,
476 Expr::or(
477 Expr::and(Expr::Var("a".into()), Expr::Var("b".into())),
478 Expr::Var("c".into())
479 )
480 );
481 let e2 = Parser::parse("a → b").unwrap();
482 assert!(matches!(e2, Expr::Implies(_, _)));
483 }
484
485 #[test]
486 fn reports_unexpected_char() {
487 let err = Parser::parse("a & @").unwrap_err();
488 assert!(matches!(err, ParseError::UnexpectedChar { .. }));
489 }
490
491 #[test]
492 fn reports_unclosed_paren() {
493 let err = Parser::parse("(a & b").unwrap_err();
494 assert!(matches!(err, ParseError::UnclosedParen { .. }));
495 }
496
497 #[test]
498 fn reports_empty() {
499 assert_eq!(Parser::parse(" ").unwrap_err(), ParseError::Empty);
500 }
501
502 #[test]
503 fn rejects_excessive_nesting() {
504 let deep = format!("{}a", "!".repeat(MAX_DEPTH + 1));
505 assert!(matches!(
506 Parser::parse(&deep).unwrap_err(),
507 ParseError::TooDeep { .. }
508 ));
509 let ok = format!("{}a", "!".repeat(MAX_DEPTH - 1));
510 assert!(Parser::parse(&ok).is_ok());
511 }
512
513 #[test]
514 fn rejects_long_flat_binary_chain() {
515 let src = std::iter::repeat_n("a", MAX_DEPTH + 2)
516 .collect::<Vec<_>>()
517 .join(" & ");
518 assert!(matches!(
519 Parser::parse(&src).unwrap_err(),
520 ParseError::TooDeep { .. }
521 ));
522 }
523
524 #[test]
525 fn rejects_long_right_associative_implication_chain() {
526 let src = std::iter::repeat_n("a", MAX_DEPTH + 2)
527 .collect::<Vec<_>>()
528 .join(" => ");
529 assert!(matches!(
530 Parser::parse(&src).unwrap_err(),
531 ParseError::TooDeep { .. }
532 ));
533 }
534
535 #[test]
536 fn node_budget_is_enforced_while_parsing() {
537 let limits = Limits {
538 max_nodes: 4,
539 ..Limits::default()
540 };
541 let err = Parser::parse_with_limits("a & b & c & d", limits).unwrap_err();
542 assert_eq!(err, ParseError::TooManyNodes { limit: 4 });
543 }
544
545 #[test]
546 fn compat_depth_constant_matches_default_limits() {
547 assert_eq!(MAX_DEPTH, Limits::default().max_depth);
548 }
549
550 #[test]
551 fn oversized_input_is_rejected_before_collecting_chars() {
552 let src = "a".repeat(MAX_INPUT_BYTES + 1);
553 assert!(matches!(
554 Parser::parse(&src).unwrap_err(),
555 ParseError::InputTooLarge { .. }
556 ));
557 }
558
559 #[test]
560 fn deep_parentheses_are_bounded_by_unary_depth() {
561 let src = format!(
562 "{}a{}",
563 "(".repeat(MAX_DEPTH + 1),
564 ")".repeat(MAX_DEPTH + 1)
565 );
566 assert!(matches!(
567 Parser::parse(&src).unwrap_err(),
568 ParseError::TooDeep { .. }
569 ));
570 }
571}