Implement augmented assignment operators

Add support for +=, -=, *=, and /= operators. This is basically just
syntactic sugar, but it's still nice to have

    a += 1

compiles to the equivalent of

    a = a + 1

with all the same implications of scoping rules.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2024-10-07 10:23:15 -07:00
parent 8179611c23
commit 365bee0554
5 changed files with 111 additions and 36 deletions

View File

@@ -178,17 +178,31 @@ impl Lexer {
} else if STRING_START_CHARS.contains(self.current()) {
return self.string();
} else if self.mat('+') {
return Ok(self.make_token(TokenKind::Plus));
if self.mat('=') {
return Ok(self.make_token(TokenKind::PlusEq));
} else {
return Ok(self.make_token(TokenKind::Plus));
}
} else if self.mat('-') {
if self.mat('>') {
return Ok(self.make_token(TokenKind::Arrow));
} else if self.mat('=') {
return Ok(self.make_token(TokenKind::MinusEq));
} else {
return Ok(self.make_token(TokenKind::Minus));
}
} else if self.mat('*') {
return Ok(self.make_token(TokenKind::Star));
if self.mat('=') {
return Ok(self.make_token(TokenKind::StarEq));
} else {
return Ok(self.make_token(TokenKind::Star));
}
} else if self.mat('/') {
return Ok(self.make_token(TokenKind::Slash));
if self.mat('=') {
return Ok(self.make_token(TokenKind::SlashEq));
} else {
return Ok(self.make_token(TokenKind::Slash));
}
} else if self.mat('&') {
if self.mat('&') {
return Ok(self.make_token(TokenKind::And));
@@ -561,7 +575,13 @@ impl Parser {
stmts,
rbrace,
}) as Box<dyn Stmt + 'static>)
} else if self.current.kind == TokenKind::Name && self.next.kind == TokenKind::Eq {
} else if self.current.kind == TokenKind::Name
&& (self.next.kind == TokenKind::Eq
|| self.next.kind == TokenKind::PlusEq
|| self.next.kind == TokenKind::MinusEq
|| self.next.kind == TokenKind::StarEq
|| self.next.kind == TokenKind::SlashEq)
{
self.assign_stmt()
} else {
let expr = self.expr()?;
@@ -745,7 +765,15 @@ impl Parser {
let name = self
.expect("expect name for assign statement", TokenKind::Name)?
.clone();
self.expect("expect '=' after name", TokenKind::Eq)?;
let op = expect!(
self,
"expected '=' or augmented assign after name",
TokenKind::Eq,
TokenKind::PlusEq,
TokenKind::MinusEq,
TokenKind::StarEq,
TokenKind::SlashEq
)?;
let expr = self.expr()?;
if !self.check(TokenKind::RBrace) {
expect!(
@@ -757,6 +785,7 @@ impl Parser {
}
Ok(Box::new(AssignStmt {
lhs: name,
op,
rhs: expr,
}))
}