Skip to main content

ironcalc_base/expressions/parser/
static_analysis.rs

1use crate::functions::Function;
2
3use super::Node;
4
5#[cfg(target_arch = "wasm32")]
6use regex_lite as regex;
7
8use regex::Regex;
9use std::sync::OnceLock;
10
11static RANGE_REFERENCE_REGEX: OnceLock<Regex> = OnceLock::new();
12
13#[allow(clippy::expect_used)]
14fn get_re() -> &'static Regex {
15    RANGE_REFERENCE_REGEX
16        .get_or_init(|| Regex::new(r":[A-Z]*[0-9]*$").expect("Regex is known to be valid"))
17}
18
19fn is_range_reference(s: &str) -> bool {
20    get_re().is_match(s)
21}
22
23/*
24
25# NOTES on the Implicit Intersection operator: @
26
27 Sometimes we obtain a range where we expected a single argument. This can happen:
28
29 * As an argument of a function, eg: `SIN(A1:A5)`
30 * As the result of a computation of a formula `=A1:A5`
31
32 In previous versions of the Friendly Giant the spreadsheet engine would perform an operation called _implicit intersection_
33 that tries to find a single cell within the range. It works by picking a cell in the range that is the same row or the same column
34 as the cell. If there is just one we return that otherwise we return the `#REF!` error.
35
36 Examples:
37
38 * Siting on `C3` the formula `=D1:D5` will return `D3`
39 * Sitting on `C3` the formula `=D:D` will return `D3`
40 * Sitting on `C3` the formula `=A1:A7` will return `A3`
41 * Sitting on `C3` the formula `=A5:A8` will return `#REF!`
42 * Sitting on `C3` the formula `D1:G7` will return `#REF!`
43
44 Today's version of the engine will result in a dynamic array spilling the result through several cells.
45 To force the old behaviour we can use the _implicit intersection operator_: @
46
47 * `=@A1:A7` or `=SIN(@A1:A7)
48
49 When parsing formulas that come form old workbooks this is done automatically.
50 We call this version of the II operator the _automatic_ II operator.
51
52 We can also insert the II operator in places where before was impossible:
53
54 * `=SUM(@A1:A7)`
55
56 This formulas will not be compatible with old versions of the engine. The FG will stringify this as `=SUM(_xlfn.SIMPLE(A1:A7))`.
57 */
58
59/// Traverses the formula tree adding the implicit intersection operator in all arguments of functions that
60/// expect a scalar but get a range.
61///  * A:A => @A:A
62///  * SIN(A1:D1) => SIN(@A1:D1)
63///
64/// Assumes formula return a scalar
65pub fn add_implicit_intersection(node: &mut Node, add: bool) {
66    match node {
67        Node::BooleanKind(_)
68        | Node::NumberKind(_)
69        | Node::StringKind(_)
70        | Node::ErrorKind(_)
71        | Node::EmptyArgKind
72        | Node::ParseErrorKind { .. }
73        | Node::WrongReferenceKind { .. }
74        | Node::WrongRangeKind { .. }
75        | Node::NamedFunctionKind { .. }
76        | Node::ArrayKind(_)
77        | Node::ReferenceKind { .. }
78        | Node::LambdaDefKind { .. }
79        | Node::LambdaCallKind { .. } => {}
80        Node::ImplicitIntersection { child, .. } => {
81            // We need to check wether the II can be automatic or not
82            let mut new_node = child.as_ref().clone();
83            add_implicit_intersection(&mut new_node, add);
84            if matches!(&new_node, Node::ImplicitIntersection { .. }) {
85                *node = new_node
86            }
87        }
88        Node::SpillRangeOperator { child } => {
89            add_implicit_intersection(child, add);
90        }
91        Node::RangeKind {
92            row1,
93            column1,
94            row2,
95            column2,
96            sheet_name,
97            sheet_index,
98            absolute_row1,
99            absolute_column1,
100            absolute_row2,
101            absolute_column2,
102        } => {
103            if add {
104                *node = Node::ImplicitIntersection {
105                    automatic: true,
106                    child: Box::new(Node::RangeKind {
107                        sheet_name: sheet_name.clone(),
108                        sheet_index: *sheet_index,
109                        absolute_row1: *absolute_row1,
110                        absolute_column1: *absolute_column1,
111                        row1: *row1,
112                        column1: *column1,
113                        absolute_row2: *absolute_row2,
114                        absolute_column2: *absolute_column2,
115                        row2: *row2,
116                        column2: *column2,
117                    }),
118                };
119            }
120        }
121        Node::OpRangeKind { left, right } => {
122            if add {
123                *node = Node::ImplicitIntersection {
124                    automatic: true,
125                    child: Box::new(Node::OpRangeKind {
126                        left: left.clone(),
127                        right: right.clone(),
128                    }),
129                }
130            }
131        }
132
133        // operations
134        Node::UnaryKind { right, .. } => add_implicit_intersection(right, add),
135        Node::OpConcatenateKind { left, right }
136        | Node::OpSumKind { left, right, .. }
137        | Node::OpProductKind { left, right, .. }
138        | Node::OpPowerKind { left, right, .. }
139        | Node::CompareKind { left, right, .. } => {
140            add_implicit_intersection(left, add);
141            add_implicit_intersection(right, add);
142        }
143
144        Node::DefinedNameKind(v) => {
145            if add {
146                // Not all defined names deserve the II operator
147                // For instance =Sheet1!A1 doesn't need to be intersected
148                if is_range_reference(&v.2) {
149                    *node = Node::ImplicitIntersection {
150                        automatic: true,
151                        child: Box::new(Node::DefinedNameKind(v.to_owned())),
152                    }
153                }
154            }
155        }
156        Node::NamedVariableKind { name, id } => {
157            if add {
158                *node = Node::ImplicitIntersection {
159                    automatic: true,
160                    child: Box::new(Node::NamedVariableKind {
161                        name: name.clone(),
162                        id: *id,
163                    }),
164                }
165            }
166        }
167        Node::TableNameKind(_) => {
168            // noop for now
169        }
170        Node::FunctionKind { kind, args } => {
171            let arg_count = args.len();
172            let signature = get_function_args_signature(kind, arg_count);
173            for index in 0..arg_count {
174                if matches!(signature[index], Signature::Scalar)
175                    && matches!(
176                        run_static_analysis_on_node(&args[index]),
177                        StaticResult::Range(_, _) | StaticResult::Unknown
178                    )
179                {
180                    add_implicit_intersection(&mut args[index], true);
181                } else {
182                    add_implicit_intersection(&mut args[index], false);
183                }
184            }
185            // There are some function that will never add an automatic II:
186            let new_function = matches!(kind, Function::Let | Function::Lambda);
187            if !new_function
188                && add
189                && matches!(
190                    run_static_analysis_on_node(node),
191                    StaticResult::Range(_, _) | StaticResult::Unknown
192                )
193            {
194                *node = Node::ImplicitIntersection {
195                    automatic: true,
196                    child: Box::new(node.clone()),
197                }
198            }
199        }
200    };
201}
202
203/// Inverse of [`add_implicit_intersection`], used when exporting to Excel.
204///
205/// The internal (RC) representation stores every implicit intersection as `@`,
206/// losing the `automatic` flag. When exporting we must decide, for each `@`,
207/// whether it should be written as `_xlfn.SINGLE(...)` (because it is meaningful)
208/// or dropped (because `add_implicit_intersection` would re-insert it on import).
209///
210/// That decision depends on the *context* of the operator, exactly like
211/// `add_implicit_intersection`: an `@` is redundant only in a position that
212/// expects a scalar (`add == true`). Crucially, an `@` sitting in a `Vector`
213/// argument of a function such as `SUM` is **not** redundant: on import no
214/// automatic intersection is added there, so dropping it would change the result
215/// (e.g. `SUM(A1,B1,@J:J)` would become `SUM(A1,B1,J:J)`, scanning the whole
216/// column). This pass removes only the redundant operators, leaving the rest to
217/// be stringified as `_xlfn.SINGLE`.
218///
219/// `add` mirrors the flag in `add_implicit_intersection` and must start `true`
220/// (a formula is evaluated in a scalar context).
221pub fn remove_redundant_implicit_intersection(node: &mut Node, add: bool) {
222    match node {
223        // Leaves and nodes that never contain a nested implicit intersection.
224        Node::BooleanKind(_)
225        | Node::NumberKind(_)
226        | Node::StringKind(_)
227        | Node::ErrorKind(_)
228        | Node::EmptyArgKind
229        | Node::ParseErrorKind { .. }
230        | Node::WrongReferenceKind { .. }
231        | Node::WrongRangeKind { .. }
232        | Node::NamedFunctionKind { .. }
233        | Node::ArrayKind(_)
234        | Node::ReferenceKind { .. }
235        | Node::RangeKind { .. }
236        | Node::OpRangeKind { .. }
237        | Node::DefinedNameKind(_)
238        | Node::NamedVariableKind { .. }
239        | Node::TableNameKind(_)
240        | Node::LambdaDefKind { .. }
241        | Node::LambdaCallKind { .. } => {}
242        Node::ImplicitIntersection { child, .. } => {
243            if add {
244                // Would `add_implicit_intersection` re-insert this operator on
245                // import? Probe the child in a scalar context to find out.
246                let mut probe = child.as_ref().clone();
247                add_implicit_intersection(&mut probe, true);
248                if matches!(probe, Node::ImplicitIntersection { .. }) {
249                    // Redundant: drop the operator and keep cleaning the child.
250                    // The child is still in the same (scalar) context, so recurse
251                    // with `add` to also remove any nested redundant operators.
252                    let mut inner = child.as_ref().clone();
253                    remove_redundant_implicit_intersection(&mut inner, add);
254                    *node = inner;
255                    return;
256                }
257            }
258            // Meaningful operator: keep it, but still clean any nested ones.
259            remove_redundant_implicit_intersection(child, false);
260        }
261        Node::SpillRangeOperator { child } => {
262            remove_redundant_implicit_intersection(child, add);
263        }
264        Node::UnaryKind { right, .. } => remove_redundant_implicit_intersection(right, add),
265        Node::OpConcatenateKind { left, right }
266        | Node::OpSumKind { left, right, .. }
267        | Node::OpProductKind { left, right, .. }
268        | Node::OpPowerKind { left, right, .. }
269        | Node::CompareKind { left, right, .. } => {
270            remove_redundant_implicit_intersection(left, add);
271            remove_redundant_implicit_intersection(right, add);
272        }
273        Node::FunctionKind { kind, args } => {
274            let arg_count = args.len();
275            let signature = get_function_args_signature(kind, arg_count);
276            for index in 0..arg_count {
277                // Scalar arguments are an intersecting context; vector arguments
278                // (ranges/arrays) are not.
279                let child_add = matches!(signature[index], Signature::Scalar);
280                remove_redundant_implicit_intersection(&mut args[index], child_add);
281            }
282        }
283    };
284}
285
286/// The result of the static analysis of a node
287pub enum StaticResult {
288    // The result of the evaluation is a single value (number, string, boolean, error)
289    Scalar,
290    // The result of the evaluation is an array with dimensions (rows, columns)
291    Array(i32, i32),
292    // The result of the evaluation is a range with dimensions (rows, columns)
293    Range(i32, i32),
294    // The result of the evaluation is unknown, we cannot guaranty it is a scalar, an array or a range
295    Unknown,
296    // TODO: What if one of the dimensions is known?
297    // what if the dimensions are unknown but bounded?
298}
299
300fn static_analysis_op_nodes(left: &Node, right: &Node) -> StaticResult {
301    let lhs = run_static_analysis_on_node(left);
302    let rhs = run_static_analysis_on_node(right);
303    match (lhs, rhs) {
304        (StaticResult::Scalar, StaticResult::Scalar) => StaticResult::Scalar,
305        (StaticResult::Scalar, StaticResult::Array(a, b) | StaticResult::Range(a, b)) => {
306            StaticResult::Array(a, b)
307        }
308
309        (StaticResult::Array(a, b) | StaticResult::Range(a, b), StaticResult::Scalar) => {
310            StaticResult::Array(a, b)
311        }
312        (
313            StaticResult::Array(a1, b1) | StaticResult::Range(a1, b1),
314            StaticResult::Array(a2, b2) | StaticResult::Range(a2, b2),
315        ) => StaticResult::Array(a1.max(a2), b1.max(b2)),
316
317        (_, StaticResult::Unknown) => StaticResult::Unknown,
318        (StaticResult::Unknown, _) => StaticResult::Unknown,
319    }
320}
321
322// Returns:
323//  * Scalar if we can proof the result of the evaluation is a scalar
324//  * Array(a, b) if we know it will be an a x b array.
325//  * Range(a, b) if we know it will be a a x b range.
326//  * Unknown if we cannot guaranty either
327pub(crate) fn run_static_analysis_on_node(node: &Node) -> StaticResult {
328    match node {
329        Node::BooleanKind(_)
330        | Node::NumberKind(_)
331        | Node::StringKind(_)
332        | Node::ErrorKind(_)
333        | Node::EmptyArgKind => StaticResult::Scalar,
334        Node::UnaryKind { right, .. } => run_static_analysis_on_node(right),
335        Node::ParseErrorKind { .. } => {
336            // StaticResult::Unknown is also valid
337            StaticResult::Scalar
338        }
339        Node::WrongReferenceKind { .. } => {
340            // StaticResult::Unknown is also valid
341            StaticResult::Scalar
342        }
343        Node::WrongRangeKind { .. } => {
344            // StaticResult::Unknown or Array is also valid
345            StaticResult::Scalar
346        }
347        Node::NamedFunctionKind { .. } => {
348            // A named-function call invokes a LAMBDA (defined-name or LET-bound) whose
349            // result shape is unknown at parse time — it may well be an array that needs
350            // to spill (e.g. a LAMBDA wrapping SEQUENCE). Treat it like LambdaCallKind.
351            StaticResult::Unknown
352        }
353        Node::ArrayKind(array) => {
354            let n = array.len() as i32;
355            let m = array.first().map(|row| row.len() as i32).unwrap_or(0);
356            StaticResult::Array(n, m)
357        }
358        Node::RangeKind {
359            row1,
360            column1,
361            row2,
362            column2,
363            ..
364        } => StaticResult::Range(row2 - row1, column2 - column1),
365        Node::OpRangeKind { .. } => {
366            // TODO: We could do a bit better here
367            StaticResult::Unknown
368        }
369        Node::ReferenceKind { .. } => StaticResult::Scalar,
370
371        // binary operations
372        Node::OpConcatenateKind { left, right }
373        | Node::OpSumKind { left, right, .. }
374        | Node::OpProductKind { left, right, .. }
375        | Node::OpPowerKind { left, right, .. }
376        | Node::CompareKind { left, right, .. } => static_analysis_op_nodes(left, right),
377
378        // defined names
379        Node::DefinedNameKind(_) => {
380            // TODO: We could do better if we tracked the defined names
381            StaticResult::Unknown
382        }
383        Node::NamedVariableKind { .. } => StaticResult::Scalar,
384        Node::TableNameKind(_) => StaticResult::Unknown,
385        Node::FunctionKind { kind, args } => static_analysis_on_function(kind, args),
386        Node::ImplicitIntersection { .. } => StaticResult::Scalar,
387        Node::SpillRangeOperator { .. } => StaticResult::Unknown,
388        Node::LambdaDefKind { .. } => StaticResult::Unknown,
389        Node::LambdaCallKind { .. } => StaticResult::Unknown,
390    }
391}
392
393// If all the arguments are scalars the function will return a scalar
394// If any of the arguments is a range or an array it will return an array
395fn scalar_arguments(args: &[Node]) -> StaticResult {
396    let mut n = 0;
397    let mut m = 0;
398    for arg in args {
399        match run_static_analysis_on_node(arg) {
400            StaticResult::Scalar => {
401                // noop
402            }
403            StaticResult::Array(a, b) | StaticResult::Range(a, b) => {
404                n = n.max(a);
405                m = m.max(b);
406            }
407            StaticResult::Unknown => return StaticResult::Unknown,
408        }
409    }
410    if n == 0 && m == 0 {
411        return StaticResult::Scalar;
412    }
413    StaticResult::Array(n, m)
414}
415
416// We only care if the function can return a range or not
417fn not_implemented(_args: &[Node]) -> StaticResult {
418    StaticResult::Scalar
419}
420
421/// SUMIF spills according to the shape of its criteria argument (`args[1]`); the
422/// criteria_range and sum_range arguments are consumed, not broadcast. A scalar
423/// criterion yields a scalar; a range/array criterion yields an array of the
424/// same dimensions.
425fn sumif_static_result(args: &[Node]) -> StaticResult {
426    match args.get(1) {
427        Some(criteria) => match run_static_analysis_on_node(criteria) {
428            StaticResult::Array(a, b) | StaticResult::Range(a, b) => StaticResult::Array(a, b),
429            StaticResult::Scalar => StaticResult::Scalar,
430            StaticResult::Unknown => StaticResult::Unknown,
431        },
432        None => StaticResult::Scalar,
433    }
434}
435
436fn static_analysis_offset(args: &[Node]) -> StaticResult {
437    // If first argument is a single cell reference and there are no4th and 5th argument,
438    // or they are 1, then it is a scalar
439    let arg_count = args.len();
440    if arg_count < 3 {
441        // Actually an error
442        return StaticResult::Scalar;
443    }
444    if !matches!(args[0], Node::ReferenceKind { .. }) {
445        return StaticResult::Unknown;
446    }
447    if arg_count == 3 {
448        return StaticResult::Scalar;
449    }
450    match args[3] {
451        Node::NumberKind(f) => {
452            if f != 1.0 {
453                return StaticResult::Unknown;
454            }
455        }
456        _ => return StaticResult::Unknown,
457    };
458    if arg_count == 4 {
459        return StaticResult::Scalar;
460    }
461    match args[4] {
462        Node::NumberKind(f) => {
463            if f != 1.0 {
464                return StaticResult::Unknown;
465            }
466        }
467        _ => return StaticResult::Unknown,
468    };
469    // Both height and width are explicitly 1, so OFFSET will return a single cell
470    StaticResult::Scalar
471}
472
473// fn static_analysis_choose(_args: &[Node]) -> StaticResult {
474//     // We will always insert the @ in CHOOSE, but technically it is only needed if one of the elements is a range
475//     StaticResult::Unknown
476// }
477
478fn static_analysis_indirect(_args: &[Node]) -> StaticResult {
479    // We will always insert the @, but we don't need to do that in every scenario`
480    StaticResult::Unknown
481}
482
483fn static_analysis_index(_args: &[Node]) -> StaticResult {
484    // INDEX has two forms, but they are indistinguishable at parse time.
485    StaticResult::Unknown
486}
487
488#[derive(Clone)]
489enum Signature {
490    Scalar,
491    Vector,
492    Error,
493}
494
495fn args_signature_no_args(arg_count: usize) -> Vec<Signature> {
496    if arg_count == 0 {
497        vec![]
498    } else {
499        vec![Signature::Error; arg_count]
500    }
501}
502
503fn args_signature_scalars(
504    arg_count: usize,
505    required_count: usize,
506    optional_count: usize,
507) -> Vec<Signature> {
508    if arg_count >= required_count && arg_count <= required_count + optional_count {
509        vec![Signature::Scalar; arg_count]
510    } else {
511        vec![Signature::Error; arg_count]
512    }
513}
514
515fn args_signature_lambda(arg_count: usize) -> Vec<Signature> {
516    // LAMBDA([param1, param2, ...], body) — at least 1 arg (the body)
517    if arg_count == 0 {
518        return vec![Signature::Error; arg_count];
519    }
520    // All parameter names are Scalar; the final body argument is Vector.
521    let mut sig = vec![Signature::Scalar; arg_count];
522    sig[arg_count - 1] = Signature::Vector;
523    sig
524}
525
526fn args_signature_let(arg_count: usize) -> Vec<Signature> {
527    // LET requires an odd number of args >= 3: name1, value1, [name2, value2, ...], body
528    if arg_count < 3 || arg_count.is_multiple_of(2) {
529        return vec![Signature::Error; arg_count];
530    }
531    (0..arg_count)
532        .map(|i| {
533            // Odd indices are value expressions; last index is the body.
534            // Both should be Vector so range references are not implicitly intersected.
535            // Even indices (except last) are name declarations — Scalar is fine since
536            // they are never actually evaluated as range expressions.
537            if i % 2 == 1 || i == arg_count - 1 {
538                Signature::Vector
539            } else {
540                Signature::Scalar
541            }
542        })
543        .collect()
544}
545
546fn args_signature_arraytotext(arg_count: usize) -> Vec<Signature> {
547    match arg_count {
548        1 => vec![Signature::Vector],
549        2 => vec![Signature::Vector, Signature::Scalar],
550        _ => vec![Signature::Error; arg_count],
551    }
552}
553
554fn args_signature_one_vector(arg_count: usize) -> Vec<Signature> {
555    if arg_count == 1 {
556        vec![Signature::Vector]
557    } else {
558        vec![Signature::Error; arg_count]
559    }
560}
561
562fn args_signature_sumif(arg_count: usize) -> Vec<Signature> {
563    if arg_count == 2 {
564        vec![Signature::Vector, Signature::Scalar]
565    } else if arg_count == 3 {
566        vec![Signature::Vector, Signature::Scalar, Signature::Vector]
567    } else {
568        vec![Signature::Error; arg_count]
569    }
570}
571
572/// SUMIF signature with the criteria argument as a `Vector` instead of a
573/// `Scalar`. This stops a range/array criteria from being collapsed by implicit
574/// intersection, so SUMIF can spill one sum per criterion. (COUNTIF/AVERAGEIF
575/// keep the classic [`args_signature_sumif`], intersecting range criteria.)
576fn args_signature_sumif_spill(arg_count: usize) -> Vec<Signature> {
577    if arg_count == 2 {
578        vec![Signature::Vector, Signature::Vector]
579    } else if arg_count == 3 {
580        vec![Signature::Vector, Signature::Vector, Signature::Vector]
581    } else {
582        vec![Signature::Error; arg_count]
583    }
584}
585
586// 1 or none scalars
587fn args_signature_sheet(arg_count: usize) -> Vec<Signature> {
588    if arg_count == 0 {
589        vec![]
590    } else if arg_count == 1 {
591        vec![Signature::Scalar]
592    } else {
593        vec![Signature::Error; arg_count]
594    }
595}
596
597fn args_signature_hlookup(arg_count: usize) -> Vec<Signature> {
598    if arg_count == 3 {
599        vec![Signature::Vector, Signature::Vector, Signature::Scalar]
600    } else if arg_count == 4 {
601        vec![
602            Signature::Vector,
603            Signature::Vector,
604            Signature::Scalar,
605            Signature::Vector,
606        ]
607    } else {
608        vec![Signature::Error; arg_count]
609    }
610}
611
612fn args_signature_index(arg_count: usize) -> Vec<Signature> {
613    if arg_count == 2 {
614        vec![Signature::Vector, Signature::Scalar]
615    } else if arg_count == 3 {
616        vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
617    } else if arg_count == 4 {
618        vec![
619            Signature::Vector,
620            Signature::Scalar,
621            Signature::Scalar,
622            Signature::Scalar,
623        ]
624    } else {
625        vec![Signature::Error; arg_count]
626    }
627}
628
629fn args_signature_lookup(arg_count: usize) -> Vec<Signature> {
630    if arg_count == 2 {
631        vec![Signature::Vector, Signature::Vector]
632    } else if arg_count == 3 {
633        vec![Signature::Vector, Signature::Vector, Signature::Vector]
634    } else {
635        vec![Signature::Error; arg_count]
636    }
637}
638
639fn args_signature_match(arg_count: usize) -> Vec<Signature> {
640    if arg_count == 2 {
641        vec![Signature::Vector, Signature::Vector]
642    } else if arg_count == 3 {
643        vec![Signature::Vector, Signature::Vector, Signature::Scalar]
644    } else {
645        vec![Signature::Error; arg_count]
646    }
647}
648
649fn args_signature_offset(arg_count: usize) -> Vec<Signature> {
650    if arg_count == 3 {
651        vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
652    } else if arg_count == 4 {
653        vec![
654            Signature::Vector,
655            Signature::Scalar,
656            Signature::Scalar,
657            Signature::Scalar,
658        ]
659    } else if arg_count == 5 {
660        vec![
661            Signature::Vector,
662            Signature::Scalar,
663            Signature::Scalar,
664            Signature::Scalar,
665            Signature::Scalar,
666        ]
667    } else {
668        vec![Signature::Error; arg_count]
669    }
670}
671
672fn args_signature_row(arg_count: usize) -> Vec<Signature> {
673    if arg_count == 0 {
674        vec![]
675    } else if arg_count == 1 {
676        vec![Signature::Vector]
677    } else {
678        vec![Signature::Error; arg_count]
679    }
680}
681
682fn args_signature_xlookup(arg_count: usize) -> Vec<Signature> {
683    if !(3..=6).contains(&arg_count) {
684        return vec![Signature::Error; arg_count];
685    }
686    let mut result = vec![Signature::Scalar; arg_count];
687    result[0] = Signature::Vector;
688    result[1] = Signature::Vector;
689    result[2] = Signature::Vector;
690    result
691}
692
693fn args_signature_sort(arg_count: usize) -> Vec<Signature> {
694    if !(1..=4).contains(&arg_count) {
695        return vec![Signature::Error; arg_count];
696    }
697    let mut result = vec![Signature::Scalar; arg_count];
698    result[0] = Signature::Vector;
699    result
700}
701
702fn args_signature_sortby(arg_count: usize) -> Vec<Signature> {
703    // Valid: 2, 3, 5, 7, ... (n==2 || n==3 || n>=5 with odd count)
704    if arg_count < 2 || (arg_count > 3 && arg_count.is_multiple_of(2)) {
705        return vec![Signature::Error; arg_count];
706    }
707    // arg[0] = array (Vector), arg[1] = by_array1 (Vector),
708    // optional arg[2] = sort_order1 (Scalar), then pairs (Vector, Scalar)
709    let mut result = vec![Signature::Scalar; arg_count];
710    result[0] = Signature::Vector;
711    let mut i = 1;
712    while i < arg_count {
713        result[i] = Signature::Vector; // by_array
714        i += 2; // skip the sort_order (Scalar)
715    }
716    result
717}
718
719fn args_signature_unique(arg_count: usize) -> Vec<Signature> {
720    if !(1..=3).contains(&arg_count) {
721        return vec![Signature::Error; arg_count];
722    }
723    let mut result = vec![Signature::Scalar; arg_count];
724    result[0] = Signature::Vector;
725    result
726}
727
728fn args_signature_filter(arg_count: usize) -> Vec<Signature> {
729    if !(2..=3).contains(&arg_count) {
730        return vec![Signature::Error; arg_count];
731    }
732    let mut result = vec![Signature::Scalar; arg_count];
733    result[0] = Signature::Vector;
734    result[1] = Signature::Vector;
735    result
736}
737
738fn args_signature_sequence(arg_count: usize) -> Vec<Signature> {
739    if !(1..=4).contains(&arg_count) {
740        return vec![Signature::Error; arg_count];
741    }
742    vec![Signature::Scalar; arg_count]
743}
744
745fn args_signature_randarray(arg_count: usize) -> Vec<Signature> {
746    if arg_count > 5 {
747        return vec![Signature::Error; arg_count];
748    }
749    vec![Signature::Scalar; arg_count]
750}
751
752fn args_signature_take(arg_count: usize) -> Vec<Signature> {
753    if !(2..=3).contains(&arg_count) {
754        return vec![Signature::Error; arg_count];
755    }
756    let mut result = vec![Signature::Scalar; arg_count];
757    result[0] = Signature::Vector;
758    result
759}
760
761fn args_signature_drop(arg_count: usize) -> Vec<Signature> {
762    if !(2..=3).contains(&arg_count) {
763        return vec![Signature::Error; arg_count];
764    }
765    let mut result = vec![Signature::Scalar; arg_count];
766    result[0] = Signature::Vector;
767    result
768}
769
770fn args_signature_tocol(arg_count: usize) -> Vec<Signature> {
771    if !(1..=3).contains(&arg_count) {
772        return vec![Signature::Error; arg_count];
773    }
774    let mut result = vec![Signature::Scalar; arg_count];
775    result[0] = Signature::Vector;
776    result
777}
778
779fn args_signature_bycol_byrow(arg_count: usize) -> Vec<Signature> {
780    if arg_count != 2 {
781        return vec![Signature::Error; arg_count];
782    }
783    vec![Signature::Vector, Signature::Scalar]
784}
785
786fn args_signature_map(arg_count: usize) -> Vec<Signature> {
787    if arg_count < 2 {
788        return vec![Signature::Error; arg_count];
789    }
790    // All args except the last (lambda) are Vector; the lambda is Scalar.
791    let mut result = vec![Signature::Vector; arg_count];
792    result[arg_count - 1] = Signature::Scalar;
793    result
794}
795
796fn args_signature_reduce(arg_count: usize) -> Vec<Signature> {
797    match arg_count {
798        2 => vec![Signature::Vector, Signature::Scalar],
799        3 => vec![Signature::Scalar, Signature::Vector, Signature::Scalar],
800        _ => vec![Signature::Error; arg_count],
801    }
802}
803
804fn args_signature_scan(arg_count: usize) -> Vec<Signature> {
805    match arg_count {
806        2 => vec![Signature::Vector, Signature::Scalar],
807        3 => vec![Signature::Scalar, Signature::Vector, Signature::Scalar],
808        _ => vec![Signature::Error; arg_count],
809    }
810}
811
812fn args_signature_textsplit(arg_count: usize) -> Vec<Signature> {
813    if !(2..=6).contains(&arg_count) {
814        return vec![Signature::Error; arg_count];
815    }
816    // col_delimiter (index 1) and row_delimiter (index 2) can be arrays
817    let mut result = vec![Signature::Scalar; arg_count];
818    result[1] = Signature::Vector;
819    if arg_count >= 3 {
820        result[2] = Signature::Vector;
821    }
822    result
823}
824
825fn args_signature_textafter(arg_count: usize) -> Vec<Signature> {
826    if !(2..=6).contains(&arg_count) {
827        vec![Signature::Scalar; arg_count]
828    } else {
829        vec![Signature::Error; arg_count]
830    }
831}
832
833fn args_signature_textjoin(arg_count: usize) -> Vec<Signature> {
834    if arg_count >= 3 {
835        let mut result = vec![Signature::Vector; arg_count];
836        result[0] = Signature::Scalar;
837        result[1] = Signature::Scalar;
838        result
839    } else {
840        vec![Signature::Error; arg_count]
841    }
842}
843
844fn args_signature_npv(arg_count: usize) -> Vec<Signature> {
845    if arg_count < 2 {
846        return vec![Signature::Error; arg_count];
847    }
848    let mut result = vec![Signature::Vector; arg_count];
849    result[0] = Signature::Scalar;
850    result
851}
852
853fn args_signature_irr(arg_count: usize) -> Vec<Signature> {
854    if arg_count > 2 {
855        vec![Signature::Error; arg_count]
856    } else if arg_count == 1 {
857        vec![Signature::Vector]
858    } else {
859        vec![Signature::Vector, Signature::Scalar]
860    }
861}
862
863fn args_signature_xirr(arg_count: usize) -> Vec<Signature> {
864    if arg_count == 2 {
865        vec![Signature::Vector; arg_count]
866    } else if arg_count == 3 {
867        vec![Signature::Vector, Signature::Vector, Signature::Scalar]
868    } else {
869        vec![Signature::Error; arg_count]
870    }
871}
872
873fn args_signature_mirr(arg_count: usize) -> Vec<Signature> {
874    if arg_count != 3 {
875        vec![Signature::Error; arg_count]
876    } else {
877        vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
878    }
879}
880
881fn args_signature_xnpv(arg_count: usize) -> Vec<Signature> {
882    if arg_count != 3 {
883        vec![Signature::Error; arg_count]
884    } else {
885        vec![Signature::Scalar, Signature::Vector, Signature::Vector]
886    }
887}
888
889// NETWORKDAYS(start_date, end_date, [holidays])
890// Parameters: start_date (scalar), end_date (scalar), holidays (optional vector)
891fn args_signature_networkdays(arg_count: usize) -> Vec<Signature> {
892    if arg_count == 2 {
893        vec![Signature::Scalar, Signature::Scalar]
894    } else if arg_count == 3 {
895        vec![Signature::Scalar, Signature::Scalar, Signature::Vector]
896    } else {
897        vec![Signature::Error; arg_count]
898    }
899}
900
901// NETWORKDAYS.INTL(start_date, end_date, [weekend], [holidays])
902// Parameters: start_date (scalar), end_date (scalar), weekend (optional scalar), holidays (optional vector)
903fn args_signature_networkdays_intl(arg_count: usize) -> Vec<Signature> {
904    if arg_count == 2 {
905        vec![Signature::Scalar, Signature::Scalar]
906    } else if arg_count == 3 {
907        vec![Signature::Scalar, Signature::Scalar, Signature::Scalar]
908    } else if arg_count == 4 {
909        vec![
910            Signature::Scalar,
911            Signature::Scalar,
912            Signature::Scalar,
913            Signature::Vector,
914        ]
915    } else {
916        vec![Signature::Error; arg_count]
917    }
918}
919
920// FIXME: This is terrible duplications of efforts. We use the signature in at least three different places:
921// 1. When computing the function
922// 2. Checking the arguments to see if we need to insert the implicit intersection operator
923// 3. Understanding the return value
924//
925fn args_signature_xmatch(arg_count: usize) -> Vec<Signature> {
926    if !(2..=4).contains(&arg_count) {
927        return vec![Signature::Error; arg_count];
928    }
929    let mut result = vec![Signature::Scalar; arg_count];
930    result[1] = Signature::Vector;
931    result
932}
933
934fn args_signature_trimrange(arg_count: usize) -> Vec<Signature> {
935    if !(1..=3).contains(&arg_count) {
936        return vec![Signature::Error; arg_count];
937    }
938    let mut result = vec![Signature::Scalar; arg_count];
939    result[0] = Signature::Vector;
940    result
941}
942
943fn args_signature_address(arg_count: usize) -> Vec<Signature> {
944    if !(2..=5).contains(&arg_count) {
945        return vec![Signature::Error; arg_count];
946    }
947    vec![Signature::Scalar; arg_count]
948}
949
950fn args_signature_choosecols(arg_count: usize) -> Vec<Signature> {
951    if arg_count < 2 {
952        return vec![Signature::Error; arg_count];
953    }
954    let mut result = vec![Signature::Scalar; arg_count];
955    result[0] = Signature::Vector;
956    result
957}
958
959fn args_signature_expand(arg_count: usize) -> Vec<Signature> {
960    if !(2..=4).contains(&arg_count) {
961        return vec![Signature::Error; arg_count];
962    }
963    let mut result = vec![Signature::Scalar; arg_count];
964    result[0] = Signature::Vector;
965    result
966}
967
968fn args_signature_wrapcols(arg_count: usize) -> Vec<Signature> {
969    if !(2..=3).contains(&arg_count) {
970        return vec![Signature::Error; arg_count];
971    }
972    let mut result = vec![Signature::Scalar; arg_count];
973    result[0] = Signature::Vector;
974    result
975}
976
977// The signature of the functions should be defined only once
978
979// Given a function and a number of arguments this returns the arguments at each position
980// are expected to be scalars or vectors (array/ranges).
981// Sets signature::Error to all arguments if the number of arguments is incorrect.
982fn get_function_args_signature(kind: &Function, arg_count: usize) -> Vec<Signature> {
983    match kind {
984        Function::And => vec![Signature::Vector; arg_count],
985        Function::False => args_signature_no_args(arg_count),
986        Function::If => args_signature_scalars(arg_count, 2, 1),
987        Function::Iferror => args_signature_scalars(arg_count, 2, 0),
988        Function::Ifna => args_signature_scalars(arg_count, 2, 0),
989        Function::Ifs => vec![Signature::Scalar; arg_count],
990        Function::Lambda => args_signature_lambda(arg_count),
991        Function::Let => args_signature_let(arg_count),
992        Function::Not => args_signature_scalars(arg_count, 1, 0),
993        Function::Or => vec![Signature::Vector; arg_count],
994        Function::Switch => vec![Signature::Scalar; arg_count],
995        Function::True => args_signature_no_args(arg_count),
996        Function::Xor => vec![Signature::Vector; arg_count],
997        Function::Abs => args_signature_scalars(arg_count, 1, 0),
998        Function::Acos => args_signature_scalars(arg_count, 1, 0),
999        Function::Acosh => args_signature_scalars(arg_count, 1, 0),
1000        Function::Asin => args_signature_scalars(arg_count, 1, 0),
1001        Function::Asinh => args_signature_scalars(arg_count, 1, 0),
1002        Function::Atan => args_signature_scalars(arg_count, 1, 0),
1003        Function::Atan2 => args_signature_scalars(arg_count, 2, 0),
1004        Function::Atanh => args_signature_scalars(arg_count, 1, 0),
1005        Function::Choose => vec![Signature::Scalar; arg_count],
1006        Function::Column => args_signature_row(arg_count),
1007        Function::Columns => args_signature_one_vector(arg_count),
1008        Function::Ln => args_signature_scalars(arg_count, 1, 0),
1009        Function::Log => args_signature_scalars(arg_count, 1, 1),
1010        Function::Log10 => args_signature_scalars(arg_count, 1, 0),
1011        Function::Cos => args_signature_scalars(arg_count, 1, 0),
1012        Function::Cosh => args_signature_scalars(arg_count, 1, 0),
1013        Function::Max => vec![Signature::Vector; arg_count],
1014        Function::Min => vec![Signature::Vector; arg_count],
1015        Function::Pi => args_signature_no_args(arg_count),
1016        Function::Power => args_signature_scalars(arg_count, 2, 0),
1017        Function::Product => vec![Signature::Vector; arg_count],
1018        Function::Round => args_signature_scalars(arg_count, 2, 0),
1019        Function::Rounddown => args_signature_scalars(arg_count, 2, 0),
1020        Function::Roundup => args_signature_scalars(arg_count, 2, 0),
1021        Function::Sin => args_signature_scalars(arg_count, 1, 0),
1022        Function::Sinh => args_signature_scalars(arg_count, 1, 0),
1023        Function::Sqrt => args_signature_scalars(arg_count, 1, 0),
1024        Function::Sqrtpi => args_signature_scalars(arg_count, 1, 0),
1025        Function::Sum => vec![Signature::Vector; arg_count],
1026        Function::Sumif => args_signature_sumif_spill(arg_count),
1027        Function::Sumifs => vec![Signature::Vector; arg_count],
1028        Function::Tan => args_signature_scalars(arg_count, 1, 0),
1029        Function::Tanh => args_signature_scalars(arg_count, 1, 0),
1030        Function::ErrorType => args_signature_scalars(arg_count, 1, 0),
1031        Function::Isblank => args_signature_scalars(arg_count, 1, 0),
1032        Function::Iserr => args_signature_scalars(arg_count, 1, 0),
1033        Function::Iserror => args_signature_scalars(arg_count, 1, 0),
1034        Function::Iseven => args_signature_scalars(arg_count, 1, 0),
1035        Function::Isformula => args_signature_scalars(arg_count, 1, 0),
1036        Function::Islogical => args_signature_scalars(arg_count, 1, 0),
1037        Function::Isna => args_signature_scalars(arg_count, 1, 0),
1038        Function::Isnontext => args_signature_scalars(arg_count, 1, 0),
1039        Function::Isnumber => args_signature_scalars(arg_count, 1, 0),
1040        Function::Isodd => args_signature_scalars(arg_count, 1, 0),
1041        Function::Isomitted => args_signature_scalars(arg_count, 1, 0),
1042        Function::Isref => args_signature_one_vector(arg_count),
1043        Function::Istext => args_signature_scalars(arg_count, 1, 0),
1044        Function::Na => args_signature_no_args(arg_count),
1045        Function::Sheet => args_signature_sheet(arg_count),
1046        Function::Type => args_signature_one_vector(arg_count),
1047        Function::Address => args_signature_address(arg_count),
1048        Function::Areas => args_signature_one_vector(arg_count),
1049        Function::Choosecols => args_signature_choosecols(arg_count),
1050        Function::Chooserows => args_signature_choosecols(arg_count),
1051        Function::Expand => args_signature_expand(arg_count),
1052        Function::Hlookup => args_signature_hlookup(arg_count),
1053        Function::Hstack => vec![Signature::Vector; arg_count],
1054        Function::Index => args_signature_index(arg_count),
1055        Function::Indirect => args_signature_scalars(arg_count, 1, 0),
1056        Function::Lookup => args_signature_lookup(arg_count),
1057        Function::Match => args_signature_match(arg_count),
1058        Function::Offset => args_signature_offset(arg_count),
1059        Function::Row => args_signature_row(arg_count),
1060        Function::Rows => args_signature_one_vector(arg_count),
1061        Function::Vlookup => args_signature_hlookup(arg_count),
1062        Function::Vstack => vec![Signature::Vector; arg_count],
1063        Function::Wrapcols => args_signature_wrapcols(arg_count),
1064        Function::Wraprows => args_signature_wrapcols(arg_count),
1065        Function::Xlookup => args_signature_xlookup(arg_count),
1066        Function::Xmatch => args_signature_xmatch(arg_count),
1067        Function::Trimrange => args_signature_trimrange(arg_count),
1068        Function::Sort => args_signature_sort(arg_count),
1069        Function::Sortby => args_signature_sortby(arg_count),
1070        Function::Unique => args_signature_unique(arg_count),
1071        Function::Filter => args_signature_filter(arg_count),
1072        Function::Take => args_signature_take(arg_count),
1073        Function::Drop => args_signature_drop(arg_count),
1074        Function::Tocol => args_signature_tocol(arg_count),
1075        Function::Torow => args_signature_tocol(arg_count),
1076        Function::Transpose => args_signature_one_vector(arg_count),
1077        Function::Mmult => {
1078            if arg_count == 2 {
1079                vec![Signature::Vector, Signature::Vector]
1080            } else {
1081                vec![Signature::Error; arg_count]
1082            }
1083        }
1084        Function::Bycol => args_signature_bycol_byrow(arg_count),
1085        Function::Byrow => args_signature_bycol_byrow(arg_count),
1086        Function::Map => args_signature_map(arg_count),
1087        Function::Reduce => args_signature_reduce(arg_count),
1088        Function::Scan => args_signature_scan(arg_count),
1089        Function::Makearray => vec![Signature::Scalar; 3],
1090        Function::Sequence => args_signature_sequence(arg_count),
1091        Function::Randarray => args_signature_randarray(arg_count),
1092        Function::Textsplit => args_signature_textsplit(arg_count),
1093        Function::Concat => vec![Signature::Vector; arg_count],
1094        Function::Concatenate => vec![Signature::Scalar; arg_count],
1095        Function::Exact => args_signature_scalars(arg_count, 2, 0),
1096        Function::Find => args_signature_scalars(arg_count, 2, 1),
1097        Function::Left => args_signature_scalars(arg_count, 1, 1),
1098        Function::Len => args_signature_scalars(arg_count, 1, 0),
1099        Function::Lower => args_signature_scalars(arg_count, 1, 0),
1100        Function::Mid => args_signature_scalars(arg_count, 3, 0),
1101        Function::Rept => args_signature_scalars(arg_count, 2, 0),
1102        Function::Right => args_signature_scalars(arg_count, 2, 1),
1103        Function::Search => args_signature_scalars(arg_count, 2, 1),
1104        Function::Substitute => args_signature_scalars(arg_count, 3, 1),
1105        Function::Regexextract => args_signature_scalars(arg_count, 2, 1),
1106        Function::Regexreplace => args_signature_scalars(arg_count, 3, 0),
1107        Function::Regextest => args_signature_scalars(arg_count, 2, 0),
1108        Function::T => args_signature_scalars(arg_count, 1, 0),
1109        Function::Text => args_signature_scalars(arg_count, 2, 0),
1110        Function::Textafter => args_signature_textafter(arg_count),
1111        Function::Textbefore => args_signature_textafter(arg_count),
1112        Function::Textjoin => args_signature_textjoin(arg_count),
1113        Function::Trim => args_signature_scalars(arg_count, 1, 0),
1114        Function::Upper => args_signature_scalars(arg_count, 1, 0),
1115        Function::Value => args_signature_scalars(arg_count, 1, 0),
1116        Function::Valuetotext => args_signature_scalars(arg_count, 1, 1),
1117        Function::Average => vec![Signature::Vector; arg_count],
1118        Function::Avedev => vec![Signature::Vector; arg_count],
1119        Function::Averagea => vec![Signature::Vector; arg_count],
1120        Function::Averageif => args_signature_sumif(arg_count),
1121        Function::Averageifs => vec![Signature::Vector; arg_count],
1122        Function::Count => vec![Signature::Vector; arg_count],
1123        Function::Counta => vec![Signature::Vector; arg_count],
1124        Function::Countblank => vec![Signature::Vector; arg_count],
1125        Function::Countif => args_signature_sumif(arg_count),
1126        Function::Countifs => vec![Signature::Vector; arg_count],
1127        Function::Maxifs => vec![Signature::Vector; arg_count],
1128        Function::Minifs => vec![Signature::Vector; arg_count],
1129        Function::Date => args_signature_scalars(arg_count, 3, 0),
1130        Function::Datedif => args_signature_scalars(arg_count, 3, 0),
1131        Function::Datevalue => args_signature_scalars(arg_count, 1, 0),
1132        Function::Day => args_signature_scalars(arg_count, 1, 0),
1133        Function::Edate => args_signature_scalars(arg_count, 2, 0),
1134        Function::Eomonth => args_signature_scalars(arg_count, 2, 0),
1135        Function::Month => args_signature_scalars(arg_count, 1, 0),
1136        Function::Time => args_signature_scalars(arg_count, 3, 0),
1137        Function::Timevalue => args_signature_scalars(arg_count, 1, 0),
1138        Function::Hour => args_signature_scalars(arg_count, 1, 0),
1139        Function::Minute => args_signature_scalars(arg_count, 1, 0),
1140        Function::Second => args_signature_scalars(arg_count, 1, 0),
1141        Function::Now => args_signature_no_args(arg_count),
1142        Function::Today => args_signature_no_args(arg_count),
1143        Function::Year => args_signature_scalars(arg_count, 1, 0),
1144        Function::Days => args_signature_scalars(arg_count, 2, 0),
1145        Function::Days360 => args_signature_scalars(arg_count, 2, 1),
1146        Function::Weekday => args_signature_scalars(arg_count, 1, 1),
1147        Function::Weeknum => args_signature_scalars(arg_count, 1, 1),
1148        Function::Workday => args_signature_scalars(arg_count, 2, 1),
1149        Function::WorkdayIntl => args_signature_scalars(arg_count, 2, 2),
1150        Function::Yearfrac => args_signature_scalars(arg_count, 2, 1),
1151        Function::Isoweeknum => args_signature_scalars(arg_count, 1, 0),
1152        Function::Accrint => args_signature_scalars(arg_count, 6, 2),
1153        Function::Accrintm => args_signature_scalars(arg_count, 3, 2),
1154        Function::Disc => args_signature_scalars(arg_count, 4, 1),
1155        Function::Fvschedule => vec![Signature::Scalar, Signature::Vector],
1156        Function::Intrate => args_signature_scalars(arg_count, 4, 1),
1157        Function::Pricedisc => args_signature_scalars(arg_count, 4, 1),
1158        Function::Pricemat => args_signature_scalars(arg_count, 5, 1),
1159        Function::Received => args_signature_scalars(arg_count, 4, 1),
1160        Function::Yielddisc => args_signature_scalars(arg_count, 4, 1),
1161        Function::Yieldmat => args_signature_scalars(arg_count, 5, 1),
1162        Function::Cumipmt => args_signature_scalars(arg_count, 6, 0),
1163        Function::Cumprinc => args_signature_scalars(arg_count, 6, 0),
1164        Function::Db => args_signature_scalars(arg_count, 4, 1),
1165        Function::Ddb => args_signature_scalars(arg_count, 4, 1),
1166        Function::Dollarde => args_signature_scalars(arg_count, 2, 0),
1167        Function::Dollarfr => args_signature_scalars(arg_count, 2, 0),
1168        Function::Effect => args_signature_scalars(arg_count, 2, 0),
1169        Function::Fv => args_signature_scalars(arg_count, 3, 2),
1170        Function::Ipmt => args_signature_scalars(arg_count, 4, 2),
1171        Function::Irr => args_signature_irr(arg_count),
1172        Function::Ispmt => args_signature_scalars(arg_count, 4, 0),
1173        Function::Mirr => args_signature_mirr(arg_count),
1174        Function::Nominal => args_signature_scalars(arg_count, 2, 0),
1175        Function::Nper => args_signature_scalars(arg_count, 3, 2),
1176        Function::Npv => args_signature_npv(arg_count),
1177        Function::Pduration => args_signature_scalars(arg_count, 3, 0),
1178        Function::Pmt => args_signature_scalars(arg_count, 3, 2),
1179        Function::Ppmt => args_signature_scalars(arg_count, 4, 2),
1180        Function::Pv => args_signature_scalars(arg_count, 3, 2),
1181        Function::Rate => args_signature_scalars(arg_count, 3, 3),
1182        Function::Rri => args_signature_scalars(arg_count, 3, 0),
1183        Function::Sln => args_signature_scalars(arg_count, 3, 0),
1184        Function::Syd => args_signature_scalars(arg_count, 4, 0),
1185        Function::Tbilleq => args_signature_scalars(arg_count, 3, 0),
1186        Function::Tbillprice => args_signature_scalars(arg_count, 3, 0),
1187        Function::Tbillyield => args_signature_scalars(arg_count, 3, 0),
1188        Function::Xirr => args_signature_xirr(arg_count),
1189        Function::Xnpv => args_signature_xnpv(arg_count),
1190        Function::Duration => args_signature_scalars(arg_count, 5, 1),
1191        Function::Mduration => args_signature_scalars(arg_count, 5, 1),
1192        Function::Price => args_signature_scalars(arg_count, 6, 1),
1193        Function::Yield => args_signature_scalars(arg_count, 6, 1),
1194        Function::Oddfprice => args_signature_scalars(arg_count, 8, 1),
1195        Function::Oddfyield => args_signature_scalars(arg_count, 8, 1),
1196        Function::Oddlprice => args_signature_scalars(arg_count, 7, 1),
1197        Function::Oddlyield => args_signature_scalars(arg_count, 7, 1),
1198        Function::Coupdaybs => args_signature_scalars(arg_count, 3, 1),
1199        Function::Coupdays => args_signature_scalars(arg_count, 3, 1),
1200        Function::Coupdaysnc => args_signature_scalars(arg_count, 3, 1),
1201        Function::Coupncd => args_signature_scalars(arg_count, 3, 1),
1202        Function::Coupnum => args_signature_scalars(arg_count, 3, 1),
1203        Function::Couppcd => args_signature_scalars(arg_count, 3, 1),
1204        Function::Amordegrc => args_signature_scalars(arg_count, 6, 1),
1205        Function::Amorlinc => args_signature_scalars(arg_count, 6, 1),
1206        Function::Vdb => args_signature_scalars(arg_count, 5, 2),
1207        Function::Besseli => args_signature_scalars(arg_count, 2, 0),
1208        Function::Besselj => args_signature_scalars(arg_count, 2, 0),
1209        Function::Besselk => args_signature_scalars(arg_count, 2, 0),
1210        Function::Bessely => args_signature_scalars(arg_count, 2, 0),
1211        Function::Erf => args_signature_scalars(arg_count, 1, 1),
1212        Function::Erfc => args_signature_scalars(arg_count, 1, 0),
1213        Function::ErfcPrecise => args_signature_scalars(arg_count, 1, 0),
1214        Function::ErfPrecise => args_signature_scalars(arg_count, 1, 0),
1215        Function::Bin2dec => args_signature_scalars(arg_count, 1, 0),
1216        Function::Bin2hex => args_signature_scalars(arg_count, 1, 0),
1217        Function::Bin2oct => args_signature_scalars(arg_count, 1, 0),
1218        Function::Dec2Bin => args_signature_scalars(arg_count, 1, 0),
1219        Function::Dec2hex => args_signature_scalars(arg_count, 1, 0),
1220        Function::Dec2oct => args_signature_scalars(arg_count, 1, 0),
1221        Function::Hex2bin => args_signature_scalars(arg_count, 1, 0),
1222        Function::Hex2dec => args_signature_scalars(arg_count, 1, 0),
1223        Function::Hex2oct => args_signature_scalars(arg_count, 1, 0),
1224        Function::Oct2bin => args_signature_scalars(arg_count, 1, 0),
1225        Function::Oct2dec => args_signature_scalars(arg_count, 1, 0),
1226        Function::Oct2hex => args_signature_scalars(arg_count, 1, 0),
1227        Function::Bitand => args_signature_scalars(arg_count, 2, 0),
1228        Function::Bitlshift => args_signature_scalars(arg_count, 2, 0),
1229        Function::Bitor => args_signature_scalars(arg_count, 2, 0),
1230        Function::Bitrshift => args_signature_scalars(arg_count, 2, 0),
1231        Function::Bitxor => args_signature_scalars(arg_count, 2, 0),
1232        Function::Complex => args_signature_scalars(arg_count, 2, 1),
1233        Function::Imabs => args_signature_scalars(arg_count, 1, 0),
1234        Function::Imaginary => args_signature_scalars(arg_count, 1, 0),
1235        Function::Imargument => args_signature_scalars(arg_count, 1, 0),
1236        Function::Imconjugate => args_signature_scalars(arg_count, 1, 0),
1237        Function::Imcos => args_signature_scalars(arg_count, 1, 0),
1238        Function::Imcosh => args_signature_scalars(arg_count, 1, 0),
1239        Function::Imcot => args_signature_scalars(arg_count, 1, 0),
1240        Function::Imcsc => args_signature_scalars(arg_count, 1, 0),
1241        Function::Imcsch => args_signature_scalars(arg_count, 1, 0),
1242        Function::Imdiv => args_signature_scalars(arg_count, 2, 0),
1243        Function::Imexp => args_signature_scalars(arg_count, 1, 0),
1244        Function::Imln => args_signature_scalars(arg_count, 1, 0),
1245        Function::Imlog10 => args_signature_scalars(arg_count, 1, 0),
1246        Function::Imlog2 => args_signature_scalars(arg_count, 1, 0),
1247        Function::Impower => args_signature_scalars(arg_count, 2, 0),
1248        Function::Improduct => args_signature_scalars(arg_count, 2, 0),
1249        Function::Imreal => args_signature_scalars(arg_count, 1, 0),
1250        Function::Imsec => args_signature_scalars(arg_count, 1, 0),
1251        Function::Imsech => args_signature_scalars(arg_count, 1, 0),
1252        Function::Imsin => args_signature_scalars(arg_count, 1, 0),
1253        Function::Imsinh => args_signature_scalars(arg_count, 1, 0),
1254        Function::Imsqrt => args_signature_scalars(arg_count, 1, 0),
1255        Function::Imsub => args_signature_scalars(arg_count, 2, 0),
1256        Function::Imsum => args_signature_scalars(arg_count, 2, 0),
1257        Function::Imtan => args_signature_scalars(arg_count, 1, 0),
1258        Function::Convert => args_signature_scalars(arg_count, 3, 0),
1259        Function::Delta => args_signature_scalars(arg_count, 1, 1),
1260        Function::Gestep => args_signature_scalars(arg_count, 1, 1),
1261        Function::Subtotal => args_signature_npv(arg_count),
1262        Function::Rand => args_signature_no_args(arg_count),
1263        Function::Randbetween => args_signature_scalars(arg_count, 2, 0),
1264        Function::Formulatext => args_signature_scalars(arg_count, 1, 0),
1265        Function::Unicode => args_signature_scalars(arg_count, 1, 0),
1266        Function::Unichar => args_signature_scalars(arg_count, 1, 0),
1267        Function::Char => args_signature_scalars(arg_count, 1, 0),
1268        Function::Clean => args_signature_scalars(arg_count, 1, 0),
1269        Function::Code => args_signature_scalars(arg_count, 1, 0),
1270        Function::Asc => args_signature_scalars(arg_count, 1, 0),
1271        Function::Arraytotext => args_signature_arraytotext(arg_count),
1272        Function::Dollar => args_signature_scalars(arg_count, 1, 1),
1273        Function::Findb => args_signature_scalars(arg_count, 2, 1),
1274        Function::Fixed => args_signature_scalars(arg_count, 1, 2),
1275        Function::Leftb => args_signature_scalars(arg_count, 1, 1),
1276        Function::Lenb => args_signature_scalars(arg_count, 1, 0),
1277        Function::Midb => args_signature_scalars(arg_count, 3, 0),
1278        Function::Numbervalue => args_signature_scalars(arg_count, 1, 2),
1279        Function::Proper => args_signature_scalars(arg_count, 1, 0),
1280        Function::Replace => args_signature_scalars(arg_count, 4, 0),
1281        Function::Replaceb => args_signature_scalars(arg_count, 4, 0),
1282        Function::Rightb => args_signature_scalars(arg_count, 1, 1),
1283        Function::Searchb => args_signature_scalars(arg_count, 2, 1),
1284        Function::Geomean => vec![Signature::Vector; arg_count],
1285        Function::Networkdays => args_signature_networkdays(arg_count),
1286        Function::NetworkdaysIntl => args_signature_networkdays_intl(arg_count),
1287        Function::Acot => args_signature_scalars(arg_count, 1, 0),
1288        Function::Acoth => args_signature_scalars(arg_count, 1, 0),
1289        Function::Cot => args_signature_scalars(arg_count, 1, 0),
1290        Function::Coth => args_signature_scalars(arg_count, 1, 0),
1291        Function::Csc => args_signature_scalars(arg_count, 1, 0),
1292        Function::Csch => args_signature_scalars(arg_count, 1, 0),
1293        Function::Sec => args_signature_scalars(arg_count, 1, 0),
1294        Function::Sech => args_signature_scalars(arg_count, 1, 0),
1295        Function::Exp => args_signature_scalars(arg_count, 1, 0),
1296        Function::Fact => args_signature_scalars(arg_count, 1, 0),
1297        Function::Factdouble => args_signature_scalars(arg_count, 1, 0),
1298        Function::Sign => args_signature_scalars(arg_count, 1, 0),
1299        Function::Radians => args_signature_scalars(arg_count, 1, 0),
1300        Function::Degrees => args_signature_scalars(arg_count, 1, 0),
1301        Function::Int => args_signature_scalars(arg_count, 1, 0),
1302        Function::Even => args_signature_scalars(arg_count, 1, 0),
1303        Function::Odd => args_signature_scalars(arg_count, 1, 0),
1304        Function::Ceiling => args_signature_scalars(arg_count, 2, 0),
1305        Function::CeilingMath => args_signature_scalars(arg_count, 1, 2),
1306        Function::CeilingPrecise => args_signature_scalars(arg_count, 1, 1),
1307        Function::Floor => args_signature_scalars(arg_count, 2, 0),
1308        Function::FloorMath => args_signature_scalars(arg_count, 1, 2),
1309        Function::FloorPrecise => args_signature_scalars(arg_count, 1, 1),
1310        Function::IsoCeiling => args_signature_scalars(arg_count, 1, 1),
1311        Function::Mod => args_signature_scalars(arg_count, 2, 0),
1312        Function::Quotient => args_signature_scalars(arg_count, 2, 0),
1313        Function::Mround => args_signature_scalars(arg_count, 2, 0),
1314        Function::Trunc => args_signature_scalars(arg_count, 1, 1),
1315        Function::Gcd => vec![Signature::Vector; arg_count],
1316        Function::Lcm => vec![Signature::Vector; arg_count],
1317        Function::Base => args_signature_scalars(arg_count, 2, 1),
1318        Function::Decimal => args_signature_scalars(arg_count, 2, 0),
1319        Function::Roman => args_signature_scalars(arg_count, 1, 1),
1320        Function::Arabic => args_signature_scalars(arg_count, 1, 0),
1321        Function::Combin => args_signature_scalars(arg_count, 2, 0),
1322        Function::Combina => args_signature_scalars(arg_count, 2, 0),
1323        Function::Sumsq => vec![Signature::Vector; arg_count],
1324        Function::Mdeterm => args_signature_one_vector(arg_count),
1325        Function::Minverse => args_signature_one_vector(arg_count),
1326        Function::Munit => args_signature_scalars(arg_count, 1, 0),
1327        Function::Multinomial => vec![Signature::Vector; arg_count],
1328        Function::Seriessum => {
1329            if arg_count == 4 {
1330                vec![
1331                    Signature::Scalar,
1332                    Signature::Scalar,
1333                    Signature::Scalar,
1334                    Signature::Vector,
1335                ]
1336            } else {
1337                vec![Signature::Error; arg_count]
1338            }
1339        }
1340        Function::Sumproduct => vec![Signature::Vector; arg_count],
1341        Function::Percentof => {
1342            if arg_count == 2 {
1343                vec![Signature::Vector, Signature::Vector]
1344            } else {
1345                vec![Signature::Error; arg_count]
1346            }
1347        }
1348        Function::N => args_signature_scalars(arg_count, 1, 0),
1349        Function::Sheets => args_signature_scalars(arg_count, 0, 1),
1350        Function::Cell => args_signature_scalars(arg_count, 1, 1),
1351        Function::Info => args_signature_scalars(arg_count, 1, 1),
1352        Function::Daverage => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1353        Function::Dcount => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1354        Function::Dget => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1355        Function::Dmax => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1356        Function::Dmin => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1357        Function::Dsum => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1358        Function::Dcounta => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1359        Function::Dproduct => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1360        Function::Dstdev => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1361        Function::Dvar => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1362        Function::Dvarp => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1363        Function::Dstdevp => vec![Signature::Vector, Signature::Scalar, Signature::Vector],
1364        Function::BetaDist => args_signature_scalars(arg_count, 4, 2),
1365        Function::BetaInv => args_signature_scalars(arg_count, 3, 2),
1366        Function::BinomDist => args_signature_scalars(arg_count, 4, 0),
1367        Function::BinomDistRange => args_signature_scalars(arg_count, 3, 1),
1368        Function::BinomInv => args_signature_scalars(arg_count, 3, 0),
1369        Function::ChisqDist => args_signature_scalars(arg_count, 4, 0),
1370        Function::ChisqDistRT => args_signature_scalars(arg_count, 3, 0),
1371        Function::ChisqInv => args_signature_scalars(arg_count, 3, 0),
1372        Function::ChisqInvRT => args_signature_scalars(arg_count, 2, 0),
1373        Function::ChisqTest => {
1374            if arg_count == 2 {
1375                vec![Signature::Vector, Signature::Vector]
1376            } else {
1377                vec![Signature::Error; arg_count]
1378            }
1379        }
1380        Function::ConfidenceNorm => args_signature_scalars(arg_count, 3, 0),
1381        Function::ConfidenceT => args_signature_scalars(arg_count, 3, 0),
1382        Function::CovarianceP => {
1383            if arg_count == 2 {
1384                vec![Signature::Vector, Signature::Vector]
1385            } else {
1386                vec![Signature::Error; arg_count]
1387            }
1388        }
1389        Function::CovarianceS => {
1390            if arg_count == 2 {
1391                vec![Signature::Vector, Signature::Vector]
1392            } else {
1393                vec![Signature::Error; arg_count]
1394            }
1395        }
1396        Function::Devsq => vec![Signature::Vector; arg_count],
1397        Function::ExponDist => args_signature_scalars(arg_count, 3, 0),
1398        Function::FDist => args_signature_scalars(arg_count, 4, 0),
1399        Function::FDistRT => args_signature_scalars(arg_count, 3, 0),
1400        Function::FInv => args_signature_scalars(arg_count, 3, 0),
1401        Function::FInvRT => args_signature_scalars(arg_count, 3, 0),
1402        Function::FTest => vec![Signature::Vector; 2],
1403        Function::Fisher => args_signature_scalars(arg_count, 1, 0),
1404        Function::FisherInv => args_signature_scalars(arg_count, 1, 0),
1405        Function::Gamma => args_signature_scalars(arg_count, 1, 0),
1406        Function::GammaDist => args_signature_scalars(arg_count, 4, 0),
1407        Function::GammaInv => args_signature_scalars(arg_count, 3, 0),
1408        Function::GammaLn => args_signature_scalars(arg_count, 1, 0),
1409        Function::GammaLnPrecise => args_signature_scalars(arg_count, 1, 0),
1410        Function::HypGeomDist => args_signature_scalars(arg_count, 5, 0),
1411        Function::LogNormDist => args_signature_scalars(arg_count, 4, 0),
1412        Function::LogNormInv => args_signature_scalars(arg_count, 3, 0),
1413        Function::NegbinomDist => args_signature_scalars(arg_count, 4, 0),
1414        Function::NormDist => args_signature_scalars(arg_count, 4, 0),
1415        Function::NormInv => args_signature_scalars(arg_count, 3, 0),
1416        Function::NormSdist => args_signature_scalars(arg_count, 2, 0),
1417        Function::NormSInv => args_signature_scalars(arg_count, 1, 0),
1418        Function::Pearson => {
1419            if arg_count == 2 {
1420                vec![Signature::Vector, Signature::Vector]
1421            } else {
1422                vec![Signature::Error; arg_count]
1423            }
1424        }
1425        Function::Phi => args_signature_scalars(arg_count, 1, 0),
1426        Function::PoissonDist => args_signature_scalars(arg_count, 3, 0),
1427        Function::Standardize => args_signature_scalars(arg_count, 3, 0),
1428        Function::Stdev => vec![Signature::Vector; arg_count],
1429        Function::StDevP => vec![Signature::Vector; arg_count],
1430        Function::StDevS => vec![Signature::Vector; arg_count],
1431        Function::Stdeva => vec![Signature::Vector; arg_count],
1432        Function::Stdevpa => vec![Signature::Vector; arg_count],
1433        Function::TDist => args_signature_scalars(arg_count, 3, 0),
1434        Function::TDist2T => args_signature_scalars(arg_count, 2, 0),
1435        Function::TDistRT => args_signature_scalars(arg_count, 2, 0),
1436        Function::TInv => args_signature_scalars(arg_count, 2, 0),
1437        Function::TInv2T => args_signature_scalars(arg_count, 2, 0),
1438        Function::TTest => {
1439            if arg_count == 4 {
1440                vec![
1441                    Signature::Vector,
1442                    Signature::Vector,
1443                    Signature::Scalar,
1444                    Signature::Scalar,
1445                ]
1446            } else {
1447                vec![Signature::Error; arg_count]
1448            }
1449        }
1450        Function::VarP => vec![Signature::Vector; arg_count],
1451        Function::VarS => vec![Signature::Vector; arg_count],
1452        Function::VarpA => vec![Signature::Vector; arg_count],
1453        Function::VarA => vec![Signature::Vector; arg_count],
1454        Function::WeibullDist => args_signature_scalars(arg_count, 4, 0),
1455        Function::ZTest => {
1456            if arg_count == 2 {
1457                vec![Signature::Vector, Signature::Scalar]
1458            } else if arg_count == 3 {
1459                vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
1460            } else {
1461                vec![Signature::Error; arg_count]
1462            }
1463        }
1464        // Compatibility wrappers
1465        Function::BetaDistCompat => args_signature_scalars(arg_count, 3, 2),
1466        Function::HypGeomDistCompat => args_signature_scalars(arg_count, 4, 0),
1467        Function::LogNormDistCompat => args_signature_scalars(arg_count, 3, 0),
1468        Function::NegbinomDistCompat => args_signature_scalars(arg_count, 3, 0),
1469        Function::NormSDistCompat => args_signature_scalars(arg_count, 1, 0),
1470        Function::TDistCompat => args_signature_scalars(arg_count, 3, 0),
1471        // Compatibility aliases
1472        Function::BetaInvCompat => args_signature_scalars(arg_count, 3, 2),
1473        Function::BinomDistCompat => args_signature_scalars(arg_count, 4, 0),
1474        Function::ChiDistCompat => args_signature_scalars(arg_count, 2, 0),
1475        Function::ChiInvCompat => args_signature_scalars(arg_count, 2, 0),
1476        Function::ChiTestCompat => {
1477            if arg_count == 2 {
1478                vec![Signature::Vector, Signature::Vector]
1479            } else {
1480                vec![Signature::Error; arg_count]
1481            }
1482        }
1483        Function::ConfidenceCompat => args_signature_scalars(arg_count, 3, 0),
1484        Function::CovarCompat => {
1485            if arg_count == 2 {
1486                vec![Signature::Vector, Signature::Vector]
1487            } else {
1488                vec![Signature::Error; arg_count]
1489            }
1490        }
1491        Function::CritbinomCompat => args_signature_scalars(arg_count, 3, 0),
1492        Function::ExponDistCompat => args_signature_scalars(arg_count, 3, 0),
1493        Function::FDistCompat => args_signature_scalars(arg_count, 3, 0),
1494        Function::FInvCompat => args_signature_scalars(arg_count, 3, 0),
1495        Function::FTestCompat => vec![Signature::Vector; 2],
1496        Function::GammaDistCompat => args_signature_scalars(arg_count, 4, 0),
1497        Function::GammaInvCompat => args_signature_scalars(arg_count, 3, 0),
1498        Function::LoginvCompat => args_signature_scalars(arg_count, 3, 0),
1499        Function::ModeCompat => vec![Signature::Vector; arg_count],
1500        Function::NormDistCompat => args_signature_scalars(arg_count, 4, 0),
1501        Function::NormInvCompat => args_signature_scalars(arg_count, 3, 0),
1502        Function::NormSInvCompat => args_signature_scalars(arg_count, 1, 0),
1503        Function::PercentileCompat => {
1504            if arg_count == 2 {
1505                vec![Signature::Vector, Signature::Scalar]
1506            } else {
1507                vec![Signature::Error; arg_count]
1508            }
1509        }
1510        Function::PercentrankCompat => {
1511            if arg_count == 2 {
1512                vec![Signature::Vector, Signature::Scalar]
1513            } else if arg_count == 3 {
1514                vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
1515            } else {
1516                vec![Signature::Error; arg_count]
1517            }
1518        }
1519        Function::PoissonCompat => args_signature_scalars(arg_count, 3, 0),
1520        Function::QuartileCompat => {
1521            if arg_count == 2 {
1522                vec![Signature::Vector, Signature::Scalar]
1523            } else {
1524                vec![Signature::Error; arg_count]
1525            }
1526        }
1527        Function::RankCompat => vec![Signature::Scalar, Signature::Vector, Signature::Scalar],
1528        Function::StDevPCompat => vec![Signature::Vector; arg_count],
1529        Function::TInvCompat => args_signature_scalars(arg_count, 2, 0),
1530        Function::TTestCompat => {
1531            if arg_count == 4 {
1532                vec![
1533                    Signature::Vector,
1534                    Signature::Vector,
1535                    Signature::Scalar,
1536                    Signature::Scalar,
1537                ]
1538            } else {
1539                vec![Signature::Error; arg_count]
1540            }
1541        }
1542        Function::VarCompat => vec![Signature::Vector; arg_count],
1543        Function::VarPCompat => vec![Signature::Vector; arg_count],
1544        Function::WeibullCompat => args_signature_scalars(arg_count, 4, 0),
1545        Function::ZTestCompat => {
1546            if arg_count == 2 {
1547                vec![Signature::Vector, Signature::Scalar]
1548            } else if arg_count == 3 {
1549                vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
1550            } else {
1551                vec![Signature::Error; arg_count]
1552            }
1553        }
1554        Function::Sumx2my2 => vec![Signature::Vector; 2],
1555        Function::Sumx2py2 => vec![Signature::Vector; 2],
1556        Function::Sumxmy2 => vec![Signature::Vector; 2],
1557        Function::Correl => vec![Signature::Vector; 2],
1558        Function::Rsq => vec![Signature::Vector; 2],
1559        Function::Intercept => vec![Signature::Vector; 2],
1560        Function::Slope => vec![Signature::Vector; 2],
1561        Function::Steyx => vec![Signature::Vector; 2],
1562        Function::Forecast | Function::ForecastLinear => {
1563            vec![Signature::Scalar, Signature::Vector, Signature::Vector]
1564        }
1565        Function::ForecastEts
1566        | Function::ForecastEtsConfint
1567        | Function::ForecastEtsSeasonality
1568        | Function::ForecastEtsStat => vec![Signature::Vector; arg_count],
1569        Function::Frequency => vec![Signature::Vector, Signature::Vector],
1570        Function::Growth | Function::Trend => match arg_count {
1571            1 => vec![Signature::Vector],
1572            2 => vec![Signature::Vector, Signature::Vector],
1573            3 => vec![Signature::Vector, Signature::Vector, Signature::Vector],
1574            4 => vec![
1575                Signature::Vector,
1576                Signature::Vector,
1577                Signature::Vector,
1578                Signature::Scalar,
1579            ],
1580            _ => vec![Signature::Error; arg_count],
1581        },
1582        Function::Linest | Function::Logest => match arg_count {
1583            1 => vec![Signature::Vector],
1584            2 => vec![Signature::Vector, Signature::Vector],
1585            3 => vec![Signature::Vector, Signature::Vector, Signature::Scalar],
1586            4 => vec![
1587                Signature::Vector,
1588                Signature::Vector,
1589                Signature::Scalar,
1590                Signature::Scalar,
1591            ],
1592            _ => vec![Signature::Error; arg_count],
1593        },
1594        Function::ModeMult | Function::ModeSingl => vec![Signature::Vector; arg_count],
1595        Function::PercentileExc | Function::PercentileInc => {
1596            vec![Signature::Vector, Signature::Scalar]
1597        }
1598        Function::PercentrankExc | Function::PercentrankInc => {
1599            vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
1600        }
1601        Function::Permut | Function::Permutationa => vec![Signature::Scalar; 2],
1602        Function::Prob => match arg_count {
1603            3 => vec![Signature::Vector, Signature::Vector, Signature::Scalar],
1604            4 => vec![
1605                Signature::Vector,
1606                Signature::Vector,
1607                Signature::Scalar,
1608                Signature::Scalar,
1609            ],
1610            _ => vec![Signature::Error; arg_count],
1611        },
1612        Function::QuartileExc | Function::QuartileInc => {
1613            vec![Signature::Vector, Signature::Scalar]
1614        }
1615        Function::Trimmean => vec![Signature::Vector, Signature::Scalar],
1616        Function::Gauss => args_signature_scalars(arg_count, 1, 0),
1617        Function::Harmean => vec![Signature::Vector; arg_count],
1618        Function::Kurt => vec![Signature::Vector; arg_count],
1619        Function::Large => vec![Signature::Vector, Signature::Scalar],
1620        Function::MaxA => vec![Signature::Vector; arg_count],
1621        Function::Median => vec![Signature::Vector; arg_count],
1622        Function::MinA => vec![Signature::Vector; arg_count],
1623        Function::RankAvg => vec![Signature::Scalar, Signature::Vector, Signature::Scalar],
1624        Function::RankEq => vec![Signature::Scalar, Signature::Vector, Signature::Scalar],
1625        Function::Skew => vec![Signature::Vector; arg_count],
1626        Function::SkewP => vec![Signature::Vector; arg_count],
1627        Function::Small => vec![Signature::Vector, Signature::Scalar],
1628    }
1629}
1630
1631// Returns the type of the result (Scalar, Array or Range) depending on the arguments
1632fn static_analysis_on_function(kind: &Function, args: &[Node]) -> StaticResult {
1633    match kind {
1634        Function::And => StaticResult::Scalar,
1635        Function::False => StaticResult::Scalar,
1636        Function::If => scalar_arguments(args),
1637        Function::Iferror => scalar_arguments(args),
1638        Function::Ifna => scalar_arguments(args),
1639        Function::Ifs => not_implemented(args),
1640        Function::Lambda => StaticResult::Unknown,
1641        Function::Let => StaticResult::Unknown,
1642        Function::Not => StaticResult::Scalar,
1643        Function::Or => StaticResult::Scalar,
1644        Function::Switch => not_implemented(args),
1645        Function::True => StaticResult::Scalar,
1646        Function::Xor => StaticResult::Scalar,
1647        Function::Abs => scalar_arguments(args),
1648        Function::Acos => scalar_arguments(args),
1649        Function::Acosh => scalar_arguments(args),
1650        Function::Asin => scalar_arguments(args),
1651        Function::Asinh => scalar_arguments(args),
1652        Function::Atan => scalar_arguments(args),
1653        Function::Atan2 => scalar_arguments(args),
1654        Function::Atanh => scalar_arguments(args),
1655        Function::Choose => scalar_arguments(args),
1656        Function::Column => not_implemented(args),
1657        Function::Columns => not_implemented(args),
1658        Function::Cos => scalar_arguments(args),
1659        Function::Cosh => scalar_arguments(args),
1660        Function::Max => StaticResult::Scalar,
1661        Function::Min => StaticResult::Scalar,
1662        Function::Pi => StaticResult::Scalar,
1663        Function::Power => scalar_arguments(args),
1664        Function::Product => not_implemented(args),
1665        Function::Round => scalar_arguments(args),
1666        Function::Rounddown => scalar_arguments(args),
1667        Function::Roundup => scalar_arguments(args),
1668        Function::Ln => scalar_arguments(args),
1669        Function::Log => scalar_arguments(args),
1670        Function::Log10 => scalar_arguments(args),
1671        Function::Sin => scalar_arguments(args),
1672        Function::Sinh => scalar_arguments(args),
1673        Function::Sqrt => scalar_arguments(args),
1674        Function::Sqrtpi => StaticResult::Scalar,
1675        Function::Sum => StaticResult::Scalar,
1676        Function::Sumif => sumif_static_result(args),
1677        Function::Sumifs => not_implemented(args),
1678        Function::Tan => scalar_arguments(args),
1679        Function::Tanh => scalar_arguments(args),
1680        Function::ErrorType => not_implemented(args),
1681        Function::Isblank => not_implemented(args),
1682        Function::Iserr => not_implemented(args),
1683        Function::Iserror => not_implemented(args),
1684        Function::Iseven => not_implemented(args),
1685        Function::Isformula => not_implemented(args),
1686        Function::Islogical => not_implemented(args),
1687        Function::Isna => not_implemented(args),
1688        Function::Isnontext => not_implemented(args),
1689        Function::Isnumber => not_implemented(args),
1690        Function::Isodd => not_implemented(args),
1691        Function::Isomitted => not_implemented(args),
1692        Function::Isref => not_implemented(args),
1693        Function::Istext => not_implemented(args),
1694        Function::Na => StaticResult::Scalar,
1695        Function::Sheet => StaticResult::Scalar,
1696        Function::Type => not_implemented(args),
1697        Function::Address => not_implemented(args),
1698        Function::Areas => StaticResult::Scalar,
1699        Function::Choosecols => StaticResult::Unknown,
1700        Function::Chooserows => StaticResult::Unknown,
1701        Function::Expand => StaticResult::Unknown,
1702        Function::Hlookup => not_implemented(args),
1703        Function::Hstack => StaticResult::Unknown,
1704        Function::Index => static_analysis_index(args),
1705        Function::Indirect => static_analysis_indirect(args),
1706        Function::Lookup => not_implemented(args),
1707        Function::Match => not_implemented(args),
1708        Function::Offset => static_analysis_offset(args),
1709        Function::Row => StaticResult::Scalar,
1710        Function::Rows => not_implemented(args),
1711        Function::Vlookup => not_implemented(args),
1712        Function::Vstack => StaticResult::Unknown,
1713        Function::Wrapcols => StaticResult::Unknown,
1714        Function::Wraprows => StaticResult::Unknown,
1715        Function::Xlookup => not_implemented(args),
1716        Function::Xmatch => not_implemented(args),
1717        Function::Trimrange => StaticResult::Unknown,
1718        Function::Sort => StaticResult::Unknown,
1719        Function::Sortby => StaticResult::Unknown,
1720        Function::Unique => StaticResult::Unknown,
1721        Function::Filter => StaticResult::Unknown,
1722        Function::Take => StaticResult::Unknown,
1723        Function::Drop => StaticResult::Unknown,
1724        Function::Tocol => StaticResult::Unknown,
1725        Function::Torow => StaticResult::Unknown,
1726        Function::Transpose => StaticResult::Unknown,
1727        Function::Mmult => StaticResult::Unknown,
1728        Function::Bycol => StaticResult::Unknown,
1729        Function::Byrow => StaticResult::Unknown,
1730        Function::Map => StaticResult::Unknown,
1731        Function::Reduce => StaticResult::Unknown,
1732        Function::Scan => StaticResult::Unknown,
1733        Function::Makearray => StaticResult::Unknown,
1734        Function::Sequence => StaticResult::Unknown,
1735        Function::Randarray => StaticResult::Unknown,
1736        Function::Textsplit => StaticResult::Unknown,
1737        Function::Concat => not_implemented(args),
1738        Function::Concatenate => not_implemented(args),
1739        Function::Exact => not_implemented(args),
1740        Function::Find => not_implemented(args),
1741        // LEFT/MID/RIGHT broadcast element-wise: an array/range argument yields an array.
1742        Function::Left => scalar_arguments(args),
1743        Function::Len => not_implemented(args),
1744        // UPPER/LOWER broadcast element-wise: an array/range argument yields an array.
1745        Function::Lower => scalar_arguments(args),
1746        Function::Mid => scalar_arguments(args),
1747        Function::Rept => not_implemented(args),
1748        Function::Right => scalar_arguments(args),
1749        Function::Search => not_implemented(args),
1750        Function::Substitute => not_implemented(args),
1751        Function::Regexextract => {
1752            if args.len() == 3 {
1753                StaticResult::Unknown
1754            } else {
1755                not_implemented(args)
1756            }
1757        }
1758        Function::Regexreplace => not_implemented(args),
1759        Function::Regextest => not_implemented(args),
1760        Function::T => not_implemented(args),
1761        Function::Text => scalar_arguments(args),
1762        Function::Textafter => not_implemented(args),
1763        Function::Textbefore => not_implemented(args),
1764        Function::Textjoin => not_implemented(args),
1765        Function::Trim => not_implemented(args),
1766        Function::Unicode => not_implemented(args),
1767        Function::Unichar => not_implemented(args),
1768        Function::Char => not_implemented(args),
1769        Function::Clean => not_implemented(args),
1770        Function::Code => not_implemented(args),
1771        Function::Asc => not_implemented(args),
1772        Function::Arraytotext => not_implemented(args),
1773        Function::Dollar => not_implemented(args),
1774        Function::Findb => not_implemented(args),
1775        Function::Fixed => not_implemented(args),
1776        Function::Leftb => not_implemented(args),
1777        Function::Lenb => not_implemented(args),
1778        Function::Midb => not_implemented(args),
1779        Function::Numbervalue => not_implemented(args),
1780        Function::Proper => not_implemented(args),
1781        Function::Replace => not_implemented(args),
1782        Function::Replaceb => not_implemented(args),
1783        Function::Rightb => not_implemented(args),
1784        Function::Searchb => not_implemented(args),
1785        Function::Upper => scalar_arguments(args),
1786        Function::Value => not_implemented(args),
1787        Function::Valuetotext => not_implemented(args),
1788        Function::Average => not_implemented(args),
1789        Function::Averagea => not_implemented(args),
1790        Function::Avedev => not_implemented(args),
1791        Function::Averageif => not_implemented(args),
1792        Function::Averageifs => not_implemented(args),
1793        Function::Count => not_implemented(args),
1794        Function::Counta => not_implemented(args),
1795        Function::Countblank => not_implemented(args),
1796        Function::Countif => not_implemented(args),
1797        Function::Countifs => not_implemented(args),
1798        Function::Maxifs => not_implemented(args),
1799        Function::Minifs => not_implemented(args),
1800        // DATE broadcasts element-wise: an array/range argument yields an array.
1801        Function::Date => scalar_arguments(args),
1802        Function::Datedif => not_implemented(args),
1803        Function::Datevalue => not_implemented(args),
1804        Function::Day => scalar_arguments(args),
1805        Function::Edate => not_implemented(args),
1806        Function::Month => scalar_arguments(args),
1807        Function::Time => not_implemented(args),
1808        Function::Timevalue => not_implemented(args),
1809        Function::Hour => not_implemented(args),
1810        Function::Minute => not_implemented(args),
1811        Function::Second => not_implemented(args),
1812        Function::Now => not_implemented(args),
1813        Function::Today => not_implemented(args),
1814        Function::Year => scalar_arguments(args),
1815        Function::Days => not_implemented(args),
1816        Function::Days360 => not_implemented(args),
1817        Function::Weekday => scalar_arguments(args),
1818        Function::Weeknum => not_implemented(args),
1819        Function::Workday => not_implemented(args),
1820        Function::WorkdayIntl => not_implemented(args),
1821        Function::Yearfrac => not_implemented(args),
1822        Function::Isoweeknum => scalar_arguments(args),
1823        Function::Accrint => scalar_arguments(args),
1824        Function::Accrintm => scalar_arguments(args),
1825        Function::Disc => StaticResult::Scalar,
1826        Function::Fvschedule => StaticResult::Scalar,
1827        Function::Intrate => StaticResult::Scalar,
1828        Function::Pricedisc => StaticResult::Scalar,
1829        Function::Pricemat => StaticResult::Scalar,
1830        Function::Received => StaticResult::Scalar,
1831        Function::Yielddisc => StaticResult::Scalar,
1832        Function::Yieldmat => StaticResult::Scalar,
1833        Function::Cumipmt => not_implemented(args),
1834        Function::Cumprinc => not_implemented(args),
1835        Function::Db => not_implemented(args),
1836        Function::Ddb => not_implemented(args),
1837        Function::Dollarde => not_implemented(args),
1838        Function::Dollarfr => not_implemented(args),
1839        Function::Effect => not_implemented(args),
1840        Function::Fv => not_implemented(args),
1841        Function::Ipmt => not_implemented(args),
1842        Function::Irr => not_implemented(args),
1843        Function::Ispmt => not_implemented(args),
1844        Function::Mirr => not_implemented(args),
1845        Function::Nominal => not_implemented(args),
1846        Function::Nper => not_implemented(args),
1847        Function::Npv => not_implemented(args),
1848        Function::Pduration => not_implemented(args),
1849        Function::Pmt => not_implemented(args),
1850        Function::Ppmt => not_implemented(args),
1851        Function::Pv => not_implemented(args),
1852        Function::Rate => not_implemented(args),
1853        Function::Rri => not_implemented(args),
1854        Function::Sln => not_implemented(args),
1855        Function::Syd => not_implemented(args),
1856        Function::Tbilleq => not_implemented(args),
1857        Function::Tbillprice => not_implemented(args),
1858        Function::Tbillyield => not_implemented(args),
1859        Function::Xirr => not_implemented(args),
1860        Function::Xnpv => not_implemented(args),
1861        Function::Duration => StaticResult::Scalar,
1862        Function::Mduration => StaticResult::Scalar,
1863        Function::Price => StaticResult::Scalar,
1864        Function::Yield => StaticResult::Scalar,
1865        Function::Oddfprice => StaticResult::Scalar,
1866        Function::Oddfyield => StaticResult::Scalar,
1867        Function::Oddlprice => StaticResult::Scalar,
1868        Function::Oddlyield => StaticResult::Scalar,
1869        Function::Coupdaybs => StaticResult::Scalar,
1870        Function::Coupdays => StaticResult::Scalar,
1871        Function::Coupdaysnc => StaticResult::Scalar,
1872        Function::Coupncd => StaticResult::Scalar,
1873        Function::Coupnum => StaticResult::Scalar,
1874        Function::Couppcd => StaticResult::Scalar,
1875        Function::Amordegrc => StaticResult::Scalar,
1876        Function::Amorlinc => StaticResult::Scalar,
1877        Function::Vdb => StaticResult::Scalar,
1878        Function::Besseli => scalar_arguments(args),
1879        Function::Besselj => scalar_arguments(args),
1880        Function::Besselk => scalar_arguments(args),
1881        Function::Bessely => scalar_arguments(args),
1882        Function::Erf => scalar_arguments(args),
1883        Function::Erfc => scalar_arguments(args),
1884        Function::ErfcPrecise => scalar_arguments(args),
1885        Function::ErfPrecise => scalar_arguments(args),
1886        Function::Bin2dec => scalar_arguments(args),
1887        Function::Bin2hex => scalar_arguments(args),
1888        Function::Bin2oct => scalar_arguments(args),
1889        Function::Dec2Bin => scalar_arguments(args),
1890        Function::Dec2hex => scalar_arguments(args),
1891        Function::Dec2oct => scalar_arguments(args),
1892        Function::Hex2bin => scalar_arguments(args),
1893        Function::Hex2dec => scalar_arguments(args),
1894        Function::Hex2oct => scalar_arguments(args),
1895        Function::Oct2bin => scalar_arguments(args),
1896        Function::Oct2dec => scalar_arguments(args),
1897        Function::Oct2hex => scalar_arguments(args),
1898        Function::Bitand => scalar_arguments(args),
1899        Function::Bitlshift => scalar_arguments(args),
1900        Function::Bitor => scalar_arguments(args),
1901        Function::Bitrshift => scalar_arguments(args),
1902        Function::Bitxor => scalar_arguments(args),
1903        Function::Complex => scalar_arguments(args),
1904        Function::Imabs => scalar_arguments(args),
1905        Function::Imaginary => scalar_arguments(args),
1906        Function::Imargument => scalar_arguments(args),
1907        Function::Imconjugate => scalar_arguments(args),
1908        Function::Imcos => scalar_arguments(args),
1909        Function::Imcosh => scalar_arguments(args),
1910        Function::Imcot => scalar_arguments(args),
1911        Function::Imcsc => scalar_arguments(args),
1912        Function::Imcsch => scalar_arguments(args),
1913        Function::Imdiv => scalar_arguments(args),
1914        Function::Imexp => scalar_arguments(args),
1915        Function::Imln => scalar_arguments(args),
1916        Function::Imlog10 => scalar_arguments(args),
1917        Function::Imlog2 => scalar_arguments(args),
1918        Function::Impower => scalar_arguments(args),
1919        Function::Improduct => scalar_arguments(args),
1920        Function::Imreal => scalar_arguments(args),
1921        Function::Imsec => scalar_arguments(args),
1922        Function::Imsech => scalar_arguments(args),
1923        Function::Imsin => scalar_arguments(args),
1924        Function::Imsinh => scalar_arguments(args),
1925        Function::Imsqrt => scalar_arguments(args),
1926        Function::Imsub => scalar_arguments(args),
1927        Function::Imsum => scalar_arguments(args),
1928        Function::Imtan => scalar_arguments(args),
1929        Function::Convert => not_implemented(args),
1930        Function::Delta => not_implemented(args),
1931        Function::Gestep => not_implemented(args),
1932        Function::Subtotal => not_implemented(args),
1933        Function::Rand => not_implemented(args),
1934        Function::Randbetween => scalar_arguments(args),
1935        Function::Eomonth => scalar_arguments(args),
1936        Function::Formulatext => not_implemented(args),
1937        Function::Geomean => not_implemented(args),
1938        Function::Networkdays => not_implemented(args),
1939        Function::NetworkdaysIntl => not_implemented(args),
1940        Function::Acot => scalar_arguments(args),
1941        Function::Acoth => scalar_arguments(args),
1942        Function::Cot => scalar_arguments(args),
1943        Function::Coth => scalar_arguments(args),
1944        Function::Csc => scalar_arguments(args),
1945        Function::Csch => scalar_arguments(args),
1946        Function::Sec => scalar_arguments(args),
1947        Function::Sech => scalar_arguments(args),
1948        Function::Exp => scalar_arguments(args),
1949        Function::Fact => scalar_arguments(args),
1950        Function::Factdouble => scalar_arguments(args),
1951        Function::Sign => scalar_arguments(args),
1952        Function::Radians => scalar_arguments(args),
1953        Function::Degrees => scalar_arguments(args),
1954        Function::Int => scalar_arguments(args),
1955        Function::Even => scalar_arguments(args),
1956        Function::Odd => scalar_arguments(args),
1957        Function::Ceiling => scalar_arguments(args),
1958        Function::CeilingMath => scalar_arguments(args),
1959        Function::CeilingPrecise => scalar_arguments(args),
1960        Function::Floor => scalar_arguments(args),
1961        Function::FloorMath => scalar_arguments(args),
1962        Function::FloorPrecise => scalar_arguments(args),
1963        Function::IsoCeiling => scalar_arguments(args),
1964        Function::Mod => scalar_arguments(args),
1965        Function::Quotient => scalar_arguments(args),
1966        Function::Mround => scalar_arguments(args),
1967        Function::Trunc => scalar_arguments(args),
1968        Function::Gcd => StaticResult::Scalar,
1969        Function::Lcm => StaticResult::Scalar,
1970        Function::Base => scalar_arguments(args),
1971        Function::Decimal => scalar_arguments(args),
1972        Function::Roman => scalar_arguments(args),
1973        Function::Arabic => scalar_arguments(args),
1974        Function::Combin => scalar_arguments(args),
1975        Function::Combina => scalar_arguments(args),
1976        Function::Sumsq => StaticResult::Scalar,
1977        Function::Mdeterm => StaticResult::Scalar,
1978        Function::Minverse => StaticResult::Unknown,
1979        Function::Munit => StaticResult::Unknown,
1980        Function::Multinomial => StaticResult::Scalar,
1981        Function::Seriessum => StaticResult::Scalar,
1982        Function::Sumproduct => StaticResult::Scalar,
1983        Function::Percentof => StaticResult::Scalar,
1984        Function::N => scalar_arguments(args),
1985        Function::Sheets => scalar_arguments(args),
1986        Function::Cell => StaticResult::Unknown,
1987        Function::Info => StaticResult::Unknown,
1988        Function::Dget => not_implemented(args),
1989        Function::Dmax => not_implemented(args),
1990        Function::Dmin => not_implemented(args),
1991        Function::Dcount => not_implemented(args),
1992        Function::Daverage => not_implemented(args),
1993        Function::Dsum => not_implemented(args),
1994        Function::Dcounta => not_implemented(args),
1995        Function::Dproduct => not_implemented(args),
1996        Function::Dstdev => not_implemented(args),
1997        Function::Dvar => not_implemented(args),
1998        Function::Dvarp => not_implemented(args),
1999        Function::Dstdevp => not_implemented(args),
2000        Function::BetaDist => StaticResult::Scalar,
2001        Function::BetaInv => StaticResult::Scalar,
2002        Function::BinomDist => StaticResult::Scalar,
2003        Function::BinomDistRange => StaticResult::Scalar,
2004        Function::BinomInv => StaticResult::Scalar,
2005        Function::ChisqDist => StaticResult::Scalar,
2006        Function::ChisqDistRT => StaticResult::Scalar,
2007        Function::ChisqInv => StaticResult::Scalar,
2008        Function::ChisqInvRT => StaticResult::Scalar,
2009        Function::ChisqTest => StaticResult::Scalar,
2010        Function::ConfidenceNorm => StaticResult::Scalar,
2011        Function::ConfidenceT => StaticResult::Scalar,
2012        Function::CovarianceP => StaticResult::Scalar,
2013        Function::CovarianceS => StaticResult::Scalar,
2014        Function::Devsq => StaticResult::Scalar,
2015        Function::ExponDist => StaticResult::Scalar,
2016        Function::FDist => StaticResult::Scalar,
2017        Function::FDistRT => StaticResult::Scalar,
2018        Function::FInv => StaticResult::Scalar,
2019        Function::FInvRT => StaticResult::Scalar,
2020        Function::FTest => StaticResult::Scalar,
2021        Function::Fisher => StaticResult::Scalar,
2022        Function::FisherInv => StaticResult::Scalar,
2023        Function::Gamma => StaticResult::Scalar,
2024        Function::GammaDist => StaticResult::Scalar,
2025        Function::GammaInv => StaticResult::Scalar,
2026        Function::GammaLn => StaticResult::Scalar,
2027        Function::GammaLnPrecise => StaticResult::Scalar,
2028        Function::HypGeomDist => StaticResult::Scalar,
2029        Function::LogNormDist => StaticResult::Scalar,
2030        Function::LogNormInv => StaticResult::Scalar,
2031        Function::NegbinomDist => StaticResult::Scalar,
2032        Function::NormDist => StaticResult::Scalar,
2033        Function::NormInv => StaticResult::Scalar,
2034        Function::NormSdist => StaticResult::Scalar,
2035        Function::NormSInv => StaticResult::Scalar,
2036        Function::Pearson => StaticResult::Scalar,
2037        Function::Phi => StaticResult::Scalar,
2038        Function::PoissonDist => StaticResult::Scalar,
2039        Function::Standardize => StaticResult::Scalar,
2040        Function::Stdev => StaticResult::Scalar,
2041        Function::StDevP => StaticResult::Scalar,
2042        Function::StDevS => StaticResult::Scalar,
2043        Function::Stdeva => StaticResult::Scalar,
2044        Function::Stdevpa => StaticResult::Scalar,
2045        Function::TDist => StaticResult::Scalar,
2046        Function::TDist2T => StaticResult::Scalar,
2047        Function::TDistRT => StaticResult::Scalar,
2048        Function::TInv => StaticResult::Scalar,
2049        Function::TInv2T => StaticResult::Scalar,
2050        Function::TTest => StaticResult::Scalar,
2051        Function::VarP => StaticResult::Scalar,
2052        Function::VarS => StaticResult::Scalar,
2053        Function::VarpA => StaticResult::Scalar,
2054        Function::VarA => StaticResult::Scalar,
2055        Function::WeibullDist => StaticResult::Scalar,
2056        Function::ZTest => StaticResult::Scalar,
2057        Function::BetaDistCompat => StaticResult::Scalar,
2058        Function::HypGeomDistCompat => StaticResult::Scalar,
2059        Function::LogNormDistCompat => StaticResult::Scalar,
2060        Function::NegbinomDistCompat => StaticResult::Scalar,
2061        Function::NormSDistCompat => StaticResult::Scalar,
2062        Function::TDistCompat => StaticResult::Scalar,
2063        Function::BetaInvCompat => StaticResult::Scalar,
2064        Function::BinomDistCompat => StaticResult::Scalar,
2065        Function::ChiDistCompat => StaticResult::Scalar,
2066        Function::ChiInvCompat => StaticResult::Scalar,
2067        Function::ChiTestCompat => StaticResult::Scalar,
2068        Function::ConfidenceCompat => StaticResult::Scalar,
2069        Function::CovarCompat => StaticResult::Scalar,
2070        Function::CritbinomCompat => StaticResult::Scalar,
2071        Function::ExponDistCompat => StaticResult::Scalar,
2072        Function::FDistCompat => StaticResult::Scalar,
2073        Function::FInvCompat => StaticResult::Scalar,
2074        Function::FTestCompat => StaticResult::Scalar,
2075        Function::GammaDistCompat => StaticResult::Scalar,
2076        Function::GammaInvCompat => StaticResult::Scalar,
2077        Function::LoginvCompat => StaticResult::Scalar,
2078        Function::ModeCompat => StaticResult::Scalar,
2079        Function::NormDistCompat => StaticResult::Scalar,
2080        Function::NormInvCompat => StaticResult::Scalar,
2081        Function::NormSInvCompat => StaticResult::Scalar,
2082        Function::PercentileCompat => StaticResult::Scalar,
2083        Function::PercentrankCompat => StaticResult::Scalar,
2084        Function::PoissonCompat => StaticResult::Scalar,
2085        Function::QuartileCompat => StaticResult::Scalar,
2086        Function::RankCompat => StaticResult::Scalar,
2087        Function::StDevPCompat => StaticResult::Scalar,
2088        Function::TInvCompat => StaticResult::Scalar,
2089        Function::TTestCompat => StaticResult::Scalar,
2090        Function::VarCompat => StaticResult::Scalar,
2091        Function::VarPCompat => StaticResult::Scalar,
2092        Function::WeibullCompat => StaticResult::Scalar,
2093        Function::ZTestCompat => StaticResult::Scalar,
2094        Function::Sumx2my2 => StaticResult::Scalar,
2095        Function::Sumx2py2 => StaticResult::Scalar,
2096        Function::Sumxmy2 => StaticResult::Scalar,
2097        Function::Correl => StaticResult::Scalar,
2098        Function::Rsq => StaticResult::Scalar,
2099        Function::Intercept => StaticResult::Scalar,
2100        Function::Slope => StaticResult::Scalar,
2101        Function::Steyx => StaticResult::Scalar,
2102        Function::Forecast => StaticResult::Scalar,
2103        Function::ForecastLinear => StaticResult::Scalar,
2104        Function::ForecastEts => StaticResult::Scalar,
2105        Function::ForecastEtsConfint => StaticResult::Scalar,
2106        Function::ForecastEtsSeasonality => StaticResult::Scalar,
2107        Function::ForecastEtsStat => StaticResult::Scalar,
2108        // Spill-returning functions
2109        Function::Frequency => StaticResult::Unknown,
2110        Function::Growth => StaticResult::Unknown,
2111        Function::Linest => StaticResult::Unknown,
2112        Function::Logest => StaticResult::Unknown,
2113        Function::ModeMult => StaticResult::Unknown,
2114        Function::Trend => StaticResult::Unknown,
2115        // Scalar-returning functions
2116        Function::ModeSingl => StaticResult::Scalar,
2117        Function::PercentileExc => StaticResult::Scalar,
2118        Function::PercentileInc => StaticResult::Scalar,
2119        Function::PercentrankExc => StaticResult::Scalar,
2120        Function::PercentrankInc => StaticResult::Scalar,
2121        Function::Permut => StaticResult::Scalar,
2122        Function::Permutationa => StaticResult::Scalar,
2123        Function::Prob => StaticResult::Scalar,
2124        Function::QuartileExc => StaticResult::Scalar,
2125        Function::QuartileInc => StaticResult::Scalar,
2126        Function::Trimmean => StaticResult::Scalar,
2127        Function::Gauss => StaticResult::Scalar,
2128        Function::Harmean => StaticResult::Scalar,
2129        Function::Kurt => StaticResult::Scalar,
2130        Function::Large => StaticResult::Scalar,
2131        Function::MaxA => StaticResult::Scalar,
2132        Function::Median => StaticResult::Scalar,
2133        Function::MinA => StaticResult::Scalar,
2134        Function::RankAvg => StaticResult::Scalar,
2135        Function::RankEq => StaticResult::Scalar,
2136        Function::Skew => StaticResult::Scalar,
2137        Function::SkewP => StaticResult::Scalar,
2138        Function::Small => StaticResult::Scalar,
2139    }
2140}