diff --git a/src/parser.rs b/src/parser.rs index 4bf5ff32..e9fc9563 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -152,6 +152,8 @@ pub enum Token { Fn, Break, Return, + PlusEquals, + MinusEquals, LexErr(LexError), } @@ -350,8 +352,24 @@ impl<'a> Iterator for TokenIterator<'a> { ')' => return Some(Token::RParen), '[' => return Some(Token::LSquare), ']' => return Some(Token::RSquare), - '+' => return Some(Token::Plus), - '-' => return Some(Token::Minus), + '+' => { + return match self.char_stream.peek() { + Some(&'=') => { + self.char_stream.next(); + Some(Token::PlusEquals) + }, + _ => Some(Token::Plus) + } + }, + '-' => { + return match self.char_stream.peek() { + Some(&'=') => { + self.char_stream.next(); + Some(Token::MinusEquals) + }, + _ => Some(Token::Minus) + } + }, '*' => return Some(Token::Multiply), '/' => return Some(Token::Divide), ';' => return Some(Token::Semicolon), @@ -427,7 +445,9 @@ pub fn lex(input: &str) -> TokenIterator { fn get_precedence(token: &Token) -> i32 { match *token { - Token::Equals => 10, + Token::Equals + | Token::PlusEquals + | Token::MinusEquals => 10, Token::Or => 11, Token::And => 12, Token::LessThan @@ -458,7 +478,7 @@ fn parse_call_expr<'a>(id: String, input: &mut Peekable>) -> Result { let mut args = Vec::new(); - + if let Some(&Token::RParen) = input.peek() { input.next(); return Ok(Expr::FnCall(id, args)); @@ -609,6 +629,20 @@ fn parse_binop<'a>(input: &mut Peekable>, Token::Multiply => Expr::FnCall("*".to_string(), vec![lhs_curr, rhs]), Token::Divide => Expr::FnCall("/".to_string(), vec![lhs_curr, rhs]), Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)), + Token::PlusEquals => { + let lhs_copy = lhs_curr.clone(); + Expr::Assignment( + Box::new(lhs_curr), + Box::new(Expr::FnCall("+".to_string(), vec![lhs_copy, rhs])) + ) + }, + Token::MinusEquals => { + let lhs_copy = lhs_curr.clone(); + Expr::Assignment( + Box::new(lhs_curr), + Box::new(Expr::FnCall("-".to_string(), vec![lhs_copy, rhs])) + ) + }, Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)), Token::EqualTo => Expr::FnCall("==".to_string(), vec![lhs_curr, rhs]), Token::NotEqualTo => Expr::FnCall("!=".to_string(), vec![lhs_curr, rhs]), diff --git a/src/tests.rs b/src/tests.rs index 543c13f2..2a75a38d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -401,3 +401,37 @@ fn test_array_with_structs() { assert!(false); } } + +#[test] +fn test_increment() { + let mut engine = Engine::new(); + + if let Ok(result) = engine.eval::("let x = 1; x += 2; x") { + assert_eq!(result, 3); + } else { + assert!(false); + } + + if let Ok(result) = engine.eval::("let s = \"test\"; s += \"ing\"; s") { + assert_eq!(result, "testing".to_owned()); + } else { + assert!(false); + } +} + +#[test] +fn test_decrement() { + let mut engine = Engine::new(); + + if let Ok(result) = engine.eval::("let x = 10; x -= 7; x") { + assert_eq!(result, 3); + } else { + assert!(false); + } + + if let Ok(_) = engine.eval::("let s = \"test\"; s -= \"ing\"; s") { + assert!(false); + } else { + assert!(true); + } +} \ No newline at end of file