diff --git a/examples/percent.ast b/examples/percent.ast new file mode 100644 index 0000000..edc1977 --- /dev/null +++ b/examples/percent.ast @@ -0,0 +1,5 @@ +let a = 7 +let b = a % 3 +print("b=", b) +a %= 4 +print("a=", a) \ No newline at end of file diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 87772d5..d04b882 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -106,6 +106,7 @@ pub enum BinaryOp { Sub, Mul, Div, + Mod, Greater, GreaterEqual, @@ -129,4 +130,5 @@ pub enum AssignOp { MinusEqual, // -= StarEqual, // *= SlashEqual, // /= + PercentEqual, // %= } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 5bd707a..bc209bd 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -314,6 +314,13 @@ impl Interpreter { token: None, }), }, + crate::ast::expr::BinaryOp::Mod => match (l,r) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a%b)), + _ => Err(RuntimeError::RuntimeError { + message: "Invalid '%' operands".to_string(), + token: None, + }), + }, crate::ast::expr::BinaryOp::Greater => Ok(Value::Bool(self.as_number(&l)? > self.as_number(&r)?)), crate::ast::expr::BinaryOp::GreaterEqual => Ok(Value::Bool(self.as_number(&l)? >= self.as_number(&r)?)), crate::ast::expr::BinaryOp::Less => Ok(Value::Bool(self.as_number(&l)? < self.as_number(&r)?)), @@ -443,6 +450,11 @@ impl Interpreter { let right_num = self.as_number(&right)?; Ok(Value::Number(left_num / right_num)) } + AssignOp::PercentEqual => { + let left_num = self.as_number(&left)?; + let right_num = self.as_number(&right)?; + Ok(Value::Number(left_num % right_num)) + } } } diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 508a0a3..5a9c36a 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -96,6 +96,14 @@ impl Lexer { } } + '%' => { + if self.match_char('=') { + TokenKind::PercentEqual + } else { + TokenKind::Percent + } + } + '!' => { if self.match_char('=') { TokenKind::BangEqual diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 4d7f75d..4fb196b 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -9,14 +9,14 @@ pub enum TokenKind { Colon, // 运算符 - Plus, Minus, Star, Slash, + Plus, Minus, Star, Slash, Percent, Bang, Equal, Greater, GreaterEqual, Less, LessEqual, EqualEqual, BangEqual, AndAnd, OrOr, - PlusEqual, MinusEqual, StarEqual, SlashEqual, + PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, // 字面量 Identifier(String), diff --git a/src/parser/parser.rs b/src/parser/parser.rs index a7c1b62..bcf18cf 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -212,6 +212,8 @@ impl Parser { Some(AssignOp::StarEqual) } else if self.match_kind(&[TokenKind::SlashEqual]) { Some(AssignOp::SlashEqual) + } else if self.match_kind(&[TokenKind::PercentEqual]) { + Some(AssignOp::PercentEqual) } else { None }; @@ -324,10 +326,11 @@ impl Parser { fn factor(&mut self) -> Expr { let mut expr = self.unary(); - while self.match_kind(&[TokenKind::Star, TokenKind::Slash]) { + while self.match_kind(&[TokenKind::Star, TokenKind::Slash, TokenKind::Percent]) { let op = match self.previous().kind { TokenKind::Star => BinaryOp::Mul, TokenKind::Slash => BinaryOp::Div, + TokenKind::Percent => BinaryOp::Mod, _ => unreachable!(), }; let right = self.unary();