diff --git a/src/generator/js.rs b/src/generator/js.rs index 8649982..822c7b5 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -242,6 +242,10 @@ fn generate_bin_op(left: Expression, op: BinOp, right: Expression) -> String { BinOp::NotEqual => "!==", BinOp::Or => "||", BinOp::Subtraction => "-", + BinOp::AddAssign => "+=", + BinOp::SubtractAssign => "-=", + BinOp::MultiplyAssign => "*=", + BinOp::DivideAssign => "/=", }; format!( "({l} {op} {r})", diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index af2d8bf..3f79e42 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -94,6 +94,14 @@ pub enum TokenKind { And, /// "||" Or, + /// "+=" + PlusEqual, + /// "-=" + MinusEqual, + /// "*=" + StarEqual, + /// "/=" + SlashEqual, /// "(" BraceOpen, /// ")" @@ -193,15 +201,37 @@ impl Cursor<'_> { c if is_whitespace(c) => self.whitespace(), '0'..='9' => self.number(), '"' | '\'' => self.string(), - '+' => Plus, - '-' => Minus, - '*' => Star, + '+' => match self.first() { + '=' => { + self.bump(); + PlusEqual + } + _ => Plus, + }, + '-' => match self.first() { + '=' => { + self.bump(); + MinusEqual + } + _ => Minus, + }, + '*' => match self.first() { + '=' => { + self.bump(); + StarEqual + } + _ => Star, + }, '%' => Percent, '/' => match self.first() { '/' => { self.bump(); self.comment() } + '=' => { + self.bump(); + SlashEqual + } _ => Slash, }, '=' => match self.first() { diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index 12e2263..405a159 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -146,6 +146,10 @@ pub enum BinOp { NotEqual, And, Or, + AddAssign, + SubtractAssign, + MultiplyAssign, + DivideAssign, } impl TryFrom for BinOp { @@ -165,6 +169,10 @@ impl TryFrom for BinOp { TokenKind::NotEqual => Ok(BinOp::NotEqual), TokenKind::And => Ok(BinOp::And), TokenKind::Or => Ok(BinOp::Or), + TokenKind::PlusEqual => Ok(BinOp::AddAssign), + TokenKind::MinusEqual => Ok(BinOp::SubtractAssign), + TokenKind::StarEqual => Ok(BinOp::MultiplyAssign), + TokenKind::SlashEqual => Ok(BinOp::DivideAssign), other => Err(format!("Token {:?} cannot be converted into a BinOp", other).into()), } } diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 218c951..8fa5488 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -152,6 +152,10 @@ impl Parser { TokenKind::Assign => self.parse_assignent(Some(expr)), _ => Ok(Statement::Exp(expr)), } + } else if let Ok(_) = BinOp::try_from(self.peek()?.kind) { + let expr = Expression::Variable(ident.into()); + let state = Statement::Exp(self.parse_bin_op(Some(expr))?); + Ok(state) } else { let state = Statement::Exp(Expression::Variable(ident.into())); Ok(state) diff --git a/tests/operator_assignments.sb b/tests/operator_assignments.sb new file mode 100644 index 0000000..3d3a7dd --- /dev/null +++ b/tests/operator_assignments.sb @@ -0,0 +1,8 @@ +fn main() { + let x = 10 + x += 1 + x -= 2 + x *= 2 + x /= 2 + println(x) +} \ No newline at end of file