From 87951ab12ff2418983e248fdd774f0296186e218 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Mon, 29 Dec 2025 22:33:16 -0700 Subject: [PATCH] Support tuple assignment expressions and tuple assignments and declarations with function invocations --- rust_compiler/libs/parser/src/lib.rs | 40 +++++++++++++--- rust_compiler/libs/parser/src/test/mod.rs | 53 ++++++++++++++++++++++ rust_compiler/libs/parser/src/tree_node.rs | 20 ++++++++ 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/rust_compiler/libs/parser/src/lib.rs b/rust_compiler/libs/parser/src/lib.rs index c8b3340..1d7d0c3 100644 --- a/rust_compiler/libs/parser/src/lib.rs +++ b/rust_compiler/libs/parser/src/lib.rs @@ -1086,17 +1086,43 @@ impl<'a> Parser<'a> { end_col: right.span.end_col, }; + // Check if the left side is a tuple, and if so, create a TupleAssignment + let node = if let Expression::Tuple(tuple_expr) = &left.node { + // Extract variable names from the tuple, handling underscores + let mut names = Vec::new(); + for item in &tuple_expr.node { + if let Expression::Variable(var) = &item.node { + names.push(var.clone()); + } else { + return Err(Error::InvalidSyntax( + item.span, + String::from("Tuple assignment can only contain variable names"), + )); + } + } + + Expression::TupleAssignment(Spanned { + span, + node: TupleAssignmentExpression { + names, + value: boxed!(right), + }, + }) + } else { + Expression::Assignment(Spanned { + span, + node: AssignmentExpression { + assignee: boxed!(left), + expression: boxed!(right), + }, + }) + }; + expressions.insert( i, Spanned { span, - node: Expression::Assignment(Spanned { - span, - node: AssignmentExpression { - assignee: boxed!(left), - expression: boxed!(right), - }, - }), + node, }, ); } diff --git a/rust_compiler/libs/parser/src/test/mod.rs b/rust_compiler/libs/parser/src/test/mod.rs index eb5a3fc..ce91237 100644 --- a/rust_compiler/libs/parser/src/test/mod.rs +++ b/rust_compiler/libs/parser/src/test/mod.rs @@ -200,3 +200,56 @@ fn test_tuple_declaration() -> Result<()> { Ok(()) } +#[test] +fn test_tuple_assignment() -> Result<()> { + let expr = parser!("(x, y) = (1, 2);").parse()?.unwrap(); + + assert_eq!("((x, y) = (1, 2))", expr.to_string()); + + Ok(()) +} + +#[test] +fn test_tuple_assignment_with_underscore() -> Result<()> { + let expr = parser!("(x, _) = (1, 2);").parse()?.unwrap(); + + assert_eq!("((x, _) = (1, 2))", expr.to_string()); + + Ok(()) +} + +#[test] +fn test_tuple_declaration_with_function_call() -> Result<()> { + let expr = parser!("let (x, y) = doSomething();").parse()?.unwrap(); + + assert_eq!("(let (x, y) = doSomething())", expr.to_string()); + + Ok(()) +} + +#[test] +fn test_tuple_declaration_with_function_call_with_underscore() -> Result<()> { + let expr = parser!("let (x, _) = doSomething();").parse()?.unwrap(); + + assert_eq!("(let (x, _) = doSomething())", expr.to_string()); + + Ok(()) +} + +#[test] +fn test_tuple_assignment_with_function_call() -> Result<()> { + let expr = parser!("(x, y) = doSomething();").parse()?.unwrap(); + + assert_eq!("((x, y) = doSomething())", expr.to_string()); + + Ok(()) +} + +#[test] +fn test_tuple_assignment_with_function_call_with_underscore() -> Result<()> { + let expr = parser!("(x, _) = doSomething();").parse()?.unwrap(); + + assert_eq!("((x, _) = doSomething())", 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 1534c4f..3da1305 100644 --- a/rust_compiler/libs/parser/src/tree_node.rs +++ b/rust_compiler/libs/parser/src/tree_node.rs @@ -263,6 +263,24 @@ impl<'a> std::fmt::Display for TupleDeclarationExpression<'a> { } } +#[derive(Debug, PartialEq, Eq)] +pub struct TupleAssignmentExpression<'a> { + pub names: Vec>>, + pub value: Box>>, +} + +impl<'a> std::fmt::Display for TupleAssignmentExpression<'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, "(({}) = {})", names, self.value) + } +} + #[derive(Debug, PartialEq, Eq)] pub struct IfExpression<'a> { pub condition: Box>>, @@ -367,6 +385,7 @@ pub enum Expression<'a> { Syscall(Spanned>), Ternary(Spanned>), Tuple(Spanned>>>), + TupleAssignment(Spanned>), TupleDeclaration(Spanned>), Variable(Spanned>), While(Spanned>), @@ -413,6 +432,7 @@ impl<'a> std::fmt::Display for Expression<'a> { .join(", "); write!(f, "({})", items) } + Expression::TupleAssignment(e) => write!(f, "{}", e), Expression::TupleDeclaration(e) => write!(f, "{}", e), Expression::Variable(id) => write!(f, "{}", id), Expression::While(e) => write!(f, "{}", e),