MCPcopy Index your code
hub / github.com/endbasic/endbasic / parse_expr

Method parse_expr

core/src/parser.rs:785–1009  ·  view source on GitHub ↗

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>)

Source from the content-addressed store, hash-verified

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) => {

Callers 4

parse_builtin_callMethod · 0.80
maybe_parse_endMethod · 0.80
parse_required_exprMethod · 0.80

Calls 8

pushMethod · 0.80
iterMethod · 0.80
consume_peekedMethod · 0.80
applyMethod · 0.80
lastMethod · 0.80
priorityMethod · 0.80
peekMethod · 0.45

Tested by

no test coverage detected