练习:使用 Result 进行重写

以下代码实现了一个非常简单的表达式语言解析器。不过,它通过 panic 机制来处理错误。请重写该代码,改用惯用的错误处理方式,并将错误传播到 main 函数的返回值。您可以随意使用 thiserroranyhow

提示:请先修复 parse 函数中的错误处理问题。该部分正常运行后,请更新 Tokenizer 以实现 Iterator<Item=Result<Token, TokenizerError>>,并在解析器中进行相应处理。

  1. use std::iter::Peekable;
  2. use std::str::Chars;
  3. /// An arithmetic operator.
  4. #[derive(Debug, PartialEq, Clone, Copy)]
  5. enum Op {
  6. Add,
  7. Sub,
  8. }
  9. /// A token in the expression language.
  10. #[derive(Debug, PartialEq)]
  11. enum Token {
  12. Number(String),
  13. Identifier(String),
  14. Operator(Op),
  15. }
  16. /// An expression in the expression language.
  17. #[derive(Debug, PartialEq)]
  18. enum Expression {
  19. /// A reference to a variable.
  20. Var(String),
  21. /// A literal number.
  22. Number(u32),
  23. /// A binary operation.
  24. Operation(Box<Expression>, Op, Box<Expression>),
  25. }
  26. fn tokenize(input: &str) -> Tokenizer {
  27. return Tokenizer(input.chars().peekable());
  28. }
  29. struct Tokenizer<'a>(Peekable<Chars<'a>>);
  30. impl<'a> Iterator for Tokenizer<'a> {
  31. type Item = Token;
  32. fn next(&mut self) -> Option<Token> {
  33. let c = self.0.next()?;
  34. match c {
  35. '0'..='9' => {
  36. let mut num = String::from(c);
  37. while let Some(c @ '0'..='9') = self.0.peek() {
  38. num.push(*c);
  39. self.0.next();
  40. }
  41. Some(Token::Number(num))
  42. }
  43. 'a'..='z' => {
  44. let mut ident = String::from(c);
  45. while let Some(c @ ('a'..='z' | '_' | '0'..='9')) = self.0.peek() {
  46. ident.push(*c);
  47. self.0.next();
  48. }
  49. Some(Token::Identifier(ident))
  50. }
  51. '+' => Some(Token::Operator(Op::Add)),
  52. '-' => Some(Token::Operator(Op::Sub)),
  53. _ => panic!("Unexpected character {c}"),
  54. }
  55. }
  56. }
  57. fn parse(input: &str) -> Expression {
  58. let mut tokens = tokenize(input);
  59. fn parse_expr<'a>(tokens: &mut Tokenizer<'a>) -> Expression {
  60. let Some(tok) = tokens.next() else {
  61. panic!("Unexpected end of input");
  62. };
  63. let expr = match tok {
  64. Token::Number(num) => {
  65. let v = num.parse().expect("Invalid 32-bit integer'");
  66. Expression::Number(v)
  67. }
  68. Token::Identifier(ident) => Expression::Var(ident),
  69. Token::Operator(_) => panic!("Unexpected token {tok:?}"),
  70. };
  71. // Look ahead to parse a binary operation if present.
  72. match tokens.next() {
  73. None => expr,
  74. Some(Token::Operator(op)) => Expression::Operation(
  75. Box::new(expr),
  76. op,
  77. Box::new(parse_expr(tokens)),
  78. ),
  79. Some(tok) => panic!("Unexpected token {tok:?}"),
  80. }
  81. }
  82. parse_expr(&mut tokens)
  83. }
  84. fn main() {
  85. let expr = parse("10+foo+20-30");
  86. println!("{expr:?}");
  87. }