diff --git a/grammar.txt b/grammar.txt index 74f34ad..1cf4006 100644 --- a/grammar.txt +++ b/grammar.txt @@ -13,13 +13,13 @@ | | | - | ::= "let" "=" ";" ::= { call "." } "=" ";" + | ";" ::= "fn" diff --git a/src/parse/mod.rs b/src/parse/mod.rs index e3b1b8d..e0a755b 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -75,9 +75,8 @@ impl<'code> Parser<'code> { TokenType::Return => self.return_stmt(), TokenType::BraceO => Ok(Stmt::Block(self.block()?)), _ => { - let expr = self.expression()?; - self.expect(TokenType::Semi)?; - Ok(Stmt::Expr(expr)) + let stmt = self.assignment()?; + Ok(stmt) } } } @@ -95,10 +94,6 @@ impl<'code> Parser<'code> { })) } - fn assignment(&mut self) -> ParseResult<'code, Stmt> { - todo!("oh god no") - } - fn fn_decl(&mut self) -> ParseResult<'code, Stmt> { let keyword_span = self.expect(TokenType::Fn)?.span; let name = self.ident()?; @@ -215,6 +210,24 @@ impl<'code> Parser<'code> { } } + fn assignment(&mut self) -> ParseResult<'code, Stmt> { + let expr = self.expression()?; + + if let Some(TokenType::Equal) = self.peek_kind() { + let _ = self.expect(TokenType::Equal)?; + let init = self.expression()?; + let semi_span = self.expect(TokenType::Semi)?.span; + Ok(Stmt::Assignment(Assignment { + span: expr.span().extend(semi_span), + lhs: expr, + rhs: init, + })) + } else { + let _ = self.expect(TokenType::Semi)?; + Ok(Stmt::Expr(expr)) + } + } + fn expression(&mut self) -> ParseResult<'code, Expr> { self.logical_or() } diff --git a/src/parse/test.rs b/src/parse/test.rs index 7b82396..89afac4 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -73,6 +73,63 @@ fn test_number_literal>) -> Expr>(parser: F) { assert_eq!(num_lit(10.0), unary); } +mod assignment { + use super::prelude::*; + + fn parse_assignment(tokens: Vec) -> Stmt { + let mut parser = parser(tokens); + parser.assignment().unwrap() + } + + #[test] + fn simple() { + let tokens = [Ident("hugo"), Equal, Number(10.0), Semi].map(token).into(); + let ast = parse_assignment(tokens); + assert_eq!( + Stmt::Assignment(Assignment { + span: Default::default(), + lhs: Expr::Ident(ident("hugo")), + rhs: num_lit(10.0) + }), + ast + ); + } + + #[test] + fn call_expr() { + let tokens = [ + Ident("hugo"), + Dot, + Ident("age"), + Equal, + Number(2021.0), + Minus, + Number(1986.0), + Semi, + ] + .map(token) + .into(); + let ast = parse_assignment(tokens); + assert_eq!( + Stmt::Assignment(Assignment { + span: Default::default(), + lhs: Expr::Call(Box::new(Call { + callee: Expr::Ident(ident("hugo")), + span: Default::default(), + kind: CallKind::Field(ident("age")) + })), + rhs: Expr::BinaryOp(Box::new(BinaryOp { + span: Default::default(), + lhs: num_lit(2021.0), + rhs: num_lit(1986.0), + kind: BinaryOpKind::Sub + })) + }), + ast + ); + } +} + mod r#fn { use super::prelude::*;