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.
This commit is contained in:
Aodhnait Étaín 2021-05-27 17:40:36 +00:00
parent 56fffd6911
commit 48f47671cd
Signed by: aodhneine
GPG Key ID: ECE91C73AD45F245
1 changed files with 17 additions and 12 deletions

View File

@ -7,6 +7,7 @@ enum Token<'a> {
IntegerLiteral(&'a str), IntegerLiteral(&'a str),
Plus, Plus,
Star, Star,
Minus,
Semicolon, Semicolon,
LeftParen, LeftParen,
RightParen, RightParen,
@ -18,13 +19,14 @@ impl Token<'_> {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
return match self { return match self {
Token::IntegerLiteral(s) => s.len(), 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 { pub fn precedence(&self) -> usize {
return match self { return match self {
Token::Plus => 1, Token::Plus | Token::Minus => 1,
Token::Star => 2, Token::Star => 2,
_ => LOWEST_PRECEDENCE, _ => LOWEST_PRECEDENCE,
} }
@ -64,6 +66,7 @@ impl<'a> Source<'a> {
let token = match chars.next()? { let token = match chars.next()? {
'+' => Token::Plus, '+' => Token::Plus,
'-' => Token::Minus,
'*' => Token::Star, '*' => Token::Star,
';' => Token::Semicolon, ';' => Token::Semicolon,
'(' => Token::LeftParen, '(' => Token::LeftParen,
@ -151,14 +154,12 @@ impl<'a> Parser<'a> {
return self.source.peek(); return self.source.peek();
} }
// Just a wrapper around self.next which disables unused_must_use lint, so it // A wrapper around next function, which WILL panic if there is no token left
// can be more useful in some cases (such as when we already know what's the // in the source. The intent is to ONLY use it when it is KNOWN that we can
// following token, for example from the previous call to self.peek, but we // safely take a token without causing a panic, such as when we peek a token.
// want to advance the parser now, and don't care about the result).
#[allow(unused_must_use)]
#[inline(always)] #[inline(always)]
fn bump(&mut self) { fn bump(&mut self) -> Token<'a> {
self.next(); return self.next().unwrap();
} }
fn parse_primary_expr(&mut self) -> Option<Expr<'a>> { fn parse_primary_expr(&mut self) -> Option<Expr<'a>> {
@ -180,8 +181,8 @@ impl<'a> Parser<'a> {
fn parse_unary_expr(&mut self) -> Option<Expr<'a>> { fn parse_unary_expr(&mut self) -> Option<Expr<'a>> {
return match self.peek()? { return match self.peek()? {
token @ Token::Plus => { Token::Plus | Token::Minus => {
self.bump(); let token = self.bump();
let expr = self.parse_unary_expr()?; let expr = self.parse_unary_expr()?;
Some(Expr::Unary(token, box 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<Expr<'a>> { pub fn parse_expr(&mut self, min_precedence: usize) -> Option<Expr<'a>> {
let mut lhs = self.parse_unary_expr()?; let mut lhs = self.parse_unary_expr()?;
@ -211,7 +215,8 @@ impl<'a> Parser<'a> {
} }
fn main() { 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;"; // let inline_source = "(3 + 5) + 7;";
// let inline_source = "3 + (5 + (7 + 11));"; // let inline_source = "3 + (5 + (7 + 11));";