From e13f3e35c21d180af4e5c498604d2ad0261f2844 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 31 Oct 2021 01:00:56 +0200 Subject: [PATCH] binary op --- grammar.txt | 2 +- src/parse.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 120 insertions(+), 16 deletions(-) diff --git a/grammar.txt b/grammar.txt index 3e9b661..9203b92 100644 --- a/grammar.txt +++ b/grammar.txt @@ -61,7 +61,7 @@ ::= { ( "*" | "/" | "%" ) } - ::= ( "not" | "-" ) + ::= { ( "not" | "-" ) } ::= | diff --git a/src/parse.rs b/src/parse.rs index 3237c7b..4f413b2 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -92,29 +92,78 @@ impl<'code> Parser<'code> { } fn factor(&mut self) -> ParseResult<'code, Expr> { - todo!() + let lhs = self.unary()?; + match self.peek() { + Some(Token { + kind: TokenType::Asterisk, + .. + }) => { + let _ = self.next(); + let rhs = self.unary()?; + Ok(Expr::BinaryOp(Box::new(BinaryOp { + span: lhs.span().extend(rhs.span()), + lhs, + rhs, + kind: BinaryOpKind::Mul, + }))) + } + Some(Token { + kind: TokenType::Slash, + .. + }) => { + let _ = self.next(); + let rhs = self.unary()?; + Ok(Expr::BinaryOp(Box::new(BinaryOp { + span: lhs.span().extend(rhs.span()), + lhs, + rhs, + kind: BinaryOpKind::Div, + }))) + } + Some(Token { + kind: TokenType::Percent, + .. + }) => { + let _ = self.next(); + let rhs = self.unary()?; + Ok(Expr::BinaryOp(Box::new(BinaryOp { + span: lhs.span().extend(rhs.span()), + lhs, + rhs, + kind: BinaryOpKind::Mod, + }))) + } + _ => Ok(lhs), + } } fn unary(&mut self) -> ParseResult<'code, Expr> { - let next = self.next().ok_or(ParseErr::EOF)?; - match next.kind { - TokenType::Not => { + match self.peek() { + Some(Token { + kind: TokenType::Not, + .. + }) => { + let unary_op_span = self.next().unwrap().span; let expr = self.expression()?; Ok(Expr::UnaryOp(Box::new(UnaryOp { - span: next.span, + span: unary_op_span.extend(expr.span()), expr, kind: UnaryOpKind::Not, }))) } - TokenType::Minus => { + Some(Token { + kind: TokenType::Minus, + .. + }) => { + let unary_op_span = self.next().unwrap().span; let expr = self.expression()?; Ok(Expr::UnaryOp(Box::new(UnaryOp { - span: next.span, + span: unary_op_span.extend(expr.span()), expr, kind: UnaryOpKind::Neg, }))) } - _ => todo!(), + _ => self.primary(), } } @@ -160,10 +209,12 @@ impl<'code> Parser<'code> { // helpers + #[must_use] fn next(&mut self) -> Option> { self.tokens.next() } + #[must_use] fn peek(&mut self) -> Option<&Token<'code>> { self.tokens.peek() } @@ -206,6 +257,13 @@ mod test { use crate::lex::{Token, TokenType}; use crate::parse::Parser; + mod prelude { + pub(super) use super::{parser, token}; + pub(super) use crate::ast::{Expr, Literal}; + pub(super) use crate::errors::Span; + pub(super) use crate::lex::{Token, TokenType}; + } + fn token(kind: TokenType) -> Token { Token { span: crate::errors::Span::dummy(), @@ -219,17 +277,63 @@ mod test { } } + mod factor { + use super::prelude::*; + use crate::ast::{BinaryOp, BinaryOpKind}; + + fn parse_factor<'a, T: Into>>>(tokens: T) -> Expr { + let mut parser = parser(tokens); + parser.factor().unwrap() + } + + fn test_literal_factor(token_type: TokenType, expected_op_kind: BinaryOpKind) { + let tokens = [TokenType::Number(10.0), token_type, TokenType::Number(4.0)].map(token); + let factor = parse_factor(tokens); + assert_eq!( + Expr::BinaryOp(Box::new(BinaryOp { + span: Span::dummy(), + lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())), + rhs: Expr::Literal(Literal::Number(4.0, Span::dummy())), + kind: expected_op_kind + })), + factor + ); + } + + #[test] + fn multiply() { + test_literal_factor(TokenType::Asterisk, BinaryOpKind::Mul); + } + + #[test] + fn divide() { + test_literal_factor(TokenType::Slash, BinaryOpKind::Div); + } + + #[test] + fn modulo() { + test_literal_factor(TokenType::Percent, BinaryOpKind::Mod); + } + } + mod unary { - use super::{parser, token}; - use crate::ast::{Expr, Literal}; - use crate::lex::{Token, TokenType}; + use super::prelude::*; + + fn parse_unary<'a, T: Into>>>(tokens: T) -> Expr { + let mut parser = parser(tokens); + parser.primary().unwrap() + } + + #[test] + fn number_literal() { + let tokens = [TokenType::Number(10.0)].map(token); + let unary = parse_unary(tokens); + assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary); + } } mod primary { - use super::{parser, token}; - use crate::ast::{Expr, Literal}; - use crate::errors::Span; - use crate::lex::{Token, TokenType}; + use super::prelude::*; fn parse_primary<'a, T: Into>>>(tokens: T) -> Expr { let mut parser = parser(tokens);