From 429615ae859335d70bb8d4b34fa92765726a952f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher?= Date: Fri, 8 Aug 2025 18:34:57 +0200 Subject: [PATCH] FIX: Fixes stringify with parentheses --- base/src/expressions/parser/stringify.rs | 81 +++++++++++++------ .../parser/tests/test_stringify.rs | 33 ++++++++ 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/base/src/expressions/parser/stringify.rs b/base/src/expressions/parser/stringify.rs index 62d4c12..cef7549 100644 --- a/base/src/expressions/parser/stringify.rs +++ b/base/src/expressions/parser/stringify.rs @@ -2,7 +2,7 @@ use super::{super::utils::quote_name, Node, Reference}; use crate::constants::{LAST_COLUMN, LAST_ROW}; use crate::expressions::parser::move_formula::to_string_array_node; use crate::expressions::parser::static_analysis::add_implicit_intersection; -use crate::expressions::token::OpUnary; +use crate::expressions::token::{OpSum, OpUnary}; use crate::{expressions::types::CellReferenceRC, number_format::to_excel_precision_str}; pub enum DisplaceData { @@ -483,34 +483,32 @@ fn stringify( kind, stringify(right, context, displace_data, export_to_excel) ), - OpSumKind { kind, left, right } => format!( - "{}{}{}", - stringify(left, context, displace_data, export_to_excel), - kind, - stringify(right, context, displace_data, export_to_excel) - ), + OpSumKind { kind, left, right } => { + let left_str = stringify(left, context, displace_data, export_to_excel); + // if kind is minus then we need parentheses in the right side if they are OpSumKind or CompareKind + let right_str = if (matches!(kind, OpSum::Minus) && matches!(**right, OpSumKind { .. })) + | matches!(**right, CompareKind { .. }) + { + format!( + "({})", + stringify(right, context, displace_data, export_to_excel) + ) + } else { + stringify(right, context, displace_data, export_to_excel) + }; + + format!("{left_str}{kind}{right_str}") + } OpProductKind { kind, left, right } => { let x = match **left { - OpSumKind { .. } => format!( - "({})", - stringify(left, context, displace_data, export_to_excel) - ), - CompareKind { .. } => format!( + OpSumKind { .. } | CompareKind { .. } => format!( "({})", stringify(left, context, displace_data, export_to_excel) ), _ => stringify(left, context, displace_data, export_to_excel), }; let y = match **right { - OpSumKind { .. } => format!( - "({})", - stringify(right, context, displace_data, export_to_excel) - ), - CompareKind { .. } => format!( - "({})", - stringify(right, context, displace_data, export_to_excel) - ), - OpProductKind { .. } => format!( + OpSumKind { .. } | CompareKind { .. } | OpProductKind { .. } => format!( "({})", stringify(right, context, displace_data, export_to_excel) ), @@ -621,10 +619,43 @@ fn stringify( WrongVariableKind(name) => name.to_string(), UnaryKind { kind, right } => match kind { OpUnary::Minus => { - format!( - "-{}", - stringify(right, context, displace_data, export_to_excel) - ) + let needs_parentheses = match **right { + BooleanKind(_) + | NumberKind(_) + | StringKind(_) + | ReferenceKind { .. } + | RangeKind { .. } + | WrongReferenceKind { .. } + | WrongRangeKind { .. } + | OpRangeKind { .. } + | OpConcatenateKind { .. } + | OpProductKind { .. } + | OpPowerKind { .. } + | FunctionKind { .. } + | InvalidFunctionKind { .. } + | ArrayKind(_) + | DefinedNameKind(_) + | TableNameKind(_) + | WrongVariableKind(_) + | ImplicitIntersection { .. } + | CompareKind { .. } + | ErrorKind(_) + | ParseErrorKind { .. } + | EmptyArgKind => false, + + OpSumKind { .. } | UnaryKind { .. } => true, + }; + if needs_parentheses { + format!( + "-({})", + stringify(right, context, displace_data, export_to_excel) + ) + } else { + format!( + "-{}", + stringify(right, context, displace_data, export_to_excel) + ) + } } OpUnary::Percentage => { format!( diff --git a/base/src/expressions/parser/tests/test_stringify.rs b/base/src/expressions/parser/tests/test_stringify.rs index 36dd3dc..4935cf3 100644 --- a/base/src/expressions/parser/tests/test_stringify.rs +++ b/base/src/expressions/parser/tests/test_stringify.rs @@ -32,3 +32,36 @@ fn exp_order() { let t = parser.parse("(5)^(4)", &cell_reference); assert_eq!(to_string(&t, &cell_reference), "5^4"); } + +#[test] +fn correct_parenthesis() { + let worksheets = vec!["Sheet1".to_string()]; + let mut parser = Parser::new(worksheets, vec![], HashMap::new()); + + let cell_reference = CellReferenceRC { + sheet: "Sheet1".to_string(), + row: 1, + column: 1, + }; + + let t = parser.parse("-(1 + 1)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "-(1+1)"); + + let t = parser.parse("1 - (3 + 4)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "1-(3+4)"); + + let t = parser.parse("-(1.05*(0.0284 + 0.0046) - 0.0284)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "-(1.05*(0.0284+0.0046)-0.0284)"); + + let t = parser.parse("1 + (3+5)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "1+3+5"); + + let t = parser.parse("1 - (3+5)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "1-(3+5)"); + + let t = parser.parse("(1 - 3) - (3+5)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "1-3-(3+5)"); + + let t = parser.parse("1 + (3<5)", &cell_reference); + assert_eq!(to_string(&t, &cell_reference), "1+(3<5)"); +}