Files
IronCalc/base/src/functions/mod.rs
2024-12-12 05:58:20 +01:00

1229 lines
46 KiB
Rust

use core::fmt;
use std::array::IntoIter;
use crate::{
calc_result::CalcResult,
expressions::{parser::Node, token::Error, types::CellReferenceIndex},
model::Model,
};
pub(crate) mod binary_search;
mod date_and_time;
mod engineering;
mod financial;
mod financial_util;
mod information;
mod logical;
mod lookup_and_reference;
mod mathematical;
mod statistical;
mod subtotal;
mod text;
mod text_util;
pub(crate) mod util;
mod xlookup;
/// List of all implemented functions
#[derive(PartialEq, Clone, Debug)]
pub enum Function {
// Logical
And,
False,
If,
Iferror,
Ifna,
Ifs,
Not,
Or,
Switch,
True,
Xor,
// Mathematical and trigonometry
Abs,
Acos,
Acosh,
Asin,
Asinh,
Atan,
Atan2,
Atanh,
Choose,
Column,
Columns,
Cos,
Cosh,
Max,
Min,
Pi,
Power,
Product,
Rand,
Randbetween,
Round,
Rounddown,
Roundup,
Sin,
Sinh,
Sqrt,
Sqrtpi,
Sum,
Sumif,
Sumifs,
Tan,
Tanh,
// Information
ErrorType,
Formulatext,
Isblank,
Iserr,
Iserror,
Iseven,
Isformula,
Islogical,
Isna,
Isnontext,
Isnumber,
Isodd,
Isref,
Istext,
Na,
Sheet,
Type,
// Lookup and reference
Hlookup,
Index,
Indirect,
Lookup,
Match,
Offset,
Row,
Rows,
Vlookup,
Xlookup,
// Text
Concat,
Concatenate,
Exact,
Find,
Left,
Len,
Lower,
Mid,
Rept,
Right,
Search,
Substitute,
T,
Text,
Textafter,
Textbefore,
Textjoin,
Trim,
Unicode,
Upper,
Value,
Valuetotext,
// Statistical
Average,
Averagea,
Averageif,
Averageifs,
Count,
Counta,
Countblank,
Countif,
Countifs,
Maxifs,
Minifs,
Geomean,
// Date and time
Date,
Day,
Edate,
Eomonth,
Month,
Now,
Today,
Year,
// Financial
Cumipmt,
Cumprinc,
Db,
Ddb,
Dollarde,
Dollarfr,
Effect,
Fv,
Ipmt,
Irr,
Ispmt,
Mirr,
Nominal,
Nper,
Npv,
Pduration,
Pmt,
Ppmt,
Pv,
Rate,
Rri,
Sln,
Syd,
Tbilleq,
Tbillprice,
Tbillyield,
Xirr,
Xnpv,
// Engineering: Bessel and transcendental functions
Besseli,
Besselj,
Besselk,
Bessely,
Erf,
Erfc,
ErfcPrecise,
ErfPrecise,
// Engineering: Number systems
Bin2dec,
Bin2hex,
Bin2oct,
Dec2Bin,
Dec2hex,
Dec2oct,
Hex2bin,
Hex2dec,
Hex2oct,
Oct2bin,
Oct2dec,
Oct2hex,
// Engineering: Bit functions
Bitand,
Bitlshift,
Bitor,
Bitrshift,
Bitxor,
// Engineering: Complex functions
Complex,
Imabs,
Imaginary,
Imargument,
Imconjugate,
Imcos,
Imcosh,
Imcot,
Imcsc,
Imcsch,
Imdiv,
Imexp,
Imln,
Imlog10,
Imlog2,
Impower,
Improduct,
Imreal,
Imsec,
Imsech,
Imsin,
Imsinh,
Imsqrt,
Imsub,
Imsum,
Imtan,
// Engineering: Misc function
Convert,
Delta,
Gestep,
Subtotal,
}
impl Function {
pub fn into_iter() -> IntoIter<Function, 195> {
[
Function::And,
Function::False,
Function::If,
Function::Iferror,
Function::Ifna,
Function::Ifs,
Function::Not,
Function::Or,
Function::Switch,
Function::True,
Function::Xor,
Function::Sin,
Function::Cos,
Function::Tan,
Function::Asin,
Function::Acos,
Function::Atan,
Function::Sinh,
Function::Cosh,
Function::Tanh,
Function::Asinh,
Function::Acosh,
Function::Atanh,
Function::Abs,
Function::Pi,
Function::Sqrt,
Function::Sqrtpi,
Function::Atan2,
Function::Power,
Function::Max,
Function::Min,
Function::Product,
Function::Rand,
Function::Randbetween,
Function::Round,
Function::Rounddown,
Function::Roundup,
Function::Sum,
Function::Sumif,
Function::Sumifs,
Function::Choose,
Function::Column,
Function::Columns,
Function::Index,
Function::Indirect,
Function::Hlookup,
Function::Lookup,
Function::Match,
Function::Offset,
Function::Row,
Function::Rows,
Function::Vlookup,
Function::Xlookup,
Function::Concatenate,
Function::Exact,
Function::Value,
Function::T,
Function::Valuetotext,
Function::Concat,
Function::Find,
Function::Left,
Function::Len,
Function::Lower,
Function::Mid,
Function::Right,
Function::Search,
Function::Text,
Function::Trim,
Function::Unicode,
Function::Upper,
Function::Isnumber,
Function::Isnontext,
Function::Istext,
Function::Islogical,
Function::Isblank,
Function::Iserr,
Function::Iserror,
Function::Isna,
Function::Na,
Function::Isref,
Function::Isodd,
Function::Iseven,
Function::ErrorType,
Function::Formulatext,
Function::Isformula,
Function::Type,
Function::Sheet,
Function::Average,
Function::Averagea,
Function::Averageif,
Function::Averageifs,
Function::Count,
Function::Counta,
Function::Countblank,
Function::Countif,
Function::Countifs,
Function::Maxifs,
Function::Minifs,
Function::Geomean,
Function::Year,
Function::Day,
Function::Month,
Function::Eomonth,
Function::Date,
Function::Edate,
Function::Today,
Function::Now,
Function::Pmt,
Function::Pv,
Function::Rate,
Function::Nper,
Function::Fv,
Function::Ppmt,
Function::Ipmt,
Function::Npv,
Function::Mirr,
Function::Irr,
Function::Xirr,
Function::Xnpv,
Function::Rept,
Function::Textafter,
Function::Textbefore,
Function::Textjoin,
Function::Substitute,
Function::Ispmt,
Function::Rri,
Function::Sln,
Function::Syd,
Function::Nominal,
Function::Effect,
Function::Pduration,
Function::Tbillyield,
Function::Tbillprice,
Function::Tbilleq,
Function::Dollarde,
Function::Dollarfr,
Function::Ddb,
Function::Db,
Function::Cumprinc,
Function::Cumipmt,
Function::Besseli,
Function::Besselj,
Function::Besselk,
Function::Bessely,
Function::Erf,
Function::ErfPrecise,
Function::Erfc,
Function::ErfcPrecise,
Function::Bin2dec,
Function::Bin2hex,
Function::Bin2oct,
Function::Dec2Bin,
Function::Dec2hex,
Function::Dec2oct,
Function::Hex2bin,
Function::Hex2dec,
Function::Hex2oct,
Function::Oct2bin,
Function::Oct2dec,
Function::Oct2hex,
Function::Bitand,
Function::Bitlshift,
Function::Bitor,
Function::Bitrshift,
Function::Bitxor,
Function::Complex,
Function::Imabs,
Function::Imaginary,
Function::Imargument,
Function::Imconjugate,
Function::Imcos,
Function::Imcosh,
Function::Imcot,
Function::Imcsc,
Function::Imcsch,
Function::Imdiv,
Function::Imexp,
Function::Imln,
Function::Imlog10,
Function::Imlog2,
Function::Impower,
Function::Improduct,
Function::Imreal,
Function::Imsec,
Function::Imsech,
Function::Imsin,
Function::Imsinh,
Function::Imsqrt,
Function::Imsub,
Function::Imsum,
Function::Imtan,
Function::Convert,
Function::Delta,
Function::Gestep,
Function::Subtotal,
]
.into_iter()
}
}
impl Function {
/// Some functions in Excel like CONCAT are stringified as `_xlfn.CONCAT`.
pub fn to_xlsx_string(&self) -> String {
match self {
Function::Concat => "_xlfn.CONCAT".to_string(),
Function::Ifna => "_xlfn.IFNA".to_string(),
Function::Ifs => "_xlfn.IFS".to_string(),
Function::Maxifs => "_xlfn.MAXIFS".to_string(),
Function::Minifs => "_xlfn.MINIFS".to_string(),
Function::Switch => "_xlfn.SWITCH".to_string(),
Function::Xlookup => "_xlfn.XLOOKUP".to_string(),
Function::Xor => "_xlfn.XOR".to_string(),
Function::Textbefore => "_xlfn.TEXTBEFORE".to_string(),
Function::Textafter => "_xlfn.TEXTAFTER".to_string(),
Function::Textjoin => "_xlfn.TEXTJOIN".to_string(),
Function::Unicode => "_xlfn.UNICODE".to_string(),
Function::Rri => "_xlfn.RRI".to_string(),
Function::Pduration => "_xlfn.PDURATION".to_string(),
Function::Bitand => "_xlfn.BITAND".to_string(),
Function::Bitor => "_xlfn.BITOR".to_string(),
Function::Bitxor => "_xlfn.BITXOR".to_string(),
Function::Bitlshift => "_xlfn.BITLSHIFT".to_string(),
Function::Bitrshift => "_xlfn.BITRSHIFT".to_string(),
Function::Imtan => "_xlfn.IMTAN".to_string(),
Function::Imsinh => "_xlfn.IMSINH".to_string(),
Function::Imcosh => "_xlfn.IMCOSH".to_string(),
Function::Imcot => "_xlfn.IMCOT".to_string(),
Function::Imcsc => "_xlfn.IMCSC".to_string(),
Function::Imcsch => "_xlfn.IMCSCH".to_string(),
Function::Imsec => "_xlfn.IMSEC".to_string(),
Function::ErfcPrecise => "_xlfn.ERFC.PRECISE".to_string(),
Function::ErfPrecise => "_xlfn.ERF.PRECISE".to_string(),
Function::Valuetotext => "_xlfn.VALUETOTEXT".to_string(),
Function::Isformula => "_xlfn.ISFORMULA".to_string(),
Function::Sheet => "_xlfn.SHEET".to_string(),
Function::Formulatext => "_xlfn.FORMULATEXT".to_string(),
_ => self.to_string(),
}
}
pub(crate) fn returns_reference(&self) -> bool {
matches!(self, Function::Indirect | Function::Offset)
}
/// Gets the function from the name.
/// Note that in Excel some (modern) functions are prefixed by `_xlfn.`
pub fn get_function(name: &str) -> Option<Function> {
match name.to_ascii_uppercase().as_str() {
"AND" => Some(Function::And),
"FALSE" => Some(Function::False),
"IF" => Some(Function::If),
"IFERROR" => Some(Function::Iferror),
"IFNA" | "_XLFN.IFNA" => Some(Function::Ifna),
"IFS" | "_XLFN.IFS" => Some(Function::Ifs),
"NOT" => Some(Function::Not),
"OR" => Some(Function::Or),
"SWITCH" | "_XLFN.SWITCH" => Some(Function::Switch),
"TRUE" => Some(Function::True),
"XOR" | "_XLFN.XOR" => Some(Function::Xor),
"SIN" => Some(Function::Sin),
"COS" => Some(Function::Cos),
"TAN" => Some(Function::Tan),
"ASIN" => Some(Function::Asin),
"ACOS" => Some(Function::Acos),
"ATAN" => Some(Function::Atan),
"SINH" => Some(Function::Sinh),
"COSH" => Some(Function::Cosh),
"TANH" => Some(Function::Tanh),
"ASINH" => Some(Function::Asinh),
"ACOSH" => Some(Function::Acosh),
"ATANH" => Some(Function::Atanh),
"PI" => Some(Function::Pi),
"ABS" => Some(Function::Abs),
"SQRT" => Some(Function::Sqrt),
"SQRTPI" => Some(Function::Sqrtpi),
"POWER" => Some(Function::Power),
"ATAN2" => Some(Function::Atan2),
"MAX" => Some(Function::Max),
"MIN" => Some(Function::Min),
"PRODUCT" => Some(Function::Product),
"RAND" => Some(Function::Rand),
"RANDBETWEEN" => Some(Function::Randbetween),
"ROUND" => Some(Function::Round),
"ROUNDDOWN" => Some(Function::Rounddown),
"ROUNDUP" => Some(Function::Roundup),
"SUM" => Some(Function::Sum),
"SUMIF" => Some(Function::Sumif),
"SUMIFS" => Some(Function::Sumifs),
// Lookup and Reference
"CHOOSE" => Some(Function::Choose),
"COLUMN" => Some(Function::Column),
"COLUMNS" => Some(Function::Columns),
"INDEX" => Some(Function::Index),
"INDIRECT" => Some(Function::Indirect),
"HLOOKUP" => Some(Function::Hlookup),
"LOOKUP" => Some(Function::Lookup),
"MATCH" => Some(Function::Match),
"OFFSET" => Some(Function::Offset),
"ROW" => Some(Function::Row),
"ROWS" => Some(Function::Rows),
"VLOOKUP" => Some(Function::Vlookup),
"XLOOKUP" | "_XLFN.XLOOKUP" => Some(Function::Xlookup),
"CONCATENATE" => Some(Function::Concatenate),
"EXACT" => Some(Function::Exact),
"VALUE" => Some(Function::Value),
"T" => Some(Function::T),
"VALUETOTEXT" | "_XLFN.VALUETOTEXT" => Some(Function::Valuetotext),
"CONCAT" | "_XLFN.CONCAT" => Some(Function::Concat),
"FIND" => Some(Function::Find),
"LEFT" => Some(Function::Left),
"LEN" => Some(Function::Len),
"LOWER" => Some(Function::Lower),
"MID" => Some(Function::Mid),
"RIGHT" => Some(Function::Right),
"SEARCH" => Some(Function::Search),
"TEXT" => Some(Function::Text),
"TRIM" => Some(Function::Trim),
"UNICODE" | "_XLFN.UNICODE" => Some(Function::Unicode),
"UPPER" => Some(Function::Upper),
"REPT" => Some(Function::Rept),
"TEXTAFTER" | "_XLFN.TEXTAFTER" => Some(Function::Textafter),
"TEXTBEFORE" | "_XLFN.TEXTBEFORE" => Some(Function::Textbefore),
"TEXTJOIN" | "_XLFN.TEXTJOIN" => Some(Function::Textjoin),
"SUBSTITUTE" => Some(Function::Substitute),
"ISNUMBER" => Some(Function::Isnumber),
"ISNONTEXT" => Some(Function::Isnontext),
"ISTEXT" => Some(Function::Istext),
"ISLOGICAL" => Some(Function::Islogical),
"ISBLANK" => Some(Function::Isblank),
"ISERR" => Some(Function::Iserr),
"ISERROR" => Some(Function::Iserror),
"ISNA" => Some(Function::Isna),
"NA" => Some(Function::Na),
"ISREF" => Some(Function::Isref),
"ISODD" => Some(Function::Isodd),
"ISEVEN" => Some(Function::Iseven),
"ERROR.TYPE" => Some(Function::ErrorType),
"FORMULATEXT" | "_XLFN.FORMULATEXT" => Some(Function::Formulatext),
"ISFORMULA" | "_XLFN.ISFORMULA" => Some(Function::Isformula),
"TYPE" => Some(Function::Type),
"SHEET" | "_XLFN.SHEET" => Some(Function::Sheet),
"AVERAGE" => Some(Function::Average),
"AVERAGEA" => Some(Function::Averagea),
"AVERAGEIF" => Some(Function::Averageif),
"AVERAGEIFS" => Some(Function::Averageifs),
"COUNT" => Some(Function::Count),
"COUNTA" => Some(Function::Counta),
"COUNTBLANK" => Some(Function::Countblank),
"COUNTIF" => Some(Function::Countif),
"COUNTIFS" => Some(Function::Countifs),
"MAXIFS" | "_XLFN.MAXIFS" => Some(Function::Maxifs),
"MINIFS" | "_XLFN.MINIFS" => Some(Function::Minifs),
"GEOMEAN" => Some(Function::Geomean),
// Date and Time
"YEAR" => Some(Function::Year),
"DAY" => Some(Function::Day),
"EOMONTH" => Some(Function::Eomonth),
"MONTH" => Some(Function::Month),
"DATE" => Some(Function::Date),
"EDATE" => Some(Function::Edate),
"TODAY" => Some(Function::Today),
"NOW" => Some(Function::Now),
// Financial
"PMT" => Some(Function::Pmt),
"PV" => Some(Function::Pv),
"RATE" => Some(Function::Rate),
"NPER" => Some(Function::Nper),
"FV" => Some(Function::Fv),
"PPMT" => Some(Function::Ppmt),
"IPMT" => Some(Function::Ipmt),
"NPV" => Some(Function::Npv),
"XNPV" => Some(Function::Xnpv),
"MIRR" => Some(Function::Mirr),
"IRR" => Some(Function::Irr),
"XIRR" => Some(Function::Xirr),
"ISPMT" => Some(Function::Ispmt),
"RRI" | "_XLFN.RRI" => Some(Function::Rri),
"SLN" => Some(Function::Sln),
"SYD" => Some(Function::Syd),
"NOMINAL" => Some(Function::Nominal),
"EFFECT" => Some(Function::Effect),
"PDURATION" | "_XLFN.PDURATION" => Some(Function::Pduration),
"TBILLYIELD" => Some(Function::Tbillyield),
"TBILLPRICE" => Some(Function::Tbillprice),
"TBILLEQ" => Some(Function::Tbilleq),
"DOLLARDE" => Some(Function::Dollarde),
"DOLLARFR" => Some(Function::Dollarfr),
"DDB" => Some(Function::Ddb),
"DB" => Some(Function::Db),
"CUMPRINC" => Some(Function::Cumprinc),
"CUMIPMT" => Some(Function::Cumipmt),
"BESSELI" => Some(Function::Besseli),
"BESSELJ" => Some(Function::Besselj),
"BESSELK" => Some(Function::Besselk),
"BESSELY" => Some(Function::Bessely),
"ERF" => Some(Function::Erf),
"ERF.PRECISE" | "_XLFN.ERF.PRECISE" => Some(Function::ErfPrecise),
"ERFC" => Some(Function::Erfc),
"ERFC.PRECISE" | "_XLFN.ERFC.PRECISE" => Some(Function::ErfcPrecise),
"BIN2DEC" => Some(Function::Bin2dec),
"BIN2HEX" => Some(Function::Bin2hex),
"BIN2OCT" => Some(Function::Bin2oct),
"DEC2BIN" => Some(Function::Dec2Bin),
"DEC2HEX" => Some(Function::Dec2hex),
"DEC2OCT" => Some(Function::Dec2oct),
"HEX2BIN" => Some(Function::Hex2bin),
"HEX2DEC" => Some(Function::Hex2dec),
"HEX2OCT" => Some(Function::Hex2oct),
"OCT2BIN" => Some(Function::Oct2bin),
"OCT2DEC" => Some(Function::Oct2dec),
"OCT2HEX" => Some(Function::Oct2hex),
"BITAND" | "_XLFN.BITAND" => Some(Function::Bitand),
"BITLSHIFT" | "_XLFN.BITLSHIFT" => Some(Function::Bitlshift),
"BITOR" | "_XLFN.BITOR" => Some(Function::Bitor),
"BITRSHIFT" | "_XLFN.BITRSHIFT" => Some(Function::Bitrshift),
"BITXOR" | "_XLFN.BITXOR" => Some(Function::Bitxor),
"COMPLEX" => Some(Function::Complex),
"IMABS" => Some(Function::Imabs),
"IMAGINARY" => Some(Function::Imaginary),
"IMARGUMENT" => Some(Function::Imargument),
"IMCONJUGATE" => Some(Function::Imconjugate),
"IMCOS" => Some(Function::Imcos),
"IMCOSH" | "_XLFN.IMCOSH" => Some(Function::Imcosh),
"IMCOT" | "_XLFN.IMCOT" => Some(Function::Imcot),
"IMCSC" | "_XLFN.IMCSC" => Some(Function::Imcsc),
"IMCSCH" | "_XLFN.IMCSCH" => Some(Function::Imcsch),
"IMDIV" => Some(Function::Imdiv),
"IMEXP" => Some(Function::Imexp),
"IMLN" => Some(Function::Imln),
"IMLOG10" => Some(Function::Imlog10),
"IMLOG2" => Some(Function::Imlog2),
"IMPOWER" => Some(Function::Impower),
"IMPRODUCT" => Some(Function::Improduct),
"IMREAL" => Some(Function::Imreal),
"IMSEC" | "_XLFN.IMSEC" => Some(Function::Imsec),
"IMSECH" | "_XLFN.IMSECH" => Some(Function::Imsech),
"IMSIN" => Some(Function::Imsin),
"IMSINH" | "_XLFN.IMSINH" => Some(Function::Imsinh),
"IMSQRT" => Some(Function::Imsqrt),
"IMSUB" => Some(Function::Imsub),
"IMSUM" => Some(Function::Imsum),
"IMTAN" | "_XLFN.IMTAN" => Some(Function::Imtan),
"CONVERT" => Some(Function::Convert),
"DELTA" => Some(Function::Delta),
"GESTEP" => Some(Function::Gestep),
"SUBTOTAL" => Some(Function::Subtotal),
_ => None,
}
}
}
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Function::And => write!(f, "AND"),
Function::False => write!(f, "FALSE"),
Function::If => write!(f, "IF"),
Function::Iferror => write!(f, "IFERROR"),
Function::Ifna => write!(f, "IFNA"),
Function::Ifs => write!(f, "IFS"),
Function::Not => write!(f, "NOT"),
Function::Or => write!(f, "OR"),
Function::Switch => write!(f, "SWITCH"),
Function::True => write!(f, "TRUE"),
Function::Xor => write!(f, "XOR"),
Function::Sin => write!(f, "SIN"),
Function::Cos => write!(f, "COS"),
Function::Tan => write!(f, "TAN"),
Function::Asin => write!(f, "ASIN"),
Function::Acos => write!(f, "ACOS"),
Function::Atan => write!(f, "ATAN"),
Function::Sinh => write!(f, "SINH"),
Function::Cosh => write!(f, "COSH"),
Function::Tanh => write!(f, "TANH"),
Function::Asinh => write!(f, "ASINH"),
Function::Acosh => write!(f, "ACOSH"),
Function::Atanh => write!(f, "ATANH"),
Function::Abs => write!(f, "ABS"),
Function::Pi => write!(f, "PI"),
Function::Sqrt => write!(f, "SQRT"),
Function::Sqrtpi => write!(f, "SQRTPI"),
Function::Atan2 => write!(f, "ATAN2"),
Function::Power => write!(f, "POWER"),
Function::Max => write!(f, "MAX"),
Function::Min => write!(f, "MIN"),
Function::Product => write!(f, "PRODUCT"),
Function::Rand => write!(f, "RAND"),
Function::Randbetween => write!(f, "RANDBETWEEN"),
Function::Round => write!(f, "ROUND"),
Function::Rounddown => write!(f, "ROUNDDOWN"),
Function::Roundup => write!(f, "ROUNDUP"),
Function::Sum => write!(f, "SUM"),
Function::Sumif => write!(f, "SUMIF"),
Function::Sumifs => write!(f, "SUMIFS"),
Function::Choose => write!(f, "CHOOSE"),
Function::Column => write!(f, "COLUMN"),
Function::Columns => write!(f, "COLUMNS"),
Function::Index => write!(f, "INDEX"),
Function::Indirect => write!(f, "INDIRECT"),
Function::Hlookup => write!(f, "HLOOKUP"),
Function::Lookup => write!(f, "LOOKUP"),
Function::Match => write!(f, "MATCH"),
Function::Offset => write!(f, "OFFSET"),
Function::Row => write!(f, "ROW"),
Function::Rows => write!(f, "ROWS"),
Function::Vlookup => write!(f, "VLOOKUP"),
Function::Xlookup => write!(f, "XLOOKUP"),
Function::Concatenate => write!(f, "CONCATENATE"),
Function::Exact => write!(f, "EXACT"),
Function::Value => write!(f, "VALUE"),
Function::T => write!(f, "T"),
Function::Valuetotext => write!(f, "VALUETOTEXT"),
Function::Concat => write!(f, "CONCAT"),
Function::Find => write!(f, "FIND"),
Function::Left => write!(f, "LEFT"),
Function::Len => write!(f, "LEN"),
Function::Lower => write!(f, "LOWER"),
Function::Mid => write!(f, "MID"),
Function::Right => write!(f, "RIGHT"),
Function::Search => write!(f, "SEARCH"),
Function::Text => write!(f, "TEXT"),
Function::Trim => write!(f, "TRIM"),
Function::Unicode => write!(f, "UNICODE"),
Function::Upper => write!(f, "UPPER"),
Function::Isnumber => write!(f, "ISNUMBER"),
Function::Isnontext => write!(f, "ISNONTEXT"),
Function::Istext => write!(f, "ISTEXT"),
Function::Islogical => write!(f, "ISLOGICAL"),
Function::Isblank => write!(f, "ISBLANK"),
Function::Iserr => write!(f, "ISERR"),
Function::Iserror => write!(f, "ISERROR"),
Function::Isna => write!(f, "ISNA"),
Function::Na => write!(f, "NA"),
Function::Isref => write!(f, "ISREF"),
Function::Isodd => write!(f, "ISODD"),
Function::Iseven => write!(f, "ISEVEN"),
Function::ErrorType => write!(f, "ERROR.TYPE"),
Function::Formulatext => write!(f, "FORMULATEXT"),
Function::Isformula => write!(f, "ISFORMULA"),
Function::Type => write!(f, "TYPE"),
Function::Sheet => write!(f, "SHEET"),
Function::Average => write!(f, "AVERAGE"),
Function::Averagea => write!(f, "AVERAGEA"),
Function::Averageif => write!(f, "AVERAGEIF"),
Function::Averageifs => write!(f, "AVERAGEIFS"),
Function::Count => write!(f, "COUNT"),
Function::Counta => write!(f, "COUNTA"),
Function::Countblank => write!(f, "COUNTBLANK"),
Function::Countif => write!(f, "COUNTIF"),
Function::Countifs => write!(f, "COUNTIFS"),
Function::Maxifs => write!(f, "MAXIFS"),
Function::Minifs => write!(f, "MINIFS"),
Function::Geomean => write!(f, "GEOMEAN"),
Function::Year => write!(f, "YEAR"),
Function::Day => write!(f, "DAY"),
Function::Month => write!(f, "MONTH"),
Function::Eomonth => write!(f, "EOMONTH"),
Function::Date => write!(f, "DATE"),
Function::Edate => write!(f, "EDATE"),
Function::Today => write!(f, "TODAY"),
Function::Now => write!(f, "NOW"),
Function::Pmt => write!(f, "PMT"),
Function::Pv => write!(f, "PV"),
Function::Rate => write!(f, "RATE"),
Function::Nper => write!(f, "NPER"),
Function::Fv => write!(f, "FV"),
Function::Ppmt => write!(f, "PPMT"),
Function::Ipmt => write!(f, "IPMT"),
Function::Npv => write!(f, "NPV"),
Function::Mirr => write!(f, "MIRR"),
Function::Irr => write!(f, "IRR"),
Function::Xirr => write!(f, "XIRR"),
Function::Xnpv => write!(f, "XNPV"),
Function::Rept => write!(f, "REPT"),
Function::Textafter => write!(f, "TEXTAFTER"),
Function::Textbefore => write!(f, "TEXTBEFORE"),
Function::Textjoin => write!(f, "TEXTJOIN"),
Function::Substitute => write!(f, "SUBSTITUTE"),
Function::Ispmt => write!(f, "ISPMT"),
Function::Rri => write!(f, "RRI"),
Function::Sln => write!(f, "SLN"),
Function::Syd => write!(f, "SYD"),
Function::Nominal => write!(f, "NOMINAL"),
Function::Effect => write!(f, "EFFECT"),
Function::Pduration => write!(f, "PDURATION"),
Function::Tbillyield => write!(f, "TBILLYIELD"),
Function::Tbillprice => write!(f, "TBILLPRICE"),
Function::Tbilleq => write!(f, "TBILLEQ"),
Function::Dollarde => write!(f, "DOLLARDE"),
Function::Dollarfr => write!(f, "DOLLARFR"),
Function::Ddb => write!(f, "DDB"),
Function::Db => write!(f, "DB"),
Function::Cumprinc => write!(f, "CUMPRINC"),
Function::Cumipmt => write!(f, "CUMIPMT"),
Function::Besseli => write!(f, "BESSELI"),
Function::Besselj => write!(f, "BESSELJ"),
Function::Besselk => write!(f, "BESSELK"),
Function::Bessely => write!(f, "BESSELY"),
Function::Erf => write!(f, "ERF"),
Function::ErfPrecise => write!(f, "ERF.PRECISE"),
Function::Erfc => write!(f, "ERFC"),
Function::ErfcPrecise => write!(f, "ERFC.PRECISE"),
Function::Bin2dec => write!(f, "BIN2DEC"),
Function::Bin2hex => write!(f, "BIN2HEX"),
Function::Bin2oct => write!(f, "BIN2OCT"),
Function::Dec2Bin => write!(f, "DEC2BIN"),
Function::Dec2hex => write!(f, "DEC2HEX"),
Function::Dec2oct => write!(f, "DEC2OCT"),
Function::Hex2bin => write!(f, "HEX2BIN"),
Function::Hex2dec => write!(f, "HEX2DEC"),
Function::Hex2oct => write!(f, "HEX2OCT"),
Function::Oct2bin => write!(f, "OCT2BIN"),
Function::Oct2dec => write!(f, "OCT2DEC"),
Function::Oct2hex => write!(f, "OCT2HEX"),
Function::Bitand => write!(f, "BITAND"),
Function::Bitlshift => write!(f, "BITLSHIFT"),
Function::Bitor => write!(f, "BITOR"),
Function::Bitrshift => write!(f, "BITRSHIFT"),
Function::Bitxor => write!(f, "BITXOR"),
Function::Complex => write!(f, "COMPLEX"),
Function::Imabs => write!(f, "IMABS"),
Function::Imaginary => write!(f, "IMAGINARY"),
Function::Imargument => write!(f, "IMARGUMENT"),
Function::Imconjugate => write!(f, "IMCONJUGATE"),
Function::Imcos => write!(f, "IMCOS"),
Function::Imcosh => write!(f, "IMCOSH"),
Function::Imcot => write!(f, "IMCOT"),
Function::Imcsc => write!(f, "IMCSC"),
Function::Imcsch => write!(f, "IMCSCH"),
Function::Imdiv => write!(f, "IMDIV"),
Function::Imexp => write!(f, "IMEXP"),
Function::Imln => write!(f, "IMLN"),
Function::Imlog10 => write!(f, "IMLOG10"),
Function::Imlog2 => write!(f, "IMLOG2"),
Function::Impower => write!(f, "IMPOWER"),
Function::Improduct => write!(f, "IMPRODUCT"),
Function::Imreal => write!(f, "IMREAL"),
Function::Imsec => write!(f, "IMSEC"),
Function::Imsech => write!(f, "IMSECH"),
Function::Imsin => write!(f, "IMSIN"),
Function::Imsinh => write!(f, "IMSINH"),
Function::Imsqrt => write!(f, "IMSQRT"),
Function::Imsub => write!(f, "IMSUB"),
Function::Imsum => write!(f, "IMSUM"),
Function::Imtan => write!(f, "IMTAN"),
Function::Convert => write!(f, "CONVERT"),
Function::Delta => write!(f, "DELTA"),
Function::Gestep => write!(f, "GESTEP"),
Function::Subtotal => write!(f, "SUBTOTAL"),
}
}
}
/// Documentation for one function
pub struct Documentation {
pub name: String,
}
impl Model {
/// Produces documentation for all implemented functions
pub fn documentation() -> Vec<Documentation> {
let mut doc = Vec::new();
for function in Function::into_iter() {
doc.push(Documentation {
name: function.to_string(),
});
}
doc
}
pub(crate) fn evaluate_function(
&mut self,
kind: &Function,
args: &[Node],
cell: CellReferenceIndex,
) -> CalcResult {
match kind {
// Logical
Function::And => self.fn_and(args, cell),
Function::False => CalcResult::Boolean(false),
Function::If => self.fn_if(args, cell),
Function::Iferror => self.fn_iferror(args, cell),
Function::Ifna => self.fn_ifna(args, cell),
Function::Ifs => self.fn_ifs(args, cell),
Function::Not => self.fn_not(args, cell),
Function::Or => self.fn_or(args, cell),
Function::Switch => self.fn_switch(args, cell),
Function::True => CalcResult::Boolean(true),
Function::Xor => self.fn_xor(args, cell),
// Math and trigonometry
Function::Sin => self.fn_sin(args, cell),
Function::Cos => self.fn_cos(args, cell),
Function::Tan => self.fn_tan(args, cell),
Function::Asin => self.fn_asin(args, cell),
Function::Acos => self.fn_acos(args, cell),
Function::Atan => self.fn_atan(args, cell),
Function::Sinh => self.fn_sinh(args, cell),
Function::Cosh => self.fn_cosh(args, cell),
Function::Tanh => self.fn_tanh(args, cell),
Function::Asinh => self.fn_asinh(args, cell),
Function::Acosh => self.fn_acosh(args, cell),
Function::Atanh => self.fn_atanh(args, cell),
Function::Pi => self.fn_pi(args, cell),
Function::Abs => self.fn_abs(args, cell),
Function::Sqrt => self.fn_sqrt(args, cell),
Function::Sqrtpi => self.fn_sqrtpi(args, cell),
Function::Atan2 => self.fn_atan2(args, cell),
Function::Power => self.fn_power(args, cell),
Function::Max => self.fn_max(args, cell),
Function::Min => self.fn_min(args, cell),
Function::Product => self.fn_product(args, cell),
Function::Rand => self.fn_rand(args, cell),
Function::Randbetween => self.fn_randbetween(args, cell),
Function::Round => self.fn_round(args, cell),
Function::Rounddown => self.fn_rounddown(args, cell),
Function::Roundup => self.fn_roundup(args, cell),
Function::Sum => self.fn_sum(args, cell),
Function::Sumif => self.fn_sumif(args, cell),
Function::Sumifs => self.fn_sumifs(args, cell),
// Lookup and Reference
Function::Choose => self.fn_choose(args, cell),
Function::Column => self.fn_column(args, cell),
Function::Columns => self.fn_columns(args, cell),
Function::Index => self.fn_index(args, cell),
Function::Indirect => self.fn_indirect(args, cell),
Function::Hlookup => self.fn_hlookup(args, cell),
Function::Lookup => self.fn_lookup(args, cell),
Function::Match => self.fn_match(args, cell),
Function::Offset => self.fn_offset(args, cell),
Function::Row => self.fn_row(args, cell),
Function::Rows => self.fn_rows(args, cell),
Function::Vlookup => self.fn_vlookup(args, cell),
Function::Xlookup => self.fn_xlookup(args, cell),
// Text
Function::Concatenate => self.fn_concatenate(args, cell),
Function::Exact => self.fn_exact(args, cell),
Function::Value => self.fn_value(args, cell),
Function::T => self.fn_t(args, cell),
Function::Valuetotext => self.fn_valuetotext(args, cell),
Function::Concat => self.fn_concat(args, cell),
Function::Find => self.fn_find(args, cell),
Function::Left => self.fn_left(args, cell),
Function::Len => self.fn_len(args, cell),
Function::Lower => self.fn_lower(args, cell),
Function::Mid => self.fn_mid(args, cell),
Function::Right => self.fn_right(args, cell),
Function::Search => self.fn_search(args, cell),
Function::Text => self.fn_text(args, cell),
Function::Trim => self.fn_trim(args, cell),
Function::Unicode => self.fn_unicode(args, cell),
Function::Upper => self.fn_upper(args, cell),
// Information
Function::Isnumber => self.fn_isnumber(args, cell),
Function::Isnontext => self.fn_isnontext(args, cell),
Function::Istext => self.fn_istext(args, cell),
Function::Islogical => self.fn_islogical(args, cell),
Function::Isblank => self.fn_isblank(args, cell),
Function::Iserr => self.fn_iserr(args, cell),
Function::Iserror => self.fn_iserror(args, cell),
Function::Isna => self.fn_isna(args, cell),
Function::Na => CalcResult::new_error(Error::NA, cell, "".to_string()),
Function::Isref => self.fn_isref(args, cell),
Function::Isodd => self.fn_isodd(args, cell),
Function::Iseven => self.fn_iseven(args, cell),
Function::ErrorType => self.fn_errortype(args, cell),
Function::Formulatext => self.fn_formulatext(args, cell),
Function::Isformula => self.fn_isformula(args, cell),
Function::Type => self.fn_type(args, cell),
Function::Sheet => self.fn_sheet(args, cell),
// Statistical
Function::Average => self.fn_average(args, cell),
Function::Averagea => self.fn_averagea(args, cell),
Function::Averageif => self.fn_averageif(args, cell),
Function::Averageifs => self.fn_averageifs(args, cell),
Function::Count => self.fn_count(args, cell),
Function::Counta => self.fn_counta(args, cell),
Function::Countblank => self.fn_countblank(args, cell),
Function::Countif => self.fn_countif(args, cell),
Function::Countifs => self.fn_countifs(args, cell),
Function::Maxifs => self.fn_maxifs(args, cell),
Function::Minifs => self.fn_minifs(args, cell),
Function::Geomean => self.fn_geomean(args, cell),
// Date and Time
Function::Year => self.fn_year(args, cell),
Function::Day => self.fn_day(args, cell),
Function::Eomonth => self.fn_eomonth(args, cell),
Function::Month => self.fn_month(args, cell),
Function::Date => self.fn_date(args, cell),
Function::Edate => self.fn_edate(args, cell),
Function::Today => self.fn_today(args, cell),
Function::Now => self.fn_now(args, cell),
// Financial
Function::Pmt => self.fn_pmt(args, cell),
Function::Pv => self.fn_pv(args, cell),
Function::Rate => self.fn_rate(args, cell),
Function::Nper => self.fn_nper(args, cell),
Function::Fv => self.fn_fv(args, cell),
Function::Ppmt => self.fn_ppmt(args, cell),
Function::Ipmt => self.fn_ipmt(args, cell),
Function::Npv => self.fn_npv(args, cell),
Function::Mirr => self.fn_mirr(args, cell),
Function::Irr => self.fn_irr(args, cell),
Function::Xirr => self.fn_xirr(args, cell),
Function::Xnpv => self.fn_xnpv(args, cell),
Function::Rept => self.fn_rept(args, cell),
Function::Textafter => self.fn_textafter(args, cell),
Function::Textbefore => self.fn_textbefore(args, cell),
Function::Textjoin => self.fn_textjoin(args, cell),
Function::Substitute => self.fn_substitute(args, cell),
Function::Ispmt => self.fn_ispmt(args, cell),
Function::Rri => self.fn_rri(args, cell),
Function::Sln => self.fn_sln(args, cell),
Function::Syd => self.fn_syd(args, cell),
Function::Nominal => self.fn_nominal(args, cell),
Function::Effect => self.fn_effect(args, cell),
Function::Pduration => self.fn_pduration(args, cell),
Function::Tbillyield => self.fn_tbillyield(args, cell),
Function::Tbillprice => self.fn_tbillprice(args, cell),
Function::Tbilleq => self.fn_tbilleq(args, cell),
Function::Dollarde => self.fn_dollarde(args, cell),
Function::Dollarfr => self.fn_dollarfr(args, cell),
Function::Ddb => self.fn_ddb(args, cell),
Function::Db => self.fn_db(args, cell),
Function::Cumprinc => self.fn_cumprinc(args, cell),
Function::Cumipmt => self.fn_cumipmt(args, cell),
// Engineering
Function::Besseli => self.fn_besseli(args, cell),
Function::Besselj => self.fn_besselj(args, cell),
Function::Besselk => self.fn_besselk(args, cell),
Function::Bessely => self.fn_bessely(args, cell),
Function::Erf => self.fn_erf(args, cell),
Function::ErfPrecise => self.fn_erfprecise(args, cell),
Function::Erfc => self.fn_erfc(args, cell),
Function::ErfcPrecise => self.fn_erfcprecise(args, cell),
Function::Bin2dec => self.fn_bin2dec(args, cell),
Function::Bin2hex => self.fn_bin2hex(args, cell),
Function::Bin2oct => self.fn_bin2oct(args, cell),
Function::Dec2Bin => self.fn_dec2bin(args, cell),
Function::Dec2hex => self.fn_dec2hex(args, cell),
Function::Dec2oct => self.fn_dec2oct(args, cell),
Function::Hex2bin => self.fn_hex2bin(args, cell),
Function::Hex2dec => self.fn_hex2dec(args, cell),
Function::Hex2oct => self.fn_hex2oct(args, cell),
Function::Oct2bin => self.fn_oct2bin(args, cell),
Function::Oct2dec => self.fn_oct2dec(args, cell),
Function::Oct2hex => self.fn_oct2hex(args, cell),
Function::Bitand => self.fn_bitand(args, cell),
Function::Bitlshift => self.fn_bitlshift(args, cell),
Function::Bitor => self.fn_bitor(args, cell),
Function::Bitrshift => self.fn_bitrshift(args, cell),
Function::Bitxor => self.fn_bitxor(args, cell),
Function::Complex => self.fn_complex(args, cell),
Function::Imabs => self.fn_imabs(args, cell),
Function::Imaginary => self.fn_imaginary(args, cell),
Function::Imargument => self.fn_imargument(args, cell),
Function::Imconjugate => self.fn_imconjugate(args, cell),
Function::Imcos => self.fn_imcos(args, cell),
Function::Imcosh => self.fn_imcosh(args, cell),
Function::Imcot => self.fn_imcot(args, cell),
Function::Imcsc => self.fn_imcsc(args, cell),
Function::Imcsch => self.fn_imcsch(args, cell),
Function::Imdiv => self.fn_imdiv(args, cell),
Function::Imexp => self.fn_imexp(args, cell),
Function::Imln => self.fn_imln(args, cell),
Function::Imlog10 => self.fn_imlog10(args, cell),
Function::Imlog2 => self.fn_imlog2(args, cell),
Function::Impower => self.fn_impower(args, cell),
Function::Improduct => self.fn_improduct(args, cell),
Function::Imreal => self.fn_imreal(args, cell),
Function::Imsec => self.fn_imsec(args, cell),
Function::Imsech => self.fn_imsech(args, cell),
Function::Imsin => self.fn_imsin(args, cell),
Function::Imsinh => self.fn_imsinh(args, cell),
Function::Imsqrt => self.fn_imsqrt(args, cell),
Function::Imsub => self.fn_imsub(args, cell),
Function::Imsum => self.fn_imsum(args, cell),
Function::Imtan => self.fn_imtan(args, cell),
Function::Convert => self.fn_convert(args, cell),
Function::Delta => self.fn_delta(args, cell),
Function::Gestep => self.fn_gestep(args, cell),
Function::Subtotal => self.fn_subtotal(args, cell),
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use std::{
fs::File,
io::{BufRead, BufReader},
};
use crate::functions::Function;
#[test]
fn function_iterator() {
// This checks that the number of functions in the enum is the same
// as the number of functions in the Iterator.
// This is tricky. In Rust we cannot loop over all the members of an enum.
// There are alternatives like using an external crate like strum.
// But I am not in the mood for that.
// What we do here is read this file , extract the functions in the enum
// and check they are the same as in the iterator
let file = File::open("src/functions/mod.rs").unwrap();
let reader = BufReader::new(file);
let mut start = false;
let mut list = Vec::new();
for line in reader.lines() {
let text = line.unwrap();
let text = text.trim().trim_end_matches(',');
if text == "pub enum Function {" {
start = true;
continue;
}
if start {
if text == "}" {
break;
}
if text.starts_with("//") {
// skip comments
continue;
}
if text.is_empty() {
// skip empty lines
continue;
}
list.push(text.to_owned());
}
}
// We make a list with their functions names, but we escape ".": ERROR.TYPE => ERRORTYPE
let iter_list = Function::into_iter()
.map(|f| format!("{}", f).replace('.', ""))
.collect::<Vec<_>>();
let len = iter_list.len();
assert_eq!(list.len(), len);
// We still need to check there are no duplicates. This will fail if a function in iter_list
// is included twice and one is missing
for function in list {
assert!(iter_list.contains(&function.to_uppercase()));
}
}
}