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