diff --git a/complexpr/src/eval.rs b/complexpr/src/eval.rs index 9bb0436..14f2659 100644 --- a/complexpr/src/eval.rs +++ b/complexpr/src/eval.rs @@ -273,15 +273,15 @@ pub fn eval_ident(token: &Token, env: EnvRef) -> Result { } } -fn compound_assignment_inner(l: Value, r: Value, op: &Token) -> Result { +fn compound_assignment_inner(l: &Value, r: &Value, op: &Token) -> Result { match op.ty { - TokenType::PlusEqual => &l + &r, - TokenType::MinusEqual => &l - &r, - TokenType::StarEqual => &l * &r, - TokenType::SlashEqual => &l / &r, - TokenType::PercentEqual => &l % &r, - TokenType::CaretEqual => l.pow(&r), - TokenType::DoubleSlashEqual => l.fracdiv(&r), + TokenType::PlusEqual => l + r, + TokenType::MinusEqual => l - r, + TokenType::StarEqual => l * r, + TokenType::SlashEqual => l / r, + TokenType::PercentEqual => l % r, + TokenType::CaretEqual => l.pow(r), + TokenType::DoubleSlashEqual => l.fracdiv(r), _ => todo!() // TODO more operations }.map_err(|e| RuntimeError::new(e, op.pos.clone())) } @@ -304,11 +304,10 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul .ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?; let r = eval_expr(rhs, env.clone())?; - let result = compound_assignment_inner(prev_value, r, op)?; + let result = compound_assignment_inner(&prev_value, &r, op)?; - env.borrow_mut() - .set(name, result.clone()).expect("unreachable"); - Ok(result) + env.borrow_mut().set(name, result.clone()).expect("unreachable"); + Ok(Value::Nil) } }, Expr::Index { lhs, index, pos } => { @@ -321,18 +320,28 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul } else { let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?; let r = eval_expr(rhs, env)?; - let result = compound_assignment_inner(prev_value, r, op)?; + let result = compound_assignment_inner(&prev_value, &r, op)?; l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?; - Ok(result) + Ok(Value::Nil) } }, Expr::FieldAccess { target, name, pos } => { let target = eval_expr(target, env.clone())?; - let r = eval_expr(rhs, env)?; if let Value::Struct(s) = target { if s.data.borrow().contains_key(name.as_ref()) { - s.data.borrow_mut().insert(name.to_string(), r.clone()); - Ok(r) + if op.ty == TokenType::Equal { + let r = eval_expr(rhs, env)?; + s.data.borrow_mut().insert(name.to_string(), r.clone()); + Ok(r) + } else { + let result = { + let prev_value = &s.data.borrow()[name.as_ref()]; + let r = eval_expr(rhs, env)?; + compound_assignment_inner(prev_value, &r, op)? + }; + s.data.borrow_mut().insert(name.to_string(), result); + Ok(Value::Nil) + } } else { Err(RuntimeError::new(format!("Struct {} does not have field {}", Value::Struct(s).repr(), name), pos.clone())) } diff --git a/complexpr/src/parser.rs b/complexpr/src/parser.rs index 1671d44..d2fed9b 100644 --- a/complexpr/src/parser.rs +++ b/complexpr/src/parser.rs @@ -155,16 +155,18 @@ impl Parser { } fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result { - if !req_semicolon { - return Ok(stmt) - } if self.at_end() { - self.err_on_eof()?; + if req_semicolon { + self.err_on_eof()?; + } else{ + return Ok(stmt) + } } - match self.expect(TokenType::Semicolon) { - (true, _) => Ok(stmt), - (false, _) => Err(self.mk_error("Missing semicolon after statement")) + match self.expect(TokenType::Semicolon).0 { + true => Ok(stmt), + false if !req_semicolon => Ok(stmt), + false => Err(self.mk_error("Missing semicolon after statement")) } } @@ -249,8 +251,23 @@ impl Parser { } let args = self.commalist(TokenType::RParen, Self::ident)?; self.err_on_eof()?; - let body = self.statement(false)?; - Ok(Stmt::Fn { name, args, body: Box::new(body) }) + if self.peek().ty == TokenType::LParen { + self.next(); + self.err_on_eof()?; + let body = self.assignment()?; + self.err_on_eof()?; + if !self.expect(TokenType::RParen).0 { + return Err(self.mk_error("Expected right parenthesis to close function body")) + } + Ok(Stmt::Fn { name, args, body: Box::new(Stmt::Expr {expr: body }) }) + } else if self.peek().ty == TokenType::LBrace { + self.next(); + self.err_on_eof()?; + let body = self.block()?; + Ok(Stmt::Fn { name, args, body: Box::new(body) }) + } else { + Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body")) + } } fn block(&mut self) -> Result { @@ -415,15 +432,14 @@ impl Parser { // dot notation for field access fn fieldaccess(&mut self) -> Result { - let target = self.suffix()?; - if !self.at_end() && self.peek().ty == TokenType::Dot { + let mut target = self.suffix()?; + while !self.at_end() && self.peek().ty == TokenType::Dot { let pos = self.next().pos; self.err_on_eof()?; let name = self.ident()?.ty.as_ident().unwrap(); - Ok(Expr::FieldAccess { target: Box::new(target), name, pos }) - } else { - Ok(target) - } + target = Expr::FieldAccess { target: Box::new(target), name, pos } + } + Ok(target) } // function calls, array access, struct initializaiton @@ -531,8 +547,23 @@ impl Parser { } let args = self.commalist(TokenType::RParen, Self::ident)?; self.err_on_eof()?; - let body = self.statement(false)?; - Ok(Expr::Fn { args, body: Box::new(body) }) + if self.peek().ty == TokenType::LParen { + self.next(); + self.err_on_eof()?; + let body = self.assignment()?; + self.err_on_eof()?; + if !self.expect(TokenType::RParen).0 { + return Err(self.mk_error("Expected right parenthesis to close function body")) + } + Ok(Expr::Fn { args, body: Box::new(Stmt::Expr {expr: body }) }) + } else if self.peek().ty == TokenType::LBrace { + self.next(); + self.err_on_eof()?; + let body = self.block()?; + Ok(Expr::Fn { args, body: Box::new(body) }) + } else { + Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body")) + } } else { Err(self.mk_error(format!("Unexpected token: {:?}", next.ty))) }