From 48f47671cd3a683045f33e1c14d457860c535a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aodhnait=20=C3=89ta=C3=ADn?= Date: Thu, 27 May 2021 17:40:36 +0000 Subject: [PATCH] Add minus operator Adds "minus" operator, both as a unary negation and a binary subtraction. Refactors Parser::bump to actually return the next token, which is slightly more useful for us. Also changes how Token::len is implemented, and now we return 1 for all tokens that are not listed explicitly. --- src/main.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index a70c061..9308cbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ enum Token<'a> { IntegerLiteral(&'a str), Plus, Star, + Minus, Semicolon, LeftParen, RightParen, @@ -18,13 +19,14 @@ impl Token<'_> { pub fn len(&self) -> usize { return match self { Token::IntegerLiteral(s) => s.len(), - Token::Plus | Token::Semicolon | Token::LeftParen | Token::RightParen | Token::Star => 1, + // Token::Plus, Token::Minus, Token::Semicolon, Token::LeftParen, Token::RightParen, Token::Star + _ => 1, }; } pub fn precedence(&self) -> usize { return match self { - Token::Plus => 1, + Token::Plus | Token::Minus => 1, Token::Star => 2, _ => LOWEST_PRECEDENCE, } @@ -64,6 +66,7 @@ impl<'a> Source<'a> { let token = match chars.next()? { '+' => Token::Plus, + '-' => Token::Minus, '*' => Token::Star, ';' => Token::Semicolon, '(' => Token::LeftParen, @@ -151,14 +154,12 @@ impl<'a> Parser<'a> { return self.source.peek(); } - // Just a wrapper around self.next which disables unused_must_use lint, so it - // can be more useful in some cases (such as when we already know what's the - // following token, for example from the previous call to self.peek, but we - // want to advance the parser now, and don't care about the result). - #[allow(unused_must_use)] + // A wrapper around next function, which WILL panic if there is no token left + // in the source. The intent is to ONLY use it when it is KNOWN that we can + // safely take a token without causing a panic, such as when we peek a token. #[inline(always)] - fn bump(&mut self) { - self.next(); + fn bump(&mut self) -> Token<'a> { + return self.next().unwrap(); } fn parse_primary_expr(&mut self) -> Option> { @@ -180,8 +181,8 @@ impl<'a> Parser<'a> { fn parse_unary_expr(&mut self) -> Option> { return match self.peek()? { - token @ Token::Plus => { - self.bump(); + Token::Plus | Token::Minus => { + let token = self.bump(); let expr = self.parse_unary_expr()?; Some(Expr::Unary(token, box expr)) }, @@ -189,6 +190,9 @@ impl<'a> Parser<'a> { }; } + // expr = unary_expr [ op expr ] + // unary_expr = '+' unary_expr | primary_expr + // primary_expr = literal | '(' expr ')' pub fn parse_expr(&mut self, min_precedence: usize) -> Option> { let mut lhs = self.parse_unary_expr()?; @@ -211,7 +215,8 @@ impl<'a> Parser<'a> { } fn main() { - let inline_source = "3 + +5 * +7;"; + let inline_source = "3 + 2 - -5;"; + // let inline_source = "3 + +5 * +7;"; // let inline_source = "3 + 5 * 7;"; // let inline_source = "(3 + 5) + 7;"; // let inline_source = "3 + (5 + (7 + 11));";