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:
parent
56fffd6911
commit
48f47671cd
29
src/main.rs
29
src/main.rs
|
@ -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));";
|
||||||
|
|
Loading…
Reference in New Issue