diff --git a/rust_compiler/libs/parser/src/lib.rs b/rust_compiler/libs/parser/src/lib.rs index 63e8ec2..c8b3340 100644 --- a/rust_compiler/libs/parser/src/lib.rs +++ b/rust_compiler/libs/parser/src/lib.rs @@ -441,7 +441,13 @@ impl<'a> Parser<'a> { )); } - TokenType::Keyword(Keyword::Let) => Some(self.spanned(|p| p.declaration())?), + TokenType::Keyword(Keyword::Let) => { + if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) { + Some(self.spanned(|p| p.tuple_declaration())?) + } else { + Some(self.spanned(|p| p.declaration())?) + } + } TokenType::Keyword(Keyword::Device) => { let spanned_dev = self.spanned(|p| p.device())?; @@ -561,9 +567,7 @@ impl<'a> Parser<'a> { }) } - TokenType::Symbol(Symbol::LParen) => { - self.spanned(|p| p.priority())?.node.map(|node| *node) - } + TokenType::Symbol(Symbol::LParen) => self.parenthesized_or_tuple()?, TokenType::Symbol(Symbol::Minus) => { let start_span = self.current_span(); @@ -642,8 +646,8 @@ impl<'a> Parser<'a> { } } TokenType::Symbol(Symbol::LParen) => *self - .spanned(|p| p.priority())? - .node + .parenthesized_or_tuple()? + .map(Box::new) .ok_or(Error::UnexpectedEOF)?, TokenType::Identifier(ref id) if SysCall::is_syscall(id) => { @@ -774,7 +778,8 @@ impl<'a> Parser<'a> { | Expression::Ternary(_) | Expression::Negation(_) | Expression::MemberAccess(_) - | Expression::MethodCall(_) => {} + | Expression::MethodCall(_) + | Expression::Tuple(_) => {} _ => { return Err(Error::InvalidSyntax( self.current_span(), @@ -1117,8 +1122,12 @@ impl<'a> Parser<'a> { expressions.pop().ok_or(Error::UnexpectedEOF) } - fn priority(&mut self) -> Result>>>, Error<'a>> { + fn parenthesized_or_tuple( + &mut self, + ) -> Result>>, Error<'a>> { + let start_span = self.current_span(); let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; + if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( self.current_span(), @@ -1127,17 +1136,113 @@ impl<'a> Parser<'a> { } self.assign_next()?; - let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; - let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; - if !token_matches!(current_token, TokenType::Symbol(Symbol::RParen)) { - return Err(Error::UnexpectedToken( - Self::token_to_span(¤t_token), - current_token, - )); + // Handle empty tuple '()' + if self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { + self.assign_next()?; + let end_span = self.current_span(); + let span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: end_span.end_line, + end_col: end_span.end_col, + }; + return Ok(Some(Spanned { + span, + node: Expression::Tuple(Spanned { span, node: vec![] }), + })); } - Ok(Some(boxed!(expression))) + let first_expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; + + if self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) { + // It is a tuple + let mut items = vec![first_expression]; + while self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) { + // Next toekn is a comma, we need to consume it and advance 1 more time. + self.assign_next()?; + self.assign_next()?; + println!("{:?}", self.current_token); + items.push(self.expression()?.ok_or(Error::UnexpectedEOF)?); + } + + let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) { + return Err(Error::UnexpectedToken(Self::token_to_span(&next), next)); + } + + let end_span = Self::token_to_span(&next); + let span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: end_span.end_line, + end_col: end_span.end_col, + }; + + Ok(Some(Spanned { + span, + node: Expression::Tuple(Spanned { span, node: items }), + })) + } else { + // It is just priority + let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) { + return Err(Error::UnexpectedToken(Self::token_to_span(&next), next)); + } + + Ok(Some(Spanned { + span: first_expression.span, + node: Expression::Priority(boxed!(first_expression)), + })) + } + } + + fn tuple_declaration(&mut self) -> Result, Error<'a>> { + // 'let' is consumed before this call + // expect '(' + let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) { + return Err(Error::UnexpectedToken(Self::token_to_span(&next), next)); + } + + let mut names = Vec::new(); + while !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { + let token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + let span = Self::token_to_span(&token); + if let TokenType::Identifier(id) = token.token_type { + names.push(Spanned { span, node: id }); + } else { + return Err(Error::UnexpectedToken(span, token)); + } + + if self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) { + self.assign_next()?; + } + } + self.assign_next()?; // consume ')' + + let assign = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + + if !token_matches!(assign, TokenType::Symbol(Symbol::Assign)) { + return Err(Error::UnexpectedToken(Self::token_to_span(&assign), assign)); + } + + self.assign_next()?; // Consume the `=` + + let value = self.expression()?.ok_or(Error::UnexpectedEOF)?; + + let semi = self.get_next()?.ok_or(Error::UnexpectedEOF)?; + if !token_matches!(semi, TokenType::Symbol(Symbol::Semicolon)) { + return Err(Error::UnexpectedToken(Self::token_to_span(&semi), semi)); + } + + Ok(Expression::TupleDeclaration(Spanned { + span: names.first().map(|n| n.span).unwrap_or(value.span), + node: TupleDeclarationExpression { + names, + value: boxed!(value), + }, + })) } fn invocation(&mut self) -> Result, Error<'a>> { diff --git a/rust_compiler/libs/parser/src/test/mod.rs b/rust_compiler/libs/parser/src/test/mod.rs index fe27c43..eb5a3fc 100644 --- a/rust_compiler/libs/parser/src/test/mod.rs +++ b/rust_compiler/libs/parser/src/test/mod.rs @@ -112,7 +112,7 @@ fn test_function_invocation() -> Result<()> { #[test] fn test_priority_expression() -> Result<()> { let input = r#" - let x = (4); + let x = (4 + 3); "#; let tokenizer = Tokenizer::from(input); @@ -120,7 +120,7 @@ fn test_priority_expression() -> Result<()> { let expression = parser.parse()?.unwrap(); - assert_eq!("(let x = 4)", expression.to_string()); + assert_eq!("(let x = ((4 + 3)))", expression.to_string()); Ok(()) } @@ -137,7 +137,7 @@ fn test_binary_expression() -> Result<()> { assert_eq!("(((45 * 2) - (15 / 5)) + (5 ** 2))", expr.to_string()); let expr = parser!("(5 - 2) * 10;").parse()?.unwrap(); - assert_eq!("((5 - 2) * 10)", expr.to_string()); + assert_eq!("(((5 - 2)) * 10)", expr.to_string()); Ok(()) } @@ -170,7 +170,7 @@ fn test_ternary_expression() -> Result<()> { fn test_complex_binary_with_ternary() -> Result<()> { let expr = parser!("let i = (x ? 1 : 3) * 2;").parse()?.unwrap(); - assert_eq!("(let i = ((x ? 1 : 3) * 2))", expr.to_string()); + assert_eq!("(let i = (((x ? 1 : 3)) * 2))", expr.to_string()); Ok(()) } @@ -191,3 +191,12 @@ fn test_nested_ternary_right_associativity() -> Result<()> { assert_eq!("(let i = (a ? b : (c ? d : e)))", expr.to_string()); Ok(()) } + +#[test] +fn test_tuple_declaration() -> Result<()> { + let expr = parser!("let (x, _) = (1, 2);").parse()?.unwrap(); + + assert_eq!("(let (x, _) = (1, 2))", expr.to_string()); + + Ok(()) +} diff --git a/rust_compiler/libs/parser/src/tree_node.rs b/rust_compiler/libs/parser/src/tree_node.rs index 2f21aef..1534c4f 100644 --- a/rust_compiler/libs/parser/src/tree_node.rs +++ b/rust_compiler/libs/parser/src/tree_node.rs @@ -245,6 +245,24 @@ impl<'a> std::fmt::Display for DeviceDeclarationExpression<'a> { } } +#[derive(Debug, PartialEq, Eq)] +pub struct TupleDeclarationExpression<'a> { + pub names: Vec>>, + pub value: Box>>, +} + +impl<'a> std::fmt::Display for TupleDeclarationExpression<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let names = self + .names + .iter() + .map(|n| n.node.to_string()) + .collect::>() + .join(", "); + write!(f, "(let ({}) = {})", names, self.value) + } +} + #[derive(Debug, PartialEq, Eq)] pub struct IfExpression<'a> { pub condition: Box>>, @@ -348,6 +366,8 @@ pub enum Expression<'a> { Return(Option>>>), Syscall(Spanned>), Ternary(Spanned>), + Tuple(Spanned>>>), + TupleDeclaration(Spanned>), Variable(Spanned>), While(Spanned>), } @@ -384,8 +404,19 @@ impl<'a> std::fmt::Display for Expression<'a> { ), Expression::Syscall(e) => write!(f, "{}", e), Expression::Ternary(e) => write!(f, "{}", e), + Expression::Tuple(e) => { + let items = e + .node + .iter() + .map(|x| x.to_string()) + .collect::>() + .join(", "); + write!(f, "({})", items) + } + Expression::TupleDeclaration(e) => write!(f, "{}", e), Expression::Variable(id) => write!(f, "{}", id), Expression::While(e) => write!(f, "{}", e), } } } +