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 macros; 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, Log, Log10, Ln, 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, Datedif, Datevalue, Day, Edate, Eomonth, Month, Time, Timevalue, Hour, Minute, Second, Now, Today, Year, Networkdays, NetworkdaysIntl, Days, Days360, Weekday, Weeknum, Workday, WorkdayIntl, Yearfrac, Isoweeknum, // 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::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::Ln, Function::Log, Function::Log10, 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::Datedif, Function::Datevalue, Function::Edate, Function::Networkdays, Function::NetworkdaysIntl, Function::Time, Function::Timevalue, Function::Hour, Function::Minute, Function::Second, Function::Today, Function::Now, Function::Days, Function::Days360, Function::Weekday, Function::Weeknum, Function::Workday, Function::WorkdayIntl, Function::Yearfrac, Function::Isoweeknum, 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(), Function::Isoweeknum => "_xlfn.ISOWEEKNUM".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 { 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), "LN" => Some(Function::Ln), "LOG" => Some(Function::Log), "LOG10" => Some(Function::Log10), "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), "DATEDIF" => Some(Function::Datedif), "DATEVALUE" => Some(Function::Datevalue), "EDATE" => Some(Function::Edate), "NETWORKDAYS" => Some(Function::Networkdays), "NETWORKDAYS.INTL" => Some(Function::NetworkdaysIntl), "TIME" => Some(Function::Time), "TIMEVALUE" => Some(Function::Timevalue), "HOUR" => Some(Function::Hour), "MINUTE" => Some(Function::Minute), "SECOND" => Some(Function::Second), "TODAY" => Some(Function::Today), "NOW" => Some(Function::Now), "DAYS" | "_XLFN.DAYS" => Some(Function::Days), "DAYS360" => Some(Function::Days360), "WEEKDAY" => Some(Function::Weekday), "WEEKNUM" => Some(Function::Weeknum), "WORKDAY" => Some(Function::Workday), "WORKDAY.INTL" => Some(Function::WorkdayIntl), "YEARFRAC" => Some(Function::Yearfrac), "ISOWEEKNUM" | "_XLFN.ISOWEEKNUM" => Some(Function::Isoweeknum), // 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::Log => write!(f, "LOG"), Function::Log10 => write!(f, "LOG10"), Function::Ln => write!(f, "LN"), 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::Datedif => write!(f, "DATEDIF"), Function::Datevalue => write!(f, "DATEVALUE"), Function::Edate => write!(f, "EDATE"), Function::Networkdays => write!(f, "NETWORKDAYS"), Function::NetworkdaysIntl => write!(f, "NETWORKDAYS.INTL"), Function::Time => write!(f, "TIME"), Function::Timevalue => write!(f, "TIMEVALUE"), Function::Hour => write!(f, "HOUR"), Function::Minute => write!(f, "MINUTE"), Function::Second => write!(f, "SECOND"), Function::Today => write!(f, "TODAY"), Function::Now => write!(f, "NOW"), Function::Days => write!(f, "DAYS"), Function::Days360 => write!(f, "DAYS360"), Function::Weekday => write!(f, "WEEKDAY"), Function::Weeknum => write!(f, "WEEKNUM"), Function::Workday => write!(f, "WORKDAY"), Function::WorkdayIntl => write!(f, "WORKDAY.INTL"), Function::Yearfrac => write!(f, "YEARFRAC"), Function::Isoweeknum => write!(f, "ISOWEEKNUM"), 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 { 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 => self.fn_false(args, cell), 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 => self.fn_true(args, cell), Function::Xor => self.fn_xor(args, cell), // Math and trigonometry Function::Log => self.fn_log(args, cell), Function::Log10 => self.fn_log10(args, cell), Function::Ln => self.fn_ln(args, cell), 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::Datedif => self.fn_datedif(args, cell), Function::Datevalue => self.fn_datevalue(args, cell), Function::Edate => self.fn_edate(args, cell), Function::Networkdays => self.fn_networkdays(args, cell), Function::NetworkdaysIntl => self.fn_networkdays_intl(args, cell), Function::Time => self.fn_time(args, cell), Function::Timevalue => self.fn_timevalue(args, cell), Function::Hour => self.fn_hour(args, cell), Function::Minute => self.fn_minute(args, cell), Function::Second => self.fn_second(args, cell), Function::Today => self.fn_today(args, cell), Function::Now => self.fn_now(args, cell), Function::Days => self.fn_days(args, cell), Function::Days360 => self.fn_days360(args, cell), Function::Weekday => self.fn_weekday(args, cell), Function::Weeknum => self.fn_weeknum(args, cell), Function::Workday => self.fn_workday(args, cell), Function::WorkdayIntl => self.fn_workday_intl(args, cell), Function::Yearfrac => self.fn_yearfrac(args, cell), Function::Isoweeknum => self.fn_isoweeknum(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::>(); 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())); } } }