1use super::{super::utils::quote_name, Node, Reference};
2use crate::constants::{LAST_COLUMN, LAST_ROW};
3use crate::expressions::parser::move_formula::to_string_array_node;
4use crate::expressions::parser::static_analysis::remove_redundant_implicit_intersection;
5use crate::expressions::token::{OpSum, OpUnary};
6use crate::functions::Function;
7use crate::language::{get_language, Language};
8use crate::locale::{get_locale, Locale};
9use crate::{expressions::types::CellReferenceRC, number_format::to_excel_precision_str};
10
11pub enum DisplaceData {
12 Column {
13 sheet: u32,
14 column: i32,
15 delta: i32,
16 },
17 Row {
18 sheet: u32,
19 row: i32,
20 delta: i32,
21 },
22 CellHorizontal {
23 sheet: u32,
24 row: i32,
25 column: i32,
26 delta: i32,
27 },
28 CellVertical {
29 sheet: u32,
30 row: i32,
31 column: i32,
32 delta: i32,
33 },
34 RowMove {
35 sheet: u32,
36 row: i32,
37 delta: i32,
38 },
39 ColumnMove {
40 sheet: u32,
41 column: i32,
42 delta: i32,
43 },
44 None,
45}
46
47pub fn to_rc_format(node: &Node) -> String {
50 #[allow(clippy::expect_used)]
51 let locale = get_locale("en").expect("");
52 #[allow(clippy::expect_used)]
53 let language = get_language("en").expect("");
54 stringify(node, None, &DisplaceData::None, false, locale, language)
55}
56
57pub fn to_english_string(node: &Node, context: &CellReferenceRC) -> String {
58 #[allow(clippy::expect_used)]
59 let locale = get_locale("en").expect("");
60 #[allow(clippy::expect_used)]
61 let language = get_language("en").expect("");
62 stringify(
63 node,
64 Some(context),
65 &DisplaceData::None,
66 false,
67 locale,
68 language,
69 )
70}
71
72pub fn to_localized_string(
74 node: &Node,
75 context: &CellReferenceRC,
76 locale: &Locale,
77 language: &Language,
78) -> String {
79 stringify(
80 node,
81 Some(context),
82 &DisplaceData::None,
83 false,
84 locale,
85 language,
86 )
87}
88
89pub fn to_excel_string(node: &Node, context: &CellReferenceRC) -> String {
92 excel_string(node, context, false)
93}
94
95pub fn to_excel_array_formula_string(node: &Node, context: &CellReferenceRC) -> String {
101 excel_string(node, context, true)
102}
103
104fn excel_string(node: &Node, context: &CellReferenceRC, is_array_formula: bool) -> String {
105 #[allow(clippy::expect_used)]
106 let locale = get_locale("en").expect("");
107 #[allow(clippy::expect_used)]
108 let language = get_language("en").expect("");
109 let mut node = node.clone();
114 if !is_array_formula {
115 remove_redundant_implicit_intersection(&mut node, true);
116 }
117 prefix_bound_variables(&mut node, &mut Vec::new());
118 stringify(
119 &node,
120 Some(context),
121 &DisplaceData::None,
122 true,
123 locale,
124 language,
125 )
126}
127
128fn prefix_bound_variables(node: &mut Node, bound: &mut Vec<String>) {
137 match node {
138 Node::NamedVariableKind { name, .. } => {
139 if bound.iter().any(|n| n == name) {
140 *name = format!("_xlpm.{name}");
141 }
142 }
143 Node::NamedFunctionKind { name, args, .. } => {
145 if bound.iter().any(|n| n == name) {
146 *name = format!("_xlpm.{name}");
147 }
148 for arg in args {
149 prefix_bound_variables(arg, bound);
150 }
151 }
152 Node::LambdaDefKind { parameters, body } => {
153 let depth = bound.len();
154 for parameter in parameters.iter() {
155 bound.push(parameter.name.clone());
156 }
157 prefix_bound_variables(body, bound);
158 bound.truncate(depth);
159 }
160 Node::FunctionKind {
161 kind: Function::Let,
162 args,
163 } if args.len() >= 3 && args.len() % 2 == 1 => {
164 let depth = bound.len();
167 let pair_count = (args.len() - 1) / 2;
168 for i in 0..pair_count {
169 if let Node::NamedVariableKind { name, .. } = &mut args[2 * i] {
170 bound.push(name.clone());
171 *name = format!("_xlpm.{name}");
172 }
173 prefix_bound_variables(&mut args[2 * i + 1], bound);
174 }
175 prefix_bound_variables(&mut args[2 * pair_count], bound);
176 bound.truncate(depth);
177 }
178 Node::FunctionKind { args, .. } => {
179 for arg in args {
180 prefix_bound_variables(arg, bound);
181 }
182 }
183 Node::LambdaCallKind { lambda, args } => {
184 prefix_bound_variables(lambda, bound);
185 for arg in args {
186 prefix_bound_variables(arg, bound);
187 }
188 }
189 Node::OpRangeKind { left, right }
190 | Node::OpConcatenateKind { left, right }
191 | Node::OpSumKind { left, right, .. }
192 | Node::OpProductKind { left, right, .. }
193 | Node::OpPowerKind { left, right }
194 | Node::CompareKind { left, right, .. } => {
195 prefix_bound_variables(left, bound);
196 prefix_bound_variables(right, bound);
197 }
198 Node::UnaryKind { right, .. } => prefix_bound_variables(right, bound),
199 Node::ImplicitIntersection { child, .. } | Node::SpillRangeOperator { child } => {
200 prefix_bound_variables(child, bound)
201 }
202 Node::BooleanKind(_)
203 | Node::NumberKind(_)
204 | Node::StringKind(_)
205 | Node::ReferenceKind { .. }
206 | Node::RangeKind { .. }
207 | Node::WrongReferenceKind { .. }
208 | Node::WrongRangeKind { .. }
209 | Node::ArrayKind(_)
210 | Node::DefinedNameKind(_)
211 | Node::TableNameKind(_)
212 | Node::ErrorKind(_)
213 | Node::ParseErrorKind { .. }
214 | Node::EmptyArgKind => {}
215 }
216}
217
218pub fn to_string_displaced(
219 node: &Node,
220 context: &CellReferenceRC,
221 displace_data: &DisplaceData,
222 locale: &Locale,
223 language: &Language,
224) -> String {
225 stringify(node, Some(context), displace_data, false, locale, language)
226}
227
228pub(crate) fn stringify_reference(
233 context: Option<&CellReferenceRC>,
234 displace_data: &DisplaceData,
235 reference: &Reference,
236 full_row: bool,
237 full_column: bool,
238) -> String {
239 let sheet_name = reference.sheet_name;
240 let sheet_index = reference.sheet_index;
241 let absolute_row = reference.absolute_row;
242 let absolute_column = reference.absolute_column;
243 let row = reference.row;
244 let column = reference.column;
245 match context {
246 Some(context) => {
247 let mut row = if absolute_row { row } else { row + context.row };
248 let mut column = if absolute_column {
249 column
250 } else {
251 column + context.column
252 };
253 match displace_data {
254 DisplaceData::Row {
255 sheet,
256 row: displace_row,
257 delta,
258 } => {
259 if sheet_index == *sheet && !full_row {
260 if *delta < 0 {
261 if &row >= displace_row {
262 if row < displace_row - *delta {
263 return "#REF!".to_string();
264 }
265 row += *delta;
266 }
267 } else if &row >= displace_row {
268 row += *delta;
269 }
270 }
271 }
272 DisplaceData::Column {
273 sheet,
274 column: displace_column,
275 delta,
276 } => {
277 if sheet_index == *sheet && !full_column {
278 if *delta < 0 {
279 if &column >= displace_column {
280 if column < displace_column - *delta {
281 return "#REF!".to_string();
282 }
283 column += *delta;
284 }
285 } else if &column >= displace_column {
286 column += *delta;
287 }
288 }
289 }
290 DisplaceData::CellHorizontal {
291 sheet,
292 row: displace_row,
293 column: displace_column,
294 delta,
295 } => {
296 if sheet_index == *sheet && displace_row == &row {
297 if *delta < 0 {
298 if &column >= displace_column {
299 if column < displace_column - *delta {
300 return "#REF!".to_string();
301 }
302 column += *delta;
303 }
304 } else if &column >= displace_column {
305 column += *delta;
306 }
307 }
308 }
309 DisplaceData::CellVertical {
310 sheet,
311 row: displace_row,
312 column: displace_column,
313 delta,
314 } => {
315 if sheet_index == *sheet && displace_column == &column {
316 if *delta < 0 {
317 if &row >= displace_row {
318 if row < displace_row - *delta {
319 return "#REF!".to_string();
320 }
321 row += *delta;
322 }
323 } else if &row >= displace_row {
324 row += *delta;
325 }
326 }
327 }
328 DisplaceData::RowMove {
329 sheet,
330 row: move_row,
331 delta,
332 } => {
333 if sheet_index == *sheet {
334 if row == *move_row {
335 row += *delta;
336 } else if *delta > 0 {
337 if row > *move_row && row <= *move_row + *delta {
339 row -= 1;
341 }
342 } else if *delta < 0 {
343 if row < *move_row && row >= *move_row + *delta {
345 row += 1;
347 }
348 }
349 }
350 }
351 DisplaceData::ColumnMove {
352 sheet,
353 column: move_column,
354 delta,
355 } => {
356 if sheet_index == *sheet {
357 if column == *move_column {
358 column += *delta;
359 } else if *delta > 0 {
360 if column > *move_column && column <= *move_column + *delta {
362 column -= 1;
364 }
365 } else if *delta < 0 {
366 if column < *move_column && column >= *move_column + *delta {
368 column += 1;
370 }
371 }
372 }
373 }
374 DisplaceData::None => {}
375 }
376 if row < 1 {
377 return "#REF!".to_string();
378 }
379 let mut row_abs = if absolute_row {
380 format!("${row}")
381 } else {
382 format!("{row}")
383 };
384 let column = match crate::expressions::utils::number_to_column(column) {
385 Some(s) => s,
386 None => return "#REF!".to_string(),
387 };
388 let mut col_abs = if absolute_column {
389 format!("${column}")
390 } else {
391 column
392 };
393 if full_row {
394 row_abs = "".to_string()
395 }
396 if full_column {
397 col_abs = "".to_string()
398 }
399 match &sheet_name {
400 Some(name) => {
401 format!("{}!{}{}", quote_name(name), col_abs, row_abs)
402 }
403 None => {
404 format!("{col_abs}{row_abs}")
405 }
406 }
407 }
408 None => {
409 let row_abs = if absolute_row {
410 format!("R{row}")
411 } else {
412 format!("R[{row}]")
413 };
414 let col_abs = if absolute_column {
415 format!("C{column}")
416 } else {
417 format!("C[{column}]")
418 };
419 match &sheet_name {
420 Some(name) => {
421 format!("{}!{}{}", quote_name(name), row_abs, col_abs)
422 }
423 None => {
424 format!("{row_abs}{col_abs}")
425 }
426 }
427 }
428 }
429}
430
431fn format_function(
432 name: &str,
433 args: &Vec<Node>,
434 context: Option<&CellReferenceRC>,
435 displace_data: &DisplaceData,
436 export_to_excel: bool,
437 locale: &Locale,
438 language: &Language,
439) -> String {
440 let mut first = true;
441 let mut arguments = "".to_string();
442 let arg_separator = if locale.numbers.symbols.decimal == "." {
443 ','
444 } else {
445 ';'
446 };
447 for el in args {
448 if !first {
449 arguments = format!(
450 "{}{}{}",
451 arguments,
452 arg_separator,
453 stringify(
454 el,
455 context,
456 displace_data,
457 export_to_excel,
458 locale,
459 language
460 )
461 );
462 } else {
463 first = false;
464 arguments = stringify(
465 el,
466 context,
467 displace_data,
468 export_to_excel,
469 locale,
470 language,
471 );
472 }
473 }
474 format!("{name}({arguments})")
475}
476
477fn stringify(
503 node: &Node,
504 context: Option<&CellReferenceRC>,
505 displace_data: &DisplaceData,
506 export_to_excel: bool,
507 locale: &Locale,
508 language: &Language,
509) -> String {
510 use self::Node::*;
511 match node {
512 BooleanKind(value) => {
513 if *value {
514 language.booleans.r#true.to_string()
515 } else {
516 language.booleans.r#false.to_string()
517 }
518 }
519 NumberKind(number) => {
520 let s = to_excel_precision_str(*number);
521 if locale.numbers.symbols.decimal == "." {
522 s
523 } else {
524 s.replace(".", &locale.numbers.symbols.decimal)
525 }
526 }
527 StringKind(value) => format!("\"{value}\""),
528 WrongReferenceKind {
529 sheet_name,
530 column,
531 row,
532 absolute_row,
533 absolute_column,
534 } => stringify_reference(
535 context,
536 &DisplaceData::None,
537 &Reference {
538 sheet_name,
539 sheet_index: 0,
540 row: *row,
541 column: *column,
542 absolute_row: *absolute_row,
543 absolute_column: *absolute_column,
544 },
545 false,
546 false,
547 ),
548 ReferenceKind {
549 sheet_name,
550 sheet_index,
551 column,
552 row,
553 absolute_row,
554 absolute_column,
555 } => stringify_reference(
556 context,
557 displace_data,
558 &Reference {
559 sheet_name,
560 sheet_index: *sheet_index,
561 row: *row,
562 column: *column,
563 absolute_row: *absolute_row,
564 absolute_column: *absolute_column,
565 },
566 false,
567 false,
568 ),
569 RangeKind {
570 sheet_name,
571 sheet_index,
572 absolute_row1,
573 absolute_column1,
574 row1,
575 column1,
576 absolute_row2,
577 absolute_column2,
578 row2,
579 column2,
580 } => {
581 let full_row = *absolute_row1 && *absolute_row2 && (*row1 == 1) && (*row2 == LAST_ROW);
585 let full_column = *absolute_column1
586 && *absolute_column2
587 && (*column1 == 1)
588 && (*column2 == LAST_COLUMN);
589 let s1 = stringify_reference(
590 context,
591 displace_data,
592 &Reference {
593 sheet_name,
594 sheet_index: *sheet_index,
595 row: *row1,
596 column: *column1,
597 absolute_row: *absolute_row1,
598 absolute_column: *absolute_column1,
599 },
600 full_row,
601 full_column,
602 );
603 let s2 = stringify_reference(
604 context,
605 displace_data,
606 &Reference {
607 sheet_name: &None,
608 sheet_index: *sheet_index,
609 row: *row2,
610 column: *column2,
611 absolute_row: *absolute_row2,
612 absolute_column: *absolute_column2,
613 },
614 full_row,
615 full_column,
616 );
617 format!("{s1}:{s2}")
618 }
619 WrongRangeKind {
620 sheet_name,
621 absolute_row1,
622 absolute_column1,
623 row1,
624 column1,
625 absolute_row2,
626 absolute_column2,
627 row2,
628 column2,
629 } => {
630 let full_row = *absolute_row1 && *absolute_row2 && (*row1 == 1) && (*row2 == LAST_ROW);
634 let full_column = *absolute_column1
635 && *absolute_column2
636 && (*column1 == 1)
637 && (*column2 == LAST_COLUMN);
638 let s1 = stringify_reference(
639 context,
640 &DisplaceData::None,
641 &Reference {
642 sheet_name,
643 sheet_index: 0, row: *row1,
645 column: *column1,
646 absolute_row: *absolute_row1,
647 absolute_column: *absolute_column1,
648 },
649 full_row,
650 full_column,
651 );
652 let s2 = stringify_reference(
653 context,
654 &DisplaceData::None,
655 &Reference {
656 sheet_name: &None,
657 sheet_index: 0, row: *row2,
659 column: *column2,
660 absolute_row: *absolute_row2,
661 absolute_column: *absolute_column2,
662 },
663 full_row,
664 full_column,
665 );
666 format!("{s1}:{s2}")
667 }
668 OpRangeKind { left, right } => format!(
669 "{}:{}",
670 stringify(
671 left,
672 context,
673 displace_data,
674 export_to_excel,
675 locale,
676 language
677 ),
678 stringify(
679 right,
680 context,
681 displace_data,
682 export_to_excel,
683 locale,
684 language
685 )
686 ),
687 OpConcatenateKind { left, right } => format!(
688 "{}&{}",
689 stringify(
690 left,
691 context,
692 displace_data,
693 export_to_excel,
694 locale,
695 language
696 ),
697 stringify(
698 right,
699 context,
700 displace_data,
701 export_to_excel,
702 locale,
703 language
704 )
705 ),
706 CompareKind { kind, left, right } => format!(
707 "{}{}{}",
708 stringify(
709 left,
710 context,
711 displace_data,
712 export_to_excel,
713 locale,
714 language
715 ),
716 kind,
717 stringify(
718 right,
719 context,
720 displace_data,
721 export_to_excel,
722 locale,
723 language
724 )
725 ),
726 OpSumKind { kind, left, right } => {
727 let left_str = if matches!(**left, CompareKind { .. }) {
729 format!(
730 "({})",
731 stringify(
732 left,
733 context,
734 displace_data,
735 export_to_excel,
736 locale,
737 language
738 )
739 )
740 } else {
741 stringify(
742 left,
743 context,
744 displace_data,
745 export_to_excel,
746 locale,
747 language,
748 )
749 };
750 let right_str = if (matches!(kind, OpSum::Minus) && matches!(**right, OpSumKind { .. }))
752 | matches!(**right, CompareKind { .. })
753 {
754 format!(
755 "({})",
756 stringify(
757 right,
758 context,
759 displace_data,
760 export_to_excel,
761 locale,
762 language
763 )
764 )
765 } else {
766 stringify(
767 right,
768 context,
769 displace_data,
770 export_to_excel,
771 locale,
772 language,
773 )
774 };
775
776 format!("{left_str}{kind}{right_str}")
777 }
778 OpProductKind { kind, left, right } => {
779 let x = match **left {
780 OpSumKind { .. } | CompareKind { .. } => format!(
781 "({})",
782 stringify(
783 left,
784 context,
785 displace_data,
786 export_to_excel,
787 locale,
788 language
789 )
790 ),
791 _ => stringify(
792 left,
793 context,
794 displace_data,
795 export_to_excel,
796 locale,
797 language,
798 ),
799 };
800 let y = match **right {
801 OpSumKind { .. } | CompareKind { .. } | OpProductKind { .. } => format!(
802 "({})",
803 stringify(
804 right,
805 context,
806 displace_data,
807 export_to_excel,
808 locale,
809 language
810 )
811 ),
812 _ => stringify(
813 right,
814 context,
815 displace_data,
816 export_to_excel,
817 locale,
818 language,
819 ),
820 };
821 format!("{x}{kind}{y}")
822 }
823 OpPowerKind { left, right } => {
824 let x = match **left {
825 BooleanKind(_)
826 | NumberKind(_)
827 | UnaryKind { .. }
828 | StringKind(_)
829 | ReferenceKind { .. }
830 | RangeKind { .. }
831 | WrongReferenceKind { .. }
832 | DefinedNameKind(_)
833 | TableNameKind(_)
834 | NamedVariableKind { .. }
835 | WrongRangeKind { .. } => stringify(
836 left,
837 context,
838 displace_data,
839 export_to_excel,
840 locale,
841 language,
842 ),
843 OpRangeKind { .. }
844 | OpConcatenateKind { .. }
845 | OpProductKind { .. }
846 | OpPowerKind { .. }
847 | FunctionKind { .. }
848 | NamedFunctionKind { .. }
849 | LambdaDefKind { .. }
850 | LambdaCallKind { .. }
851 | ArrayKind(_)
852 | ErrorKind(_)
853 | ParseErrorKind { .. }
854 | OpSumKind { .. }
855 | CompareKind { .. }
856 | ImplicitIntersection { .. }
857 | SpillRangeOperator { .. }
858 | EmptyArgKind => format!(
859 "({})",
860 stringify(
861 left,
862 context,
863 displace_data,
864 export_to_excel,
865 locale,
866 language
867 )
868 ),
869 };
870 let y = match **right {
871 BooleanKind(_)
872 | NumberKind(_)
873 | StringKind(_)
874 | ReferenceKind { .. }
875 | RangeKind { .. }
876 | WrongReferenceKind { .. }
877 | DefinedNameKind(_)
878 | TableNameKind(_)
879 | NamedVariableKind { .. }
880 | WrongRangeKind { .. } => stringify(
881 right,
882 context,
883 displace_data,
884 export_to_excel,
885 locale,
886 language,
887 ),
888 OpRangeKind { .. }
889 | OpConcatenateKind { .. }
890 | OpProductKind { .. }
891 | OpPowerKind { .. }
892 | FunctionKind { .. }
893 | NamedFunctionKind { .. }
894 | LambdaDefKind { .. }
895 | LambdaCallKind { .. }
896 | ArrayKind(_)
897 | UnaryKind { .. }
898 | ErrorKind(_)
899 | ParseErrorKind { .. }
900 | OpSumKind { .. }
901 | CompareKind { .. }
902 | ImplicitIntersection { .. }
903 | SpillRangeOperator { .. }
904 | EmptyArgKind => format!(
905 "({})",
906 stringify(
907 right,
908 context,
909 displace_data,
910 export_to_excel,
911 locale,
912 language
913 )
914 ),
915 };
916 format!("{x}^{y}")
917 }
918 NamedFunctionKind { name, args, id: _ } => format_function(
919 &name.to_lowercase(),
920 args,
921 context,
922 displace_data,
923 export_to_excel,
924 locale,
925 language,
926 ),
927 FunctionKind { kind, args } => {
928 let name = if export_to_excel {
929 kind.to_xlsx_string()
930 } else {
931 kind.to_localized_name(language)
932 };
933 format_function(
934 &name,
935 args,
936 context,
937 displace_data,
938 export_to_excel,
939 locale,
940 language,
941 )
942 }
943 ArrayKind(args) => {
944 let mut first_row = true;
945 let mut matrix_string = String::new();
946 let row_separator = if locale.numbers.symbols.decimal == "." {
947 ';'
948 } else {
949 '/'
950 };
951 let col_separator = if row_separator == ';' { ',' } else { ';' };
952
953 for row in args {
954 if !first_row {
955 matrix_string.push(row_separator);
956 } else {
957 first_row = false;
958 }
959 let mut first_column = true;
960 let mut row_string = String::new();
961 for el in row {
962 if !first_column {
963 row_string.push(col_separator);
964 } else {
965 first_column = false;
966 }
967 row_string.push_str(&to_string_array_node(el, locale, language));
968 }
969 matrix_string.push_str(&row_string);
970 }
971 format!("{{{matrix_string}}}")
972 }
973 TableNameKind(value) => value.to_string(),
974 DefinedNameKind((name, ..)) => name.to_string(),
975 NamedVariableKind { name, id: _ } => name.to_string(),
976 UnaryKind { kind, right } => match kind {
977 OpUnary::Minus => {
978 let needs_parentheses = match **right {
979 BooleanKind(_)
980 | NumberKind(_)
981 | StringKind(_)
982 | ReferenceKind { .. }
983 | RangeKind { .. }
984 | WrongReferenceKind { .. }
985 | WrongRangeKind { .. }
986 | OpRangeKind { .. }
987 | OpProductKind { .. }
988 | FunctionKind { .. }
989 | NamedFunctionKind { .. }
990 | LambdaDefKind { .. }
991 | LambdaCallKind { .. }
992 | ArrayKind(_)
993 | DefinedNameKind(_)
994 | TableNameKind(_)
995 | NamedVariableKind { .. }
996 | ImplicitIntersection { .. }
997 | SpillRangeOperator { .. }
998 | ErrorKind(_)
999 | ParseErrorKind { .. }
1000 | EmptyArgKind => false,
1001
1002 UnaryKind {
1004 kind: OpUnary::Minus,
1005 ..
1006 } => false,
1007
1008 OpPowerKind { .. }
1010 | OpSumKind { .. }
1011 | OpConcatenateKind { .. }
1012 | CompareKind { .. }
1013 | UnaryKind { .. } => true,
1014 };
1015 if needs_parentheses {
1016 format!(
1017 "-({})",
1018 stringify(
1019 right,
1020 context,
1021 displace_data,
1022 export_to_excel,
1023 locale,
1024 language
1025 )
1026 )
1027 } else {
1028 format!(
1029 "-{}",
1030 stringify(
1031 right,
1032 context,
1033 displace_data,
1034 export_to_excel,
1035 locale,
1036 language
1037 )
1038 )
1039 }
1040 }
1041 OpUnary::Percentage => {
1042 format!(
1043 "{}%",
1044 stringify(
1045 right,
1046 context,
1047 displace_data,
1048 export_to_excel,
1049 locale,
1050 language
1051 )
1052 )
1053 }
1054 },
1055 ErrorKind(kind) => format!("{kind}"),
1056 ParseErrorKind { formula, .. } => formula.to_string(),
1057 EmptyArgKind => "".to_string(),
1058 SpillRangeOperator { child } => {
1059 if export_to_excel {
1060 return format!(
1061 "_xlfn.ANCHORARRAY({})",
1062 stringify(
1063 child,
1064 context,
1065 displace_data,
1066 export_to_excel,
1067 locale,
1068 language
1069 )
1070 );
1071 };
1072 format!(
1073 "{}#",
1074 stringify(
1075 child,
1076 context,
1077 displace_data,
1078 export_to_excel,
1079 locale,
1080 language
1081 )
1082 )
1083 }
1084 LambdaDefKind { parameters, body } => {
1085 let lambda_name = if export_to_excel {
1086 "_xlfn.LAMBDA"
1087 } else {
1088 "LAMBDA"
1089 };
1090 let arg_sep = if locale.numbers.symbols.decimal == "." {
1091 ","
1092 } else {
1093 ";"
1094 };
1095 let mut parts: Vec<String> = parameters
1096 .iter()
1097 .map(|p| {
1098 if export_to_excel {
1099 if p.is_optional {
1100 format!("_xlop.{}", p.name)
1101 } else {
1102 format!("_xlpm.{}", p.name)
1103 }
1104 } else if p.is_optional {
1105 format!("[{}]", p.name)
1106 } else {
1107 p.name.clone()
1108 }
1109 })
1110 .collect();
1111 parts.push(stringify(
1112 body,
1113 context,
1114 displace_data,
1115 export_to_excel,
1116 locale,
1117 language,
1118 ));
1119 format!("{}({})", lambda_name, parts.join(arg_sep))
1120 }
1121 LambdaCallKind { lambda, args } => {
1122 let arg_sep = if locale.numbers.symbols.decimal == "." {
1123 ","
1124 } else {
1125 ";"
1126 };
1127 let lambda_str = match lambda.as_ref() {
1131 Node::NamedVariableKind { name, id: _ } => name.to_lowercase(),
1132 other => stringify(
1133 other,
1134 context,
1135 displace_data,
1136 export_to_excel,
1137 locale,
1138 language,
1139 ),
1140 };
1141 let call_args: Vec<String> = args
1142 .iter()
1143 .map(|a| stringify(a, context, displace_data, export_to_excel, locale, language))
1144 .collect();
1145 format!("{}({})", lambda_str, call_args.join(arg_sep))
1146 }
1147 ImplicitIntersection {
1148 automatic: _,
1149 child,
1150 } => {
1151 if export_to_excel {
1152 return format!(
1156 "_xlfn.SINGLE({})",
1157 stringify(
1158 child,
1159 context,
1160 displace_data,
1161 export_to_excel,
1162 locale,
1163 language
1164 )
1165 );
1166 }
1167 format!(
1168 "@{}",
1169 stringify(
1170 child,
1171 context,
1172 displace_data,
1173 export_to_excel,
1174 locale,
1175 language
1176 )
1177 )
1178 }
1179 }
1180}
1181
1182pub(crate) fn rename_sheet_in_node(node: &mut Node, sheet_index: u32, new_name: &str) {
1183 match node {
1184 Node::ReferenceKind {
1186 sheet_name,
1187 sheet_index: index,
1188 ..
1189 } => {
1190 if *index == sheet_index && sheet_name.is_some() {
1191 *sheet_name = Some(new_name.to_owned());
1192 }
1193 }
1194 Node::RangeKind {
1195 sheet_name,
1196 sheet_index: index,
1197 ..
1198 } => {
1199 if *index == sheet_index && sheet_name.is_some() {
1200 *sheet_name = Some(new_name.to_owned());
1201 }
1202 }
1203 Node::WrongReferenceKind { sheet_name, .. } => {
1204 if let Some(name) = sheet_name {
1205 if name.to_uppercase() == new_name.to_uppercase() {
1206 *sheet_name = Some(name.to_owned())
1207 }
1208 }
1209 }
1210 Node::WrongRangeKind { sheet_name, .. } => {
1211 if sheet_name.is_some() {
1212 *sheet_name = Some(new_name.to_owned());
1213 }
1214 }
1215
1216 Node::OpRangeKind { left, right } => {
1218 rename_sheet_in_node(left, sheet_index, new_name);
1219 rename_sheet_in_node(right, sheet_index, new_name);
1220 }
1221 Node::OpConcatenateKind { left, right } => {
1222 rename_sheet_in_node(left, sheet_index, new_name);
1223 rename_sheet_in_node(right, sheet_index, new_name);
1224 }
1225 Node::OpSumKind {
1226 kind: _,
1227 left,
1228 right,
1229 } => {
1230 rename_sheet_in_node(left, sheet_index, new_name);
1231 rename_sheet_in_node(right, sheet_index, new_name);
1232 }
1233 Node::OpProductKind {
1234 kind: _,
1235 left,
1236 right,
1237 } => {
1238 rename_sheet_in_node(left, sheet_index, new_name);
1239 rename_sheet_in_node(right, sheet_index, new_name);
1240 }
1241 Node::OpPowerKind { left, right } => {
1242 rename_sheet_in_node(left, sheet_index, new_name);
1243 rename_sheet_in_node(right, sheet_index, new_name);
1244 }
1245 Node::FunctionKind { kind: _, args } => {
1246 for arg in args {
1247 rename_sheet_in_node(arg, sheet_index, new_name);
1248 }
1249 }
1250 Node::NamedFunctionKind {
1251 name: _,
1252 args,
1253 id: _,
1254 } => {
1255 for arg in args {
1256 rename_sheet_in_node(arg, sheet_index, new_name);
1257 }
1258 }
1259 Node::CompareKind {
1260 kind: _,
1261 left,
1262 right,
1263 } => {
1264 rename_sheet_in_node(left, sheet_index, new_name);
1265 rename_sheet_in_node(right, sheet_index, new_name);
1266 }
1267 Node::UnaryKind { kind: _, right } => {
1268 rename_sheet_in_node(right, sheet_index, new_name);
1269 }
1270 Node::ImplicitIntersection {
1271 automatic: _,
1272 child,
1273 } => {
1274 rename_sheet_in_node(child, sheet_index, new_name);
1275 }
1276 Node::SpillRangeOperator { child } => {
1277 rename_sheet_in_node(child, sheet_index, new_name);
1278 }
1279
1280 Node::BooleanKind(_) => {}
1282 Node::NumberKind(_) => {}
1283 Node::StringKind(_) => {}
1284 Node::ErrorKind(_) => {}
1285 Node::ParseErrorKind { .. } => {}
1286 Node::ArrayKind(_) => {}
1287 Node::DefinedNameKind(_) => {}
1288 Node::TableNameKind(_) => {}
1289 Node::NamedVariableKind { .. } => {}
1290 Node::EmptyArgKind => {}
1291 Node::LambdaDefKind {
1292 parameters: _,
1293 body,
1294 } => {
1295 rename_sheet_in_node(body, sheet_index, new_name);
1296 }
1297 Node::LambdaCallKind { lambda, args } => {
1298 rename_sheet_in_node(lambda, sheet_index, new_name);
1299 for arg in args {
1300 rename_sheet_in_node(arg, sheet_index, new_name);
1301 }
1302 }
1303 }
1304}
1305
1306pub(crate) fn rename_defined_name_in_node(
1307 node: &mut Node,
1308 name: &str,
1309 scope: Option<u32>,
1310 new_name: &str,
1311) {
1312 match node {
1313 Node::DefinedNameKind((n, s, _)) => {
1315 if name.to_lowercase() == n.to_lowercase() && *s == scope {
1316 *n = new_name.to_string();
1317 }
1318 }
1319 Node::OpRangeKind { left, right } => {
1321 rename_defined_name_in_node(left, name, scope, new_name);
1322 rename_defined_name_in_node(right, name, scope, new_name);
1323 }
1324 Node::OpConcatenateKind { left, right } => {
1325 rename_defined_name_in_node(left, name, scope, new_name);
1326 rename_defined_name_in_node(right, name, scope, new_name);
1327 }
1328 Node::OpSumKind {
1329 kind: _,
1330 left,
1331 right,
1332 } => {
1333 rename_defined_name_in_node(left, name, scope, new_name);
1334 rename_defined_name_in_node(right, name, scope, new_name);
1335 }
1336 Node::OpProductKind {
1337 kind: _,
1338 left,
1339 right,
1340 } => {
1341 rename_defined_name_in_node(left, name, scope, new_name);
1342 rename_defined_name_in_node(right, name, scope, new_name);
1343 }
1344 Node::OpPowerKind { left, right } => {
1345 rename_defined_name_in_node(left, name, scope, new_name);
1346 rename_defined_name_in_node(right, name, scope, new_name);
1347 }
1348 Node::FunctionKind { kind: _, args } => {
1349 for arg in args {
1350 rename_defined_name_in_node(arg, name, scope, new_name);
1351 }
1352 }
1353 Node::NamedFunctionKind {
1354 name: _,
1355 args,
1356 id: _,
1357 } => {
1358 for arg in args {
1359 rename_defined_name_in_node(arg, name, scope, new_name);
1360 }
1361 }
1362 Node::CompareKind {
1363 kind: _,
1364 left,
1365 right,
1366 } => {
1367 rename_defined_name_in_node(left, name, scope, new_name);
1368 rename_defined_name_in_node(right, name, scope, new_name);
1369 }
1370 Node::UnaryKind { kind: _, right } => {
1371 rename_defined_name_in_node(right, name, scope, new_name);
1372 }
1373 Node::ImplicitIntersection {
1374 automatic: _,
1375 child,
1376 } => {
1377 rename_defined_name_in_node(child, name, scope, new_name);
1378 }
1379 Node::SpillRangeOperator { child } => {
1380 rename_defined_name_in_node(child, name, scope, new_name);
1381 }
1382 Node::BooleanKind(_) => {}
1384 Node::NumberKind(_) => {}
1385 Node::StringKind(_) => {}
1386 Node::ErrorKind(_) => {}
1387 Node::ParseErrorKind { .. } => {}
1388 Node::ArrayKind(_) => {}
1389 Node::EmptyArgKind => {}
1390 Node::ReferenceKind { .. } => {}
1391 Node::RangeKind { .. } => {}
1392 Node::WrongReferenceKind { .. } => {}
1393 Node::WrongRangeKind { .. } => {}
1394 Node::TableNameKind(_) => {}
1395 Node::NamedVariableKind { .. } => {}
1396 Node::LambdaDefKind {
1397 parameters: _,
1398 body,
1399 } => {
1400 rename_defined_name_in_node(body, name, scope, new_name);
1401 }
1402 Node::LambdaCallKind { lambda, args } => {
1403 rename_defined_name_in_node(lambda, name, scope, new_name);
1404 for arg in args {
1405 rename_defined_name_in_node(arg, name, scope, new_name);
1406 }
1407 }
1408 }
1409}