1152 lines
50 KiB
Rust
1152 lines
50 KiB
Rust
use crate::functions::Function;
|
|
|
|
use super::Node;
|
|
|
|
use regex::Regex;
|
|
use std::sync::OnceLock;
|
|
|
|
static RANGE_REFERENCE_REGEX: OnceLock<Regex> = OnceLock::new();
|
|
|
|
#[allow(clippy::expect_used)]
|
|
fn get_re() -> &'static Regex {
|
|
RANGE_REFERENCE_REGEX
|
|
.get_or_init(|| Regex::new(r":[A-Z]*[0-9]*$").expect("Regex is known to be valid"))
|
|
}
|
|
|
|
fn is_range_reference(s: &str) -> bool {
|
|
get_re().is_match(s)
|
|
}
|
|
|
|
/*
|
|
|
|
# NOTES on the Implicit Intersection operator: @
|
|
|
|
Sometimes we obtain a range where we expected a single argument. This can happen:
|
|
|
|
* As an argument of a function, eg: `SIN(A1:A5)`
|
|
* As the result of a computation of a formula `=A1:A5`
|
|
|
|
In previous versions of the Friendly Giant the spreadsheet engine would perform an operation called _implicit intersection_
|
|
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
|
|
as the cell. If there is just one we return that otherwise we return the `#REF!` error.
|
|
|
|
Examples:
|
|
|
|
* Siting on `C3` the formula `=D1:D5` will return `D3`
|
|
* Sitting on `C3` the formula `=D:D` will return `D3`
|
|
* Sitting on `C3` the formula `=A1:A7` will return `A3`
|
|
* Sitting on `C3` the formula `=A5:A8` will return `#REF!`
|
|
* Sitting on `C3` the formula `D1:G7` will return `#REF!`
|
|
|
|
Today's version of the engine will result in a dynamic array spilling the result through several cells.
|
|
To force the old behaviour we can use the _implicit intersection operator_: @
|
|
|
|
* `=@A1:A7` or `=SIN(@A1:A7)
|
|
|
|
When parsing formulas that come form old workbooks this is done automatically.
|
|
We call this version of the II operator the _automatic_ II operator.
|
|
|
|
We can also insert the II operator in places where before was impossible:
|
|
|
|
* `=SUM(@A1:A7)`
|
|
|
|
This formulas will not be compatible with old versions of the engine. The FG will stringify this as `=SUM(_xlfn.SIMPLE(A1:A7))`.
|
|
*/
|
|
|
|
/// Transverses the formula tree adding the implicit intersection operator in all arguments of functions that
|
|
/// expect a scalar but get a range.
|
|
/// * A:A => @A:A
|
|
/// * SIN(A1:D1) => SIN(@A1:D1)
|
|
///
|
|
/// Assumes formula return a scalar
|
|
pub fn add_implicit_intersection(node: &mut Node, add: bool) {
|
|
match node {
|
|
Node::BooleanKind(_)
|
|
| Node::NumberKind(_)
|
|
| Node::StringKind(_)
|
|
| Node::ErrorKind(_)
|
|
| Node::EmptyArgKind
|
|
| Node::ParseErrorKind { .. }
|
|
| Node::WrongReferenceKind { .. }
|
|
| Node::WrongRangeKind { .. }
|
|
| Node::InvalidFunctionKind { .. }
|
|
| Node::ArrayKind(_)
|
|
| Node::ReferenceKind { .. } => {}
|
|
Node::ImplicitIntersection { child, .. } => {
|
|
// We need to check wether the II can be automatic or not
|
|
let mut new_node = child.as_ref().clone();
|
|
add_implicit_intersection(&mut new_node, add);
|
|
if matches!(&new_node, Node::ImplicitIntersection { .. }) {
|
|
*node = new_node
|
|
}
|
|
}
|
|
Node::RangeKind {
|
|
row1,
|
|
column1,
|
|
row2,
|
|
column2,
|
|
sheet_name,
|
|
sheet_index,
|
|
absolute_row1,
|
|
absolute_column1,
|
|
absolute_row2,
|
|
absolute_column2,
|
|
} => {
|
|
if add {
|
|
*node = Node::ImplicitIntersection {
|
|
automatic: true,
|
|
child: Box::new(Node::RangeKind {
|
|
sheet_name: sheet_name.clone(),
|
|
sheet_index: *sheet_index,
|
|
absolute_row1: *absolute_row1,
|
|
absolute_column1: *absolute_column1,
|
|
row1: *row1,
|
|
column1: *column1,
|
|
absolute_row2: *absolute_row2,
|
|
absolute_column2: *absolute_column2,
|
|
row2: *row2,
|
|
column2: *column2,
|
|
}),
|
|
};
|
|
}
|
|
}
|
|
Node::OpRangeKind { left, right } => {
|
|
if add {
|
|
*node = Node::ImplicitIntersection {
|
|
automatic: true,
|
|
child: Box::new(Node::OpRangeKind {
|
|
left: left.clone(),
|
|
right: right.clone(),
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
// operations
|
|
Node::UnaryKind { right, .. } => add_implicit_intersection(right, add),
|
|
Node::OpConcatenateKind { left, right }
|
|
| Node::OpSumKind { left, right, .. }
|
|
| Node::OpProductKind { left, right, .. }
|
|
| Node::OpPowerKind { left, right, .. }
|
|
| Node::CompareKind { left, right, .. } => {
|
|
add_implicit_intersection(left, add);
|
|
add_implicit_intersection(right, add);
|
|
}
|
|
|
|
Node::DefinedNameKind(v) => {
|
|
if add {
|
|
// Not all defined names deserve the II operator
|
|
// For instance =Sheet1!A1 doesn't need to be intersected
|
|
if is_range_reference(&v.2) {
|
|
*node = Node::ImplicitIntersection {
|
|
automatic: true,
|
|
child: Box::new(Node::DefinedNameKind(v.to_owned())),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Node::WrongVariableKind(v) => {
|
|
if add {
|
|
*node = Node::ImplicitIntersection {
|
|
automatic: true,
|
|
child: Box::new(Node::WrongVariableKind(v.to_owned())),
|
|
}
|
|
}
|
|
}
|
|
Node::TableNameKind(_) => {
|
|
// noop for now
|
|
}
|
|
Node::FunctionKind { kind, args } => {
|
|
let arg_count = args.len();
|
|
let signature = get_function_args_signature(kind, arg_count);
|
|
for index in 0..arg_count {
|
|
if matches!(signature[index], Signature::Scalar)
|
|
&& matches!(
|
|
run_static_analysis_on_node(&args[index]),
|
|
StaticResult::Range(_, _) | StaticResult::Unknown
|
|
)
|
|
{
|
|
add_implicit_intersection(&mut args[index], true);
|
|
} else {
|
|
add_implicit_intersection(&mut args[index], false);
|
|
}
|
|
}
|
|
if add
|
|
&& matches!(
|
|
run_static_analysis_on_node(node),
|
|
StaticResult::Range(_, _) | StaticResult::Unknown
|
|
)
|
|
{
|
|
*node = Node::ImplicitIntersection {
|
|
automatic: true,
|
|
child: Box::new(node.clone()),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pub(crate) enum StaticResult {
|
|
Scalar,
|
|
Array(i32, i32),
|
|
Range(i32, i32),
|
|
Unknown,
|
|
// TODO: What if one of the dimensions is known?
|
|
// what if the dimensions are unknown but bounded?
|
|
}
|
|
|
|
fn static_analysis_op_nodes(left: &Node, right: &Node) -> StaticResult {
|
|
let lhs = run_static_analysis_on_node(left);
|
|
let rhs = run_static_analysis_on_node(right);
|
|
match (lhs, rhs) {
|
|
(StaticResult::Scalar, StaticResult::Scalar) => StaticResult::Scalar,
|
|
(StaticResult::Scalar, StaticResult::Array(a, b) | StaticResult::Range(a, b)) => {
|
|
StaticResult::Array(a, b)
|
|
}
|
|
|
|
(StaticResult::Array(a, b) | StaticResult::Range(a, b), StaticResult::Scalar) => {
|
|
StaticResult::Array(a, b)
|
|
}
|
|
(
|
|
StaticResult::Array(a1, b1) | StaticResult::Range(a1, b1),
|
|
StaticResult::Array(a2, b2) | StaticResult::Range(a2, b2),
|
|
) => StaticResult::Array(a1.max(a2), b1.max(b2)),
|
|
|
|
(_, StaticResult::Unknown) => StaticResult::Unknown,
|
|
(StaticResult::Unknown, _) => StaticResult::Unknown,
|
|
}
|
|
}
|
|
|
|
// Returns:
|
|
// * Scalar if we can proof the result of the evaluation is a scalar
|
|
// * Array(a, b) if we know it will be an a x b array.
|
|
// * Range(a, b) if we know it will be a a x b range.
|
|
// * Unknown if we cannot guaranty either
|
|
fn run_static_analysis_on_node(node: &Node) -> StaticResult {
|
|
match node {
|
|
Node::BooleanKind(_)
|
|
| Node::NumberKind(_)
|
|
| Node::StringKind(_)
|
|
| Node::ErrorKind(_)
|
|
| Node::EmptyArgKind => StaticResult::Scalar,
|
|
Node::UnaryKind { right, .. } => run_static_analysis_on_node(right),
|
|
Node::ParseErrorKind { .. } => {
|
|
// StaticResult::Unknown is also valid
|
|
StaticResult::Scalar
|
|
}
|
|
Node::WrongReferenceKind { .. } => {
|
|
// StaticResult::Unknown is also valid
|
|
StaticResult::Scalar
|
|
}
|
|
Node::WrongRangeKind { .. } => {
|
|
// StaticResult::Unknown or Array is also valid
|
|
StaticResult::Scalar
|
|
}
|
|
Node::InvalidFunctionKind { .. } => {
|
|
// StaticResult::Unknown is also valid
|
|
StaticResult::Scalar
|
|
}
|
|
Node::ArrayKind(array) => {
|
|
let n = array.len() as i32;
|
|
// FIXME: This is a placeholder until we implement arrays
|
|
StaticResult::Array(n, 1)
|
|
}
|
|
Node::RangeKind {
|
|
row1,
|
|
column1,
|
|
row2,
|
|
column2,
|
|
..
|
|
} => StaticResult::Range(row2 - row1, column2 - column1),
|
|
Node::OpRangeKind { .. } => {
|
|
// TODO: We could do a bit better here
|
|
StaticResult::Unknown
|
|
}
|
|
Node::ReferenceKind { .. } => StaticResult::Scalar,
|
|
|
|
// binary operations
|
|
Node::OpConcatenateKind { left, right } => static_analysis_op_nodes(left, right),
|
|
Node::OpSumKind { left, right, .. } => static_analysis_op_nodes(left, right),
|
|
Node::OpProductKind { left, right, .. } => static_analysis_op_nodes(left, right),
|
|
Node::OpPowerKind { left, right, .. } => static_analysis_op_nodes(left, right),
|
|
Node::CompareKind { left, right, .. } => static_analysis_op_nodes(left, right),
|
|
|
|
// defined names
|
|
Node::DefinedNameKind(_) => StaticResult::Unknown,
|
|
Node::WrongVariableKind(_) => StaticResult::Unknown,
|
|
Node::TableNameKind(_) => StaticResult::Unknown,
|
|
Node::FunctionKind { kind, args } => static_analysis_on_function(kind, args),
|
|
Node::ImplicitIntersection { .. } => StaticResult::Scalar,
|
|
}
|
|
}
|
|
|
|
// If all the arguments are scalars the function will return a scalar
|
|
// If any of the arguments is a range or an array it will return an array
|
|
fn scalar_arguments(args: &[Node]) -> StaticResult {
|
|
let mut n = 0;
|
|
let mut m = 0;
|
|
for arg in args {
|
|
match run_static_analysis_on_node(arg) {
|
|
StaticResult::Scalar => {
|
|
// noop
|
|
}
|
|
StaticResult::Array(a, b) | StaticResult::Range(a, b) => {
|
|
n = n.max(a);
|
|
m = m.max(b);
|
|
}
|
|
StaticResult::Unknown => return StaticResult::Unknown,
|
|
}
|
|
}
|
|
if n == 0 && m == 0 {
|
|
return StaticResult::Scalar;
|
|
}
|
|
StaticResult::Array(n, m)
|
|
}
|
|
|
|
// We only care if the function can return a range or not
|
|
fn not_implemented(_args: &[Node]) -> StaticResult {
|
|
StaticResult::Scalar
|
|
}
|
|
|
|
fn static_analysis_offset(args: &[Node]) -> StaticResult {
|
|
// If first argument is a single cell reference and there are no4th and 5th argument,
|
|
// or they are 1, then it is a scalar
|
|
let arg_count = args.len();
|
|
if arg_count < 3 {
|
|
// Actually an error
|
|
return StaticResult::Scalar;
|
|
}
|
|
if !matches!(args[0], Node::ReferenceKind { .. }) {
|
|
return StaticResult::Unknown;
|
|
}
|
|
if arg_count == 3 {
|
|
return StaticResult::Scalar;
|
|
}
|
|
match args[3] {
|
|
Node::NumberKind(f) => {
|
|
if f != 1.0 {
|
|
return StaticResult::Unknown;
|
|
}
|
|
}
|
|
_ => return StaticResult::Unknown,
|
|
};
|
|
if arg_count == 4 {
|
|
return StaticResult::Scalar;
|
|
}
|
|
match args[4] {
|
|
Node::NumberKind(f) => {
|
|
if f != 1.0 {
|
|
return StaticResult::Unknown;
|
|
}
|
|
}
|
|
_ => return StaticResult::Unknown,
|
|
};
|
|
// Both height and width are explicitly 1, so OFFSET will return a single cell
|
|
StaticResult::Scalar
|
|
}
|
|
|
|
// fn static_analysis_choose(_args: &[Node]) -> StaticResult {
|
|
// // We will always insert the @ in CHOOSE, but technically it is only needed if one of the elements is a range
|
|
// StaticResult::Unknown
|
|
// }
|
|
|
|
fn static_analysis_indirect(_args: &[Node]) -> StaticResult {
|
|
// We will always insert the @, but we don't need to do that in every scenario`
|
|
StaticResult::Unknown
|
|
}
|
|
|
|
fn static_analysis_index(_args: &[Node]) -> StaticResult {
|
|
// INDEX has two forms, but they are indistinguishable at parse time.
|
|
StaticResult::Unknown
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
enum Signature {
|
|
Scalar,
|
|
Vector,
|
|
Error,
|
|
}
|
|
|
|
fn args_signature_no_args(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 0 {
|
|
vec![]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_scalars(
|
|
arg_count: usize,
|
|
required_count: usize,
|
|
optional_count: usize,
|
|
) -> Vec<Signature> {
|
|
if arg_count >= required_count && arg_count <= required_count + optional_count {
|
|
vec![Signature::Scalar; arg_count]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_one_vector(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 1 {
|
|
vec![Signature::Vector]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_sumif(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Vector, Signature::Scalar]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Scalar, Signature::Vector]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
// 1 or none scalars
|
|
fn args_signature_sheet(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 0 {
|
|
vec![]
|
|
} else if arg_count == 1 {
|
|
vec![Signature::Scalar]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_hlookup(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Vector, Signature::Scalar]
|
|
} else if arg_count == 4 {
|
|
vec![
|
|
Signature::Vector,
|
|
Signature::Vector,
|
|
Signature::Scalar,
|
|
Signature::Vector,
|
|
]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_index(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Vector, Signature::Scalar]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
|
|
} else if arg_count == 4 {
|
|
vec![
|
|
Signature::Vector,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_lookup(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Vector, Signature::Vector]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Vector, Signature::Vector]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_match(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Vector, Signature::Vector]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Vector, Signature::Scalar]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_offset(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
|
|
} else if arg_count == 4 {
|
|
vec![
|
|
Signature::Vector,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
]
|
|
} else if arg_count == 5 {
|
|
vec![
|
|
Signature::Vector,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_row(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 0 {
|
|
vec![]
|
|
} else if arg_count == 1 {
|
|
vec![Signature::Vector]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_xlookup(arg_count: usize) -> Vec<Signature> {
|
|
if !(3..=6).contains(&arg_count) {
|
|
return vec![Signature::Error; arg_count];
|
|
}
|
|
let mut result = vec![Signature::Scalar; arg_count];
|
|
result[0] = Signature::Vector;
|
|
result[1] = Signature::Vector;
|
|
result[2] = Signature::Vector;
|
|
result
|
|
}
|
|
|
|
fn args_signature_textafter(arg_count: usize) -> Vec<Signature> {
|
|
if !(2..=6).contains(&arg_count) {
|
|
vec![Signature::Scalar; arg_count]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_textjoin(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count >= 3 {
|
|
let mut result = vec![Signature::Vector; arg_count];
|
|
result[0] = Signature::Scalar;
|
|
result[1] = Signature::Scalar;
|
|
result
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_npv(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count < 2 {
|
|
return vec![Signature::Error; arg_count];
|
|
}
|
|
let mut result = vec![Signature::Vector; arg_count];
|
|
result[0] = Signature::Scalar;
|
|
result
|
|
}
|
|
|
|
fn args_signature_irr(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count > 2 {
|
|
vec![Signature::Error; arg_count]
|
|
} else if arg_count == 1 {
|
|
vec![Signature::Vector]
|
|
} else {
|
|
vec![Signature::Vector, Signature::Scalar]
|
|
}
|
|
}
|
|
|
|
fn args_signature_xirr(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Vector; arg_count]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Vector, Signature::Vector, Signature::Scalar]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
fn args_signature_mirr(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count != 3 {
|
|
vec![Signature::Error; arg_count]
|
|
} else {
|
|
vec![Signature::Vector, Signature::Scalar, Signature::Scalar]
|
|
}
|
|
}
|
|
|
|
fn args_signature_xnpv(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count != 3 {
|
|
vec![Signature::Error; arg_count]
|
|
} else {
|
|
vec![Signature::Scalar, Signature::Vector, Signature::Vector]
|
|
}
|
|
}
|
|
|
|
// NETWORKDAYS(start_date, end_date, [holidays])
|
|
// Parameters: start_date (scalar), end_date (scalar), holidays (optional vector)
|
|
fn args_signature_networkdays(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Scalar, Signature::Scalar]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Scalar, Signature::Scalar, Signature::Vector]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
// NETWORKDAYS.INTL(start_date, end_date, [weekend], [holidays])
|
|
// Parameters: start_date (scalar), end_date (scalar), weekend (optional scalar), holidays (optional vector)
|
|
fn args_signature_networkdays_intl(arg_count: usize) -> Vec<Signature> {
|
|
if arg_count == 2 {
|
|
vec![Signature::Scalar, Signature::Scalar]
|
|
} else if arg_count == 3 {
|
|
vec![Signature::Scalar, Signature::Scalar, Signature::Scalar]
|
|
} else if arg_count == 4 {
|
|
vec![
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Scalar,
|
|
Signature::Vector,
|
|
]
|
|
} else {
|
|
vec![Signature::Error; arg_count]
|
|
}
|
|
}
|
|
|
|
// FIXME: This is terrible duplications of efforts. We use the signature in at least three different places:
|
|
// 1. When computing the function
|
|
// 2. Checking the arguments to see if we need to insert the implicit intersection operator
|
|
// 3. Understanding the return value
|
|
//
|
|
// The signature of the functions should be defined only once
|
|
|
|
// Given a function and a number of arguments this returns the arguments at each position
|
|
// are expected to be scalars or vectors (array/ranges).
|
|
// Sets signature::Error to all arguments if the number of arguments is incorrect.
|
|
fn get_function_args_signature(kind: &Function, arg_count: usize) -> Vec<Signature> {
|
|
match kind {
|
|
Function::And => vec![Signature::Vector; arg_count],
|
|
Function::False => args_signature_no_args(arg_count),
|
|
Function::If => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Iferror => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Ifna => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Ifs => vec![Signature::Scalar; arg_count],
|
|
Function::Not => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Or => vec![Signature::Vector; arg_count],
|
|
Function::Switch => vec![Signature::Scalar; arg_count],
|
|
Function::True => args_signature_no_args(arg_count),
|
|
Function::Xor => vec![Signature::Vector; arg_count],
|
|
Function::Abs => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Acos => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Acosh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Asin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Asinh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Atan => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Atan2 => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Atanh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Choose => vec![Signature::Scalar; arg_count],
|
|
Function::Column => args_signature_row(arg_count),
|
|
Function::Columns => args_signature_one_vector(arg_count),
|
|
Function::Ln => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Log => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Log10 => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Cos => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Cosh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Max => vec![Signature::Vector; arg_count],
|
|
Function::Min => vec![Signature::Vector; arg_count],
|
|
Function::Pi => args_signature_no_args(arg_count),
|
|
Function::Power => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Product => vec![Signature::Vector; arg_count],
|
|
Function::Round => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Rounddown => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Roundup => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Sin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sinh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sqrt => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sqrtpi => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sum => vec![Signature::Vector; arg_count],
|
|
Function::Sumif => args_signature_sumif(arg_count),
|
|
Function::Sumifs => vec![Signature::Vector; arg_count],
|
|
Function::Tan => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Tanh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::ErrorType => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isblank => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Iserr => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Iserror => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Iseven => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isformula => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Islogical => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isna => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isnontext => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isnumber => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isodd => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Isref => args_signature_one_vector(arg_count),
|
|
Function::Istext => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Na => args_signature_no_args(arg_count),
|
|
Function::Sheet => args_signature_sheet(arg_count),
|
|
Function::Type => args_signature_one_vector(arg_count),
|
|
Function::Hlookup => args_signature_hlookup(arg_count),
|
|
Function::Index => args_signature_index(arg_count),
|
|
Function::Indirect => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Lookup => args_signature_lookup(arg_count),
|
|
Function::Match => args_signature_match(arg_count),
|
|
Function::Offset => args_signature_offset(arg_count),
|
|
Function::Row => args_signature_row(arg_count),
|
|
Function::Rows => args_signature_one_vector(arg_count),
|
|
Function::Vlookup => args_signature_hlookup(arg_count),
|
|
Function::Xlookup => args_signature_xlookup(arg_count),
|
|
Function::Concat => vec![Signature::Vector; arg_count],
|
|
Function::Concatenate => vec![Signature::Scalar; arg_count],
|
|
Function::Exact => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Find => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Left => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Len => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Lower => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Mid => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Rept => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Right => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Search => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Substitute => args_signature_scalars(arg_count, 3, 1),
|
|
Function::T => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Text => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Textafter => args_signature_textafter(arg_count),
|
|
Function::Textbefore => args_signature_textafter(arg_count),
|
|
Function::Textjoin => args_signature_textjoin(arg_count),
|
|
Function::Trim => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Upper => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Value => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Valuetotext => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Average => vec![Signature::Vector; arg_count],
|
|
Function::Averagea => vec![Signature::Vector; arg_count],
|
|
Function::Averageif => args_signature_sumif(arg_count),
|
|
Function::Averageifs => vec![Signature::Vector; arg_count],
|
|
Function::Count => vec![Signature::Vector; arg_count],
|
|
Function::Counta => vec![Signature::Vector; arg_count],
|
|
Function::Countblank => vec![Signature::Vector; arg_count],
|
|
Function::Countif => args_signature_sumif(arg_count),
|
|
Function::Countifs => vec![Signature::Vector; arg_count],
|
|
Function::Maxifs => vec![Signature::Vector; arg_count],
|
|
Function::Minifs => vec![Signature::Vector; arg_count],
|
|
Function::Date => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Datedif => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Datevalue => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Day => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Edate => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Eomonth => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Month => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Time => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Timevalue => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Hour => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Minute => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Second => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Now => args_signature_no_args(arg_count),
|
|
Function::Today => args_signature_no_args(arg_count),
|
|
Function::Year => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Days => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Days360 => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Weekday => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Weeknum => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Workday => args_signature_scalars(arg_count, 2, 1),
|
|
Function::WorkdayIntl => args_signature_scalars(arg_count, 2, 2),
|
|
Function::Yearfrac => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Isoweeknum => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Cumipmt => args_signature_scalars(arg_count, 6, 0),
|
|
Function::Cumprinc => args_signature_scalars(arg_count, 6, 0),
|
|
Function::Db => args_signature_scalars(arg_count, 4, 1),
|
|
Function::Ddb => args_signature_scalars(arg_count, 4, 1),
|
|
Function::Dollarde => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Dollarfr => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Effect => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Fv => args_signature_scalars(arg_count, 3, 2),
|
|
Function::Ipmt => args_signature_scalars(arg_count, 4, 2),
|
|
Function::Irr => args_signature_irr(arg_count),
|
|
Function::Ispmt => args_signature_scalars(arg_count, 4, 0),
|
|
Function::Mirr => args_signature_mirr(arg_count),
|
|
Function::Nominal => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Nper => args_signature_scalars(arg_count, 3, 2),
|
|
Function::Npv => args_signature_npv(arg_count),
|
|
Function::Duration => args_signature_scalars(arg_count, 5, 1),
|
|
Function::Mduration => args_signature_scalars(arg_count, 5, 1),
|
|
Function::Pduration => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Pmt => args_signature_scalars(arg_count, 3, 2),
|
|
Function::Ppmt => args_signature_scalars(arg_count, 4, 2),
|
|
Function::Price => args_signature_scalars(arg_count, 6, 1),
|
|
Function::Pv => args_signature_scalars(arg_count, 3, 2),
|
|
Function::Rate => args_signature_scalars(arg_count, 3, 3),
|
|
Function::Rri => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Sln => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Syd => args_signature_scalars(arg_count, 4, 0),
|
|
Function::Tbilleq => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Tbillprice => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Tbillyield => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Yield => args_signature_scalars(arg_count, 6, 1),
|
|
Function::Xirr => args_signature_xirr(arg_count),
|
|
Function::Xnpv => args_signature_xnpv(arg_count),
|
|
Function::Besseli => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Besselj => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Besselk => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Bessely => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Erf => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Erfc => args_signature_scalars(arg_count, 1, 0),
|
|
Function::ErfcPrecise => args_signature_scalars(arg_count, 1, 0),
|
|
Function::ErfPrecise => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Bin2dec => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Bin2hex => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Bin2oct => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Dec2Bin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Dec2hex => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Dec2oct => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Hex2bin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Hex2dec => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Hex2oct => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Oct2bin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Oct2dec => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Oct2hex => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Bitand => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Bitlshift => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Bitor => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Bitrshift => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Bitxor => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Complex => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Imabs => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imaginary => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imargument => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imconjugate => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imcos => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imcosh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imcot => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imcsc => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imcsch => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imdiv => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Imexp => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imln => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imlog10 => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imlog2 => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Impower => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Improduct => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Imreal => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsec => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsech => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsin => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsinh => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsqrt => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Imsub => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Imsum => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Imtan => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Convert => args_signature_scalars(arg_count, 3, 0),
|
|
Function::Delta => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Gestep => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Subtotal => args_signature_npv(arg_count),
|
|
Function::Rand => args_signature_no_args(arg_count),
|
|
Function::Randbetween => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Formulatext => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Unicode => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Geomean => vec![Signature::Vector; arg_count],
|
|
Function::Networkdays => args_signature_networkdays(arg_count),
|
|
Function::NetworkdaysIntl => args_signature_networkdays_intl(arg_count),
|
|
Function::Acot => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Acoth => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Cot => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Coth => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Csc => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Csch => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sec => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sech => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Exp => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Fact => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Factdouble => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sign => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Radians => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Degrees => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Int => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Even => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Odd => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Ceiling => args_signature_scalars(arg_count, 2, 0),
|
|
Function::CeilingMath => args_signature_scalars(arg_count, 1, 2),
|
|
Function::CeilingPrecise => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Floor => args_signature_scalars(arg_count, 2, 0),
|
|
Function::FloorMath => args_signature_scalars(arg_count, 1, 2),
|
|
Function::FloorPrecise => args_signature_scalars(arg_count, 1, 1),
|
|
Function::IsoCeiling => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Mod => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Quotient => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Mround => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Trunc => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Gcd => vec![Signature::Vector; arg_count],
|
|
Function::Lcm => vec![Signature::Vector; arg_count],
|
|
Function::Base => args_signature_scalars(arg_count, 2, 1),
|
|
Function::Decimal => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Roman => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Arabic => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Combin => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Combina => args_signature_scalars(arg_count, 2, 0),
|
|
Function::Sumsq => vec![Signature::Vector; arg_count],
|
|
|
|
Function::N => args_signature_scalars(arg_count, 1, 0),
|
|
Function::Sheets => args_signature_scalars(arg_count, 0, 1),
|
|
Function::Cell => args_signature_scalars(arg_count, 1, 1),
|
|
Function::Info => args_signature_scalars(arg_count, 1, 1),
|
|
}
|
|
}
|
|
|
|
// Returns the type of the result (Scalar, Array or Range) depending on the arguments
|
|
fn static_analysis_on_function(kind: &Function, args: &[Node]) -> StaticResult {
|
|
match kind {
|
|
Function::And => StaticResult::Scalar,
|
|
Function::False => StaticResult::Scalar,
|
|
Function::If => scalar_arguments(args),
|
|
Function::Iferror => scalar_arguments(args),
|
|
Function::Ifna => scalar_arguments(args),
|
|
Function::Ifs => not_implemented(args),
|
|
Function::Not => StaticResult::Scalar,
|
|
Function::Or => StaticResult::Scalar,
|
|
Function::Switch => not_implemented(args),
|
|
Function::True => StaticResult::Scalar,
|
|
Function::Xor => StaticResult::Scalar,
|
|
Function::Abs => scalar_arguments(args),
|
|
Function::Acos => scalar_arguments(args),
|
|
Function::Acosh => scalar_arguments(args),
|
|
Function::Asin => scalar_arguments(args),
|
|
Function::Asinh => scalar_arguments(args),
|
|
Function::Atan => scalar_arguments(args),
|
|
Function::Atan2 => scalar_arguments(args),
|
|
Function::Atanh => scalar_arguments(args),
|
|
Function::Choose => scalar_arguments(args), // static_analysis_choose(args, cell),
|
|
Function::Column => not_implemented(args),
|
|
Function::Columns => not_implemented(args),
|
|
Function::Cos => scalar_arguments(args),
|
|
Function::Cosh => scalar_arguments(args),
|
|
Function::Max => StaticResult::Scalar,
|
|
Function::Min => StaticResult::Scalar,
|
|
Function::Pi => StaticResult::Scalar,
|
|
Function::Power => scalar_arguments(args),
|
|
Function::Product => not_implemented(args),
|
|
Function::Round => scalar_arguments(args),
|
|
Function::Rounddown => scalar_arguments(args),
|
|
Function::Roundup => scalar_arguments(args),
|
|
Function::Ln => scalar_arguments(args),
|
|
Function::Log => scalar_arguments(args),
|
|
Function::Log10 => scalar_arguments(args),
|
|
Function::Sin => scalar_arguments(args),
|
|
Function::Sinh => scalar_arguments(args),
|
|
Function::Sqrt => scalar_arguments(args),
|
|
Function::Sqrtpi => StaticResult::Scalar,
|
|
Function::Sum => StaticResult::Scalar,
|
|
Function::Sumif => not_implemented(args),
|
|
Function::Sumifs => not_implemented(args),
|
|
Function::Tan => scalar_arguments(args),
|
|
Function::Tanh => scalar_arguments(args),
|
|
Function::ErrorType => not_implemented(args),
|
|
Function::Isblank => not_implemented(args),
|
|
Function::Iserr => not_implemented(args),
|
|
Function::Iserror => not_implemented(args),
|
|
Function::Iseven => not_implemented(args),
|
|
Function::Isformula => not_implemented(args),
|
|
Function::Islogical => not_implemented(args),
|
|
Function::Isna => not_implemented(args),
|
|
Function::Isnontext => not_implemented(args),
|
|
Function::Isnumber => not_implemented(args),
|
|
Function::Isodd => not_implemented(args),
|
|
Function::Isref => not_implemented(args),
|
|
Function::Istext => not_implemented(args),
|
|
Function::Na => StaticResult::Scalar,
|
|
Function::Sheet => StaticResult::Scalar,
|
|
Function::Type => not_implemented(args),
|
|
Function::Hlookup => not_implemented(args),
|
|
Function::Index => static_analysis_index(args),
|
|
Function::Indirect => static_analysis_indirect(args),
|
|
Function::Lookup => not_implemented(args),
|
|
Function::Match => not_implemented(args),
|
|
Function::Offset => static_analysis_offset(args),
|
|
// FIXME: Row could return an array
|
|
Function::Row => StaticResult::Scalar,
|
|
Function::Rows => not_implemented(args),
|
|
Function::Vlookup => not_implemented(args),
|
|
Function::Xlookup => not_implemented(args),
|
|
Function::Concat => not_implemented(args),
|
|
Function::Concatenate => not_implemented(args),
|
|
Function::Exact => not_implemented(args),
|
|
Function::Find => not_implemented(args),
|
|
Function::Left => not_implemented(args),
|
|
Function::Len => not_implemented(args),
|
|
Function::Lower => not_implemented(args),
|
|
Function::Mid => not_implemented(args),
|
|
Function::Rept => not_implemented(args),
|
|
Function::Right => not_implemented(args),
|
|
Function::Search => not_implemented(args),
|
|
Function::Substitute => not_implemented(args),
|
|
Function::T => not_implemented(args),
|
|
Function::Text => not_implemented(args),
|
|
Function::Textafter => not_implemented(args),
|
|
Function::Textbefore => not_implemented(args),
|
|
Function::Textjoin => not_implemented(args),
|
|
Function::Trim => not_implemented(args),
|
|
Function::Unicode => not_implemented(args),
|
|
Function::Upper => not_implemented(args),
|
|
Function::Value => not_implemented(args),
|
|
Function::Valuetotext => not_implemented(args),
|
|
Function::Average => not_implemented(args),
|
|
Function::Averagea => not_implemented(args),
|
|
Function::Averageif => not_implemented(args),
|
|
Function::Averageifs => not_implemented(args),
|
|
Function::Count => not_implemented(args),
|
|
Function::Counta => not_implemented(args),
|
|
Function::Countblank => not_implemented(args),
|
|
Function::Countif => not_implemented(args),
|
|
Function::Countifs => not_implemented(args),
|
|
Function::Maxifs => not_implemented(args),
|
|
Function::Minifs => not_implemented(args),
|
|
Function::Date => not_implemented(args),
|
|
Function::Datedif => not_implemented(args),
|
|
Function::Datevalue => not_implemented(args),
|
|
Function::Day => not_implemented(args),
|
|
Function::Edate => not_implemented(args),
|
|
Function::Month => not_implemented(args),
|
|
Function::Time => not_implemented(args),
|
|
Function::Timevalue => not_implemented(args),
|
|
Function::Hour => not_implemented(args),
|
|
Function::Minute => not_implemented(args),
|
|
Function::Second => not_implemented(args),
|
|
Function::Now => not_implemented(args),
|
|
Function::Today => not_implemented(args),
|
|
Function::Year => not_implemented(args),
|
|
Function::Days => not_implemented(args),
|
|
Function::Days360 => not_implemented(args),
|
|
Function::Weekday => not_implemented(args),
|
|
Function::Weeknum => not_implemented(args),
|
|
Function::Workday => not_implemented(args),
|
|
Function::WorkdayIntl => not_implemented(args),
|
|
Function::Yearfrac => not_implemented(args),
|
|
Function::Isoweeknum => not_implemented(args),
|
|
Function::Cumipmt => not_implemented(args),
|
|
Function::Cumprinc => not_implemented(args),
|
|
Function::Db => not_implemented(args),
|
|
Function::Ddb => not_implemented(args),
|
|
Function::Dollarde => not_implemented(args),
|
|
Function::Dollarfr => not_implemented(args),
|
|
Function::Effect => not_implemented(args),
|
|
Function::Fv => not_implemented(args),
|
|
Function::Ipmt => not_implemented(args),
|
|
Function::Irr => not_implemented(args),
|
|
Function::Ispmt => not_implemented(args),
|
|
Function::Mirr => not_implemented(args),
|
|
Function::Nominal => not_implemented(args),
|
|
Function::Nper => not_implemented(args),
|
|
Function::Npv => not_implemented(args),
|
|
Function::Duration => not_implemented(args),
|
|
Function::Mduration => not_implemented(args),
|
|
Function::Pduration => not_implemented(args),
|
|
Function::Pmt => not_implemented(args),
|
|
Function::Ppmt => not_implemented(args),
|
|
Function::Price => not_implemented(args),
|
|
Function::Pv => not_implemented(args),
|
|
Function::Rate => not_implemented(args),
|
|
Function::Rri => not_implemented(args),
|
|
Function::Sln => not_implemented(args),
|
|
Function::Syd => not_implemented(args),
|
|
Function::Tbilleq => not_implemented(args),
|
|
Function::Tbillprice => not_implemented(args),
|
|
Function::Tbillyield => not_implemented(args),
|
|
Function::Yield => not_implemented(args),
|
|
Function::Xirr => not_implemented(args),
|
|
Function::Xnpv => not_implemented(args),
|
|
Function::Besseli => scalar_arguments(args),
|
|
Function::Besselj => scalar_arguments(args),
|
|
Function::Besselk => scalar_arguments(args),
|
|
Function::Bessely => scalar_arguments(args),
|
|
Function::Erf => scalar_arguments(args),
|
|
Function::Erfc => scalar_arguments(args),
|
|
Function::ErfcPrecise => scalar_arguments(args),
|
|
Function::ErfPrecise => scalar_arguments(args),
|
|
Function::Bin2dec => scalar_arguments(args),
|
|
Function::Bin2hex => scalar_arguments(args),
|
|
Function::Bin2oct => scalar_arguments(args),
|
|
Function::Dec2Bin => scalar_arguments(args),
|
|
Function::Dec2hex => scalar_arguments(args),
|
|
Function::Dec2oct => scalar_arguments(args),
|
|
Function::Hex2bin => scalar_arguments(args),
|
|
Function::Hex2dec => scalar_arguments(args),
|
|
Function::Hex2oct => scalar_arguments(args),
|
|
Function::Oct2bin => scalar_arguments(args),
|
|
Function::Oct2dec => scalar_arguments(args),
|
|
Function::Oct2hex => scalar_arguments(args),
|
|
Function::Bitand => scalar_arguments(args),
|
|
Function::Bitlshift => scalar_arguments(args),
|
|
Function::Bitor => scalar_arguments(args),
|
|
Function::Bitrshift => scalar_arguments(args),
|
|
Function::Bitxor => scalar_arguments(args),
|
|
Function::Complex => scalar_arguments(args),
|
|
Function::Imabs => scalar_arguments(args),
|
|
Function::Imaginary => scalar_arguments(args),
|
|
Function::Imargument => scalar_arguments(args),
|
|
Function::Imconjugate => scalar_arguments(args),
|
|
Function::Imcos => scalar_arguments(args),
|
|
Function::Imcosh => scalar_arguments(args),
|
|
Function::Imcot => scalar_arguments(args),
|
|
Function::Imcsc => scalar_arguments(args),
|
|
Function::Imcsch => scalar_arguments(args),
|
|
Function::Imdiv => scalar_arguments(args),
|
|
Function::Imexp => scalar_arguments(args),
|
|
Function::Imln => scalar_arguments(args),
|
|
Function::Imlog10 => scalar_arguments(args),
|
|
Function::Imlog2 => scalar_arguments(args),
|
|
Function::Impower => scalar_arguments(args),
|
|
Function::Improduct => scalar_arguments(args),
|
|
Function::Imreal => scalar_arguments(args),
|
|
Function::Imsec => scalar_arguments(args),
|
|
Function::Imsech => scalar_arguments(args),
|
|
Function::Imsin => scalar_arguments(args),
|
|
Function::Imsinh => scalar_arguments(args),
|
|
Function::Imsqrt => scalar_arguments(args),
|
|
Function::Imsub => scalar_arguments(args),
|
|
Function::Imsum => scalar_arguments(args),
|
|
Function::Imtan => scalar_arguments(args),
|
|
Function::Convert => not_implemented(args),
|
|
Function::Delta => not_implemented(args),
|
|
Function::Gestep => not_implemented(args),
|
|
Function::Subtotal => not_implemented(args),
|
|
Function::Rand => not_implemented(args),
|
|
Function::Randbetween => scalar_arguments(args),
|
|
Function::Eomonth => scalar_arguments(args),
|
|
Function::Formulatext => not_implemented(args),
|
|
Function::Geomean => not_implemented(args),
|
|
Function::Networkdays => not_implemented(args),
|
|
Function::NetworkdaysIntl => not_implemented(args),
|
|
Function::Acot => scalar_arguments(args),
|
|
Function::Acoth => scalar_arguments(args),
|
|
Function::Cot => scalar_arguments(args),
|
|
Function::Coth => scalar_arguments(args),
|
|
Function::Csc => scalar_arguments(args),
|
|
Function::Csch => scalar_arguments(args),
|
|
Function::Sec => scalar_arguments(args),
|
|
Function::Sech => scalar_arguments(args),
|
|
Function::Exp => scalar_arguments(args),
|
|
Function::Fact => scalar_arguments(args),
|
|
Function::Factdouble => scalar_arguments(args),
|
|
Function::Sign => scalar_arguments(args),
|
|
Function::Radians => scalar_arguments(args),
|
|
Function::Degrees => scalar_arguments(args),
|
|
Function::Int => scalar_arguments(args),
|
|
Function::Even => scalar_arguments(args),
|
|
Function::Odd => scalar_arguments(args),
|
|
Function::Ceiling => scalar_arguments(args),
|
|
Function::CeilingMath => scalar_arguments(args),
|
|
Function::CeilingPrecise => scalar_arguments(args),
|
|
Function::Floor => scalar_arguments(args),
|
|
Function::FloorMath => scalar_arguments(args),
|
|
Function::FloorPrecise => scalar_arguments(args),
|
|
Function::IsoCeiling => scalar_arguments(args),
|
|
Function::Mod => scalar_arguments(args),
|
|
Function::Quotient => scalar_arguments(args),
|
|
Function::Mround => scalar_arguments(args),
|
|
Function::Trunc => scalar_arguments(args),
|
|
Function::Gcd => not_implemented(args),
|
|
Function::Lcm => not_implemented(args),
|
|
Function::Base => scalar_arguments(args),
|
|
Function::Decimal => scalar_arguments(args),
|
|
Function::Roman => scalar_arguments(args),
|
|
Function::Arabic => scalar_arguments(args),
|
|
Function::Combin => scalar_arguments(args),
|
|
Function::Combina => scalar_arguments(args),
|
|
Function::Sumsq => StaticResult::Scalar,
|
|
Function::N => scalar_arguments(args),
|
|
Function::Sheets => scalar_arguments(args),
|
|
Function::Cell => scalar_arguments(args),
|
|
Function::Info => scalar_arguments(args),
|
|
}
|
|
}
|