Parses an expression. Returns `None` if no expression was found. This is necessary to treat the case of empty arguments to statements, as is the case in `PRINT a , , b`. If the caller has already processed a parenthesized term of an expression like `(first) + second`, then that term must be provided in `first`. This is an implementation of the Shunting Yard Algorithm by Edgar Dijkstra.
(&mut self, first: Option<Expr>)
| 783 | /// |
| 784 | /// This is an implementation of the Shunting Yard Algorithm by Edgar Dijkstra. |
| 785 | fn parse_expr(&mut self, first: Option<Expr>) -> Result<Option<Expr>> { |
| 786 | let mut exprs: Vec<Expr> = vec![]; |
| 787 | let mut op_spans: Vec<ExprOpSpan> = vec![]; |
| 788 | |
| 789 | let mut need_operand = true; // Also tracks whether an upcoming minus is unary. |
| 790 | if let Some(e) = first { |
| 791 | exprs.push(e); |
| 792 | need_operand = false; |
| 793 | } |
| 794 | |
| 795 | loop { |
| 796 | let mut handle_operand = |e, pos| { |
| 797 | if !need_operand { |
| 798 | return Err(Error::Bad(pos, "Unexpected value in expression".to_owned())); |
| 799 | } |
| 800 | need_operand = false; |
| 801 | exprs.push(e); |
| 802 | Ok(()) |
| 803 | }; |
| 804 | |
| 805 | // Stop processing if we encounter an expression separator, but don't consume it because |
| 806 | // the caller needs to have access to it. |
| 807 | match self.lexer.peek()?.token { |
| 808 | Token::Eof |
| 809 | | Token::Eol |
| 810 | | Token::As |
| 811 | | Token::Comma |
| 812 | | Token::Else |
| 813 | | Token::Semicolon |
| 814 | | Token::Then |
| 815 | | Token::To |
| 816 | | Token::Step => break, |
| 817 | Token::RightParen if !op_spans.iter().any(|eos| eos.op == ExprOp::LeftParen) => { |
| 818 | // We encountered an unbalanced parenthesis but we don't know if this is |
| 819 | // because we were called from within an argument list (in which case the |
| 820 | // caller consumed the opening parenthesis and is expecting to consume the |
| 821 | // closing parenthesis) or because we really found an invalid expression. |
| 822 | // Only the caller can know, so avoid consuming the token and exit. |
| 823 | break; |
| 824 | } |
| 825 | _ => (), |
| 826 | }; |
| 827 | |
| 828 | let ts = self.lexer.consume_peeked(); |
| 829 | match ts.token { |
| 830 | Token::Boolean(value) => { |
| 831 | handle_operand(Expr::Boolean(BooleanSpan { value, pos: ts.pos }), ts.pos)? |
| 832 | } |
| 833 | Token::Double(value) => { |
| 834 | handle_operand(Expr::Double(DoubleSpan { value, pos: ts.pos }), ts.pos)? |
| 835 | } |
| 836 | Token::Integer(value) => { |
| 837 | handle_operand(Expr::Integer(IntegerSpan { value, pos: ts.pos }), ts.pos)? |
| 838 | } |
| 839 | Token::Text(value) => { |
| 840 | handle_operand(Expr::Text(TextSpan { value, pos: ts.pos }), ts.pos)? |
| 841 | } |
| 842 | Token::Symbol(vref) => { |
no test coverage detected