99        '+' => 
true, 
'-' => 
true, 
'*' => 
true, 
'/' => 
true,
 
  100        '^' => 
true, 
'&' => 
true, 
'%' => 
false, 
'~' => 
false,
 
  101        '>' => 
true, 
'<' => 
true, 
'=' => 
true, 
'>=' => 
true,
 
  102        '<=' => 
true, 
'<>' => 
true, 
'|' => 
true, 
':' => 
true,
 
  111        '+' => 
true, 
'-' => 
true, 
'*' => 
true, 
'/' => 
true,
 
  112        '^' => 
true, 
'&' => 
true, 
'>' => 
true, 
'<' => 
true,
 
  113        '=' => 
true, 
'>=' => 
true, 
'<=' => 
true, 
'<>' => 
true,
 
  114        '|' => 
true, 
':' => 
true,
 
  234            'functionCall' => [MathTrig\Absolute::class, 
'evaluate'],
 
  235            'argumentCount' => 
'1',
 
  239            'functionCall' => [Financial\Securities\AccruedInterest::class, 
'periodic'],
 
  240            'argumentCount' => 
'4-8',
 
  244            'functionCall' => [Financial\Securities\AccruedInterest::class, 
'atMaturity'],
 
  245            'argumentCount' => 
'3-5',
 
  249            'functionCall' => [MathTrig\Trig\Cosine::class, 
'acos'],
 
  250            'argumentCount' => 
'1',
 
  254            'functionCall' => [MathTrig\Trig\Cosine::class, 
'acosh'],
 
  255            'argumentCount' => 
'1',
 
  259            'functionCall' => [MathTrig\Trig\Cotangent::class, 
'acot'],
 
  260            'argumentCount' => 
'1',
 
  264            'functionCall' => [MathTrig\Trig\Cotangent::class, 
'acoth'],
 
  265            'argumentCount' => 
'1',
 
  269            'functionCall' => [LookupRef\Address::class, 
'cell'],
 
  270            'argumentCount' => 
'2-5',
 
  274            'functionCall' => [Functions::class, 
'DUMMY'],
 
  275            'argumentCount' => 
'3+',
 
  279            'functionCall' => [Financial\Amortization::class, 
'AMORDEGRC'],
 
  280            'argumentCount' => 
'6,7',
 
  284            'functionCall' => [Financial\Amortization::class, 
'AMORLINC'],
 
  285            'argumentCount' => 
'6,7',
 
  289            'functionCall' => [Logical\Operations::class, 
'logicalAnd'],
 
  290            'argumentCount' => 
'1+',
 
  294            'functionCall' => [MathTrig\Arabic::class, 
'evaluate'],
 
  295            'argumentCount' => 
'1',
 
  299            'functionCall' => [Functions::class, 
'DUMMY'],
 
  300            'argumentCount' => 
'1',
 
  304            'functionCall' => [Functions::class, 
'DUMMY'],
 
  305            'argumentCount' => 
'?',
 
  309            'functionCall' => [Functions::class, 
'DUMMY'],
 
  310            'argumentCount' => 
'1',
 
  314            'functionCall' => [MathTrig\Trig\Sine::class, 
'asin'],
 
  315            'argumentCount' => 
'1',
 
  319            'functionCall' => [MathTrig\Trig\Sine::class, 
'asinh'],
 
  320            'argumentCount' => 
'1',
 
  324            'functionCall' => [MathTrig\Trig\Tangent::class, 
'atan'],
 
  325            'argumentCount' => 
'1',
 
  329            'functionCall' => [MathTrig\Trig\Tangent::class, 
'atan2'],
 
  330            'argumentCount' => 
'2',
 
  334            'functionCall' => [MathTrig\Trig\Tangent::class, 
'atanh'],
 
  335            'argumentCount' => 
'1',
 
  339            'functionCall' => [Statistical\Averages::class, 
'averageDeviations'],
 
  340            'argumentCount' => 
'1+',
 
  344            'functionCall' => [Statistical\Averages::class, 
'average'],
 
  345            'argumentCount' => 
'1+',
 
  349            'functionCall' => [Statistical\Averages::class, 
'averageA'],
 
  350            'argumentCount' => 
'1+',
 
  354            'functionCall' => [Statistical\Conditional::class, 
'AVERAGEIF'],
 
  355            'argumentCount' => 
'2,3',
 
  359            'functionCall' => [Statistical\Conditional::class, 
'AVERAGEIFS'],
 
  360            'argumentCount' => 
'3+',
 
  364            'functionCall' => [Functions::class, 
'DUMMY'],
 
  365            'argumentCount' => 
'1',
 
  369            'functionCall' => [MathTrig\Base::class, 
'evaluate'],
 
  370            'argumentCount' => 
'2,3',
 
  374            'functionCall' => [Engineering\BesselI::class, 
'BESSELI'],
 
  375            'argumentCount' => 
'2',
 
  379            'functionCall' => [Engineering\BesselJ::class, 
'BESSELJ'],
 
  380            'argumentCount' => 
'2',
 
  384            'functionCall' => [Engineering\BesselK::class, 
'BESSELK'],
 
  385            'argumentCount' => 
'2',
 
  389            'functionCall' => [Engineering\BesselY::class, 
'BESSELY'],
 
  390            'argumentCount' => 
'2',
 
  394            'functionCall' => [Statistical\Distributions\Beta::class, 
'distribution'],
 
  395            'argumentCount' => 
'3-5',
 
  399            'functionCall' => [Functions::class, 
'DUMMY'],
 
  400            'argumentCount' => 
'4-6',
 
  404            'functionCall' => [Statistical\Distributions\Beta::class, 
'inverse'],
 
  405            'argumentCount' => 
'3-5',
 
  409            'functionCall' => [Statistical\Distributions\Beta::class, 
'inverse'],
 
  410            'argumentCount' => 
'3-5',
 
  414            'functionCall' => [Engineering\ConvertBinary::class, 
'toDecimal'],
 
  415            'argumentCount' => 
'1',
 
  419            'functionCall' => [Engineering\ConvertBinary::class, 
'toHex'],
 
  420            'argumentCount' => 
'1,2',
 
  424            'functionCall' => [Engineering\ConvertBinary::class, 
'toOctal'],
 
  425            'argumentCount' => 
'1,2',
 
  429            'functionCall' => [Statistical\Distributions\Binomial::class, 
'distribution'],
 
  430            'argumentCount' => 
'4',
 
  434            'functionCall' => [Statistical\Distributions\Binomial::class, 
'distribution'],
 
  435            'argumentCount' => 
'4',
 
  437        'BINOM.DIST.RANGE' => [
 
  439            'functionCall' => [Statistical\Distributions\Binomial::class, 
'range'],
 
  440            'argumentCount' => 
'3,4',
 
  444            'functionCall' => [Statistical\Distributions\Binomial::class, 
'inverse'],
 
  445            'argumentCount' => 
'3',
 
  449            'functionCall' => [Engineering\BitWise::class, 
'BITAND'],
 
  450            'argumentCount' => 
'2',
 
  454            'functionCall' => [Engineering\BitWise::class, 
'BITOR'],
 
  455            'argumentCount' => 
'2',
 
  459            'functionCall' => [Engineering\BitWise::class, 
'BITXOR'],
 
  460            'argumentCount' => 
'2',
 
  464            'functionCall' => [Engineering\BitWise::class, 
'BITLSHIFT'],
 
  465            'argumentCount' => 
'2',
 
  469            'functionCall' => [Engineering\BitWise::class, 
'BITRSHIFT'],
 
  470            'argumentCount' => 
'2',
 
  474            'functionCall' => [MathTrig\Ceiling::class, 
'ceiling'],
 
  475            'argumentCount' => 
'1-2', 
 
  479            'functionCall' => [MathTrig\Ceiling::class, 
'math'],
 
  480            'argumentCount' => 
'1-3',
 
  482        'CEILING.PRECISE' => [
 
  484            'functionCall' => [MathTrig\Ceiling::class, 
'precise'],
 
  485            'argumentCount' => 
'1,2',
 
  489            'functionCall' => [Functions::class, 
'DUMMY'],
 
  490            'argumentCount' => 
'1,2',
 
  494            'functionCall' => [TextData\CharacterConvert::class, 
'character'],
 
  495            'argumentCount' => 
'1',
 
  499            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'distributionRightTail'],
 
  500            'argumentCount' => 
'2',
 
  504            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'distributionLeftTail'],
 
  505            'argumentCount' => 
'3',
 
  509            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'distributionRightTail'],
 
  510            'argumentCount' => 
'2',
 
  514            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'inverseRightTail'],
 
  515            'argumentCount' => 
'2',
 
  519            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'inverseLeftTail'],
 
  520            'argumentCount' => 
'2',
 
  524            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'inverseRightTail'],
 
  525            'argumentCount' => 
'2',
 
  529            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'test'],
 
  530            'argumentCount' => 
'2',
 
  534            'functionCall' => [Statistical\Distributions\ChiSquared::class, 
'test'],
 
  535            'argumentCount' => 
'2',
 
  539            'functionCall' => [LookupRef\Selection::class, 
'CHOOSE'],
 
  540            'argumentCount' => 
'2+',
 
  544            'functionCall' => [TextData\Trim::class, 
'nonPrintable'],
 
  545            'argumentCount' => 
'1',
 
  549            'functionCall' => [TextData\CharacterConvert::class, 
'code'],
 
  550            'argumentCount' => 
'1',
 
  554            'functionCall' => [LookupRef\RowColumnInformation::class, 
'COLUMN'],
 
  555            'argumentCount' => 
'-1',
 
  556            'passCellReference' => 
true,
 
  557            'passByReference' => [
true],
 
  561            'functionCall' => [LookupRef\RowColumnInformation::class, 
'COLUMNS'],
 
  562            'argumentCount' => 
'1',
 
  566            'functionCall' => [MathTrig\Combinations::class, 
'withoutRepetition'],
 
  567            'argumentCount' => 
'2',
 
  571            'functionCall' => [MathTrig\Combinations::class, 
'withRepetition'],
 
  572            'argumentCount' => 
'2',
 
  576            'functionCall' => [Engineering\Complex::class, 
'COMPLEX'],
 
  577            'argumentCount' => 
'2,3',
 
  581            'functionCall' => [TextData\Concatenate::class, 
'CONCATENATE'],
 
  582            'argumentCount' => 
'1+',
 
  586            'functionCall' => [TextData\Concatenate::class, 
'CONCATENATE'],
 
  587            'argumentCount' => 
'1+',
 
  591            'functionCall' => [Statistical\Confidence::class, 
'CONFIDENCE'],
 
  592            'argumentCount' => 
'3',
 
  594        'CONFIDENCE.NORM' => [
 
  596            'functionCall' => [Statistical\Confidence::class, 
'CONFIDENCE'],
 
  597            'argumentCount' => 
'3',
 
  601            'functionCall' => [Functions::class, 
'DUMMY'],
 
  602            'argumentCount' => 
'3',
 
  606            'functionCall' => [Engineering\ConvertUOM::class, 
'CONVERT'],
 
  607            'argumentCount' => 
'3',
 
  611            'functionCall' => [Statistical\Trends::class, 
'CORREL'],
 
  612            'argumentCount' => 
'2',
 
  616            'functionCall' => [MathTrig\Trig\Cosine::class, 
'cos'],
 
  617            'argumentCount' => 
'1',
 
  621            'functionCall' => [MathTrig\Trig\Cosine::class, 
'cosh'],
 
  622            'argumentCount' => 
'1',
 
  626            'functionCall' => [MathTrig\Trig\Cotangent::class, 
'cot'],
 
  627            'argumentCount' => 
'1',
 
  631            'functionCall' => [MathTrig\Trig\Cotangent::class, 
'coth'],
 
  632            'argumentCount' => 
'1',
 
  636            'functionCall' => [Statistical\Counts::class, 
'COUNT'],
 
  637            'argumentCount' => 
'1+',
 
  641            'functionCall' => [Statistical\Counts::class, 
'COUNTA'],
 
  642            'argumentCount' => 
'1+',
 
  646            'functionCall' => [Statistical\Counts::class, 
'COUNTBLANK'],
 
  647            'argumentCount' => 
'1',
 
  651            'functionCall' => [Statistical\Conditional::class, 
'COUNTIF'],
 
  652            'argumentCount' => 
'2',
 
  656            'functionCall' => [Statistical\Conditional::class, 
'COUNTIFS'],
 
  657            'argumentCount' => 
'2+',
 
  661            'functionCall' => [Financial\Coupons::class, 
'COUPDAYBS'],
 
  662            'argumentCount' => 
'3,4',
 
  666            'functionCall' => [Financial\Coupons::class, 
'COUPDAYS'],
 
  667            'argumentCount' => 
'3,4',
 
  671            'functionCall' => [Financial\Coupons::class, 
'COUPDAYSNC'],
 
  672            'argumentCount' => 
'3,4',
 
  676            'functionCall' => [Financial\Coupons::class, 
'COUPNCD'],
 
  677            'argumentCount' => 
'3,4',
 
  681            'functionCall' => [Financial\Coupons::class, 
'COUPNUM'],
 
  682            'argumentCount' => 
'3,4',
 
  686            'functionCall' => [Financial\Coupons::class, 
'COUPPCD'],
 
  687            'argumentCount' => 
'3,4',
 
  691            'functionCall' => [Statistical\Trends::class, 
'COVAR'],
 
  692            'argumentCount' => 
'2',
 
  696            'functionCall' => [Statistical\Trends::class, 
'COVAR'],
 
  697            'argumentCount' => 
'2',
 
  701            'functionCall' => [Functions::class, 
'DUMMY'],
 
  702            'argumentCount' => 
'2',
 
  706            'functionCall' => [Statistical\Distributions\Binomial::class, 
'inverse'],
 
  707            'argumentCount' => 
'3',
 
  711            'functionCall' => [MathTrig\Trig\Cosecant::class, 
'csc'],
 
  712            'argumentCount' => 
'1',
 
  716            'functionCall' => [MathTrig\Trig\Cosecant::class, 
'csch'],
 
  717            'argumentCount' => 
'1',
 
  721            'functionCall' => [Functions::class, 
'DUMMY'],
 
  722            'argumentCount' => 
'?',
 
  726            'functionCall' => [Functions::class, 
'DUMMY'],
 
  727            'argumentCount' => 
'?',
 
  729        'CUBEMEMBERPROPERTY' => [
 
  731            'functionCall' => [Functions::class, 
'DUMMY'],
 
  732            'argumentCount' => 
'?',
 
  734        'CUBERANKEDMEMBER' => [
 
  736            'functionCall' => [Functions::class, 
'DUMMY'],
 
  737            'argumentCount' => 
'?',
 
  741            'functionCall' => [Functions::class, 
'DUMMY'],
 
  742            'argumentCount' => 
'?',
 
  746            'functionCall' => [Functions::class, 
'DUMMY'],
 
  747            'argumentCount' => 
'?',
 
  751            'functionCall' => [Functions::class, 
'DUMMY'],
 
  752            'argumentCount' => 
'?',
 
  756            'functionCall' => [Financial\CashFlow\Constant\Periodic\Cumulative::class, 
'interest'],
 
  757            'argumentCount' => 
'6',
 
  761            'functionCall' => [Financial\CashFlow\Constant\Periodic\Cumulative::class, 
'principal'],
 
  762            'argumentCount' => 
'6',
 
  766            'functionCall' => [DateTimeExcel\Date::class, 
'fromYMD'],
 
  767            'argumentCount' => 
'3',
 
  771            'functionCall' => [DateTimeExcel\Difference::class, 
'interval'],
 
  772            'argumentCount' => 
'2,3',
 
  776            'functionCall' => [Functions::class, 
'DUMMY'],
 
  777            'argumentCount' => 
'?',
 
  781            'functionCall' => [DateTimeExcel\DateValue::class, 
'fromString'],
 
  782            'argumentCount' => 
'1',
 
  786            'functionCall' => [Database\DAverage::class, 
'evaluate'],
 
  787            'argumentCount' => 
'3',
 
  791            'functionCall' => [DateTimeExcel\DateParts::class, 
'day'],
 
  792            'argumentCount' => 
'1',
 
  796            'functionCall' => [DateTimeExcel\Days::class, 
'between'],
 
  797            'argumentCount' => 
'2',
 
  801            'functionCall' => [DateTimeExcel\Days360::class, 
'between'],
 
  802            'argumentCount' => 
'2,3',
 
  806            'functionCall' => [Financial\Depreciation::class, 
'DB'],
 
  807            'argumentCount' => 
'4,5',
 
  811            'functionCall' => [Functions::class, 
'DUMMY'],
 
  812            'argumentCount' => 
'1',
 
  816            'functionCall' => [Database\DCount::class, 
'evaluate'],
 
  817            'argumentCount' => 
'3',
 
  821            'functionCall' => [Database\DCountA::class, 
'evaluate'],
 
  822            'argumentCount' => 
'3',
 
  826            'functionCall' => [Financial\Depreciation::class, 
'DDB'],
 
  827            'argumentCount' => 
'4,5',
 
  831            'functionCall' => [Engineering\ConvertDecimal::class, 
'toBinary'],
 
  832            'argumentCount' => 
'1,2',
 
  836            'functionCall' => [Engineering\ConvertDecimal::class, 
'toHex'],
 
  837            'argumentCount' => 
'1,2',
 
  841            'functionCall' => [Engineering\ConvertDecimal::class, 
'toOctal'],
 
  842            'argumentCount' => 
'1,2',
 
  846            'functionCall' => [Functions::class, 
'DUMMY'],
 
  847            'argumentCount' => 
'2',
 
  851            'functionCall' => [MathTrig\Angle::class, 
'toDegrees'],
 
  852            'argumentCount' => 
'1',
 
  856            'functionCall' => [Engineering\Compare::class, 
'DELTA'],
 
  857            'argumentCount' => 
'1,2',
 
  861            'functionCall' => [Statistical\Deviations::class, 
'sumSquares'],
 
  862            'argumentCount' => 
'1+',
 
  866            'functionCall' => [Database\DGet::class, 
'evaluate'],
 
  867            'argumentCount' => 
'3',
 
  871            'functionCall' => [Financial\Securities\Rates::class, 
'discount'],
 
  872            'argumentCount' => 
'4,5',
 
  876            'functionCall' => [Database\DMax::class, 
'evaluate'],
 
  877            'argumentCount' => 
'3',
 
  881            'functionCall' => [Database\DMin::class, 
'evaluate'],
 
  882            'argumentCount' => 
'3',
 
  886            'functionCall' => [TextData\Format::class, 
'DOLLAR'],
 
  887            'argumentCount' => 
'1,2',
 
  891            'functionCall' => [Financial\Dollar::class, 
'decimal'],
 
  892            'argumentCount' => 
'2',
 
  896            'functionCall' => [Financial\Dollar::class, 
'fractional'],
 
  897            'argumentCount' => 
'2',
 
  901            'functionCall' => [Database\DProduct::class, 
'evaluate'],
 
  902            'argumentCount' => 
'3',
 
  906            'functionCall' => [Database\DStDev::class, 
'evaluate'],
 
  907            'argumentCount' => 
'3',
 
  911            'functionCall' => [Database\DStDevP::class, 
'evaluate'],
 
  912            'argumentCount' => 
'3',
 
  916            'functionCall' => [Database\DSum::class, 
'evaluate'],
 
  917            'argumentCount' => 
'3',
 
  921            'functionCall' => [Functions::class, 
'DUMMY'],
 
  922            'argumentCount' => 
'5,6',
 
  926            'functionCall' => [Database\DVar::class, 
'evaluate'],
 
  927            'argumentCount' => 
'3',
 
  931            'functionCall' => [Database\DVarP::class, 
'evaluate'],
 
  932            'argumentCount' => 
'3',
 
  936            'functionCall' => [Functions::class, 
'DUMMY'],
 
  937            'argumentCount' => 
'1,2',
 
  941            'functionCall' => [DateTimeExcel\Month::class, 
'adjust'],
 
  942            'argumentCount' => 
'2',
 
  946            'functionCall' => [Financial\InterestRate::class, 
'effective'],
 
  947            'argumentCount' => 
'2',
 
  951            'functionCall' => [Web\Service::class, 
'urlEncode'],
 
  952            'argumentCount' => 
'1',
 
  956            'functionCall' => [DateTimeExcel\Month::class, 
'lastDay'],
 
  957            'argumentCount' => 
'2',
 
  961            'functionCall' => [Engineering\Erf::class, 
'ERF'],
 
  962            'argumentCount' => 
'1,2',
 
  966            'functionCall' => [Engineering\Erf::class, 
'ERFPRECISE'],
 
  967            'argumentCount' => 
'1',
 
  971            'functionCall' => [Engineering\ErfC::class, 
'ERFC'],
 
  972            'argumentCount' => 
'1',
 
  976            'functionCall' => [Engineering\ErfC::class, 
'ERFC'],
 
  977            'argumentCount' => 
'1',
 
  981            'functionCall' => [Functions::class, 
'errorType'],
 
  982            'argumentCount' => 
'1',
 
  986            'functionCall' => [MathTrig\Round::class, 
'even'],
 
  987            'argumentCount' => 
'1',
 
  991            'functionCall' => [TextData\Text::class, 
'exact'],
 
  992            'argumentCount' => 
'2',
 
  996            'functionCall' => [MathTrig\Exp::class, 
'evaluate'],
 
  997            'argumentCount' => 
'1',
 
 1001            'functionCall' => [Statistical\Distributions\Exponential::class, 
'distribution'],
 
 1002            'argumentCount' => 
'3',
 
 1006            'functionCall' => [Statistical\Distributions\Exponential::class, 
'distribution'],
 
 1007            'argumentCount' => 
'3',
 
 1011            'functionCall' => [MathTrig\Factorial::class, 
'fact'],
 
 1012            'argumentCount' => 
'1',
 
 1016            'functionCall' => [MathTrig\Factorial::class, 
'factDouble'],
 
 1017            'argumentCount' => 
'1',
 
 1021            'functionCall' => [Logical\Boolean::class, 
'FALSE'],
 
 1022            'argumentCount' => 
'0',
 
 1026            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1027            'argumentCount' => 
'3',
 
 1031            'functionCall' => [Statistical\Distributions\F::class, 
'distribution'],
 
 1032            'argumentCount' => 
'4',
 
 1036            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1037            'argumentCount' => 
'3',
 
 1041            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1042            'argumentCount' => 
'3+',
 
 1046            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1047            'argumentCount' => 
'2',
 
 1051            'functionCall' => [TextData\Search::class, 
'sensitive'],
 
 1052            'argumentCount' => 
'2,3',
 
 1056            'functionCall' => [TextData\Search::class, 
'sensitive'],
 
 1057            'argumentCount' => 
'2,3',
 
 1061            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1062            'argumentCount' => 
'3',
 
 1066            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1067            'argumentCount' => 
'3',
 
 1071            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1072            'argumentCount' => 
'3',
 
 1076            'functionCall' => [Statistical\Distributions\Fisher::class, 
'distribution'],
 
 1077            'argumentCount' => 
'1',
 
 1081            'functionCall' => [Statistical\Distributions\Fisher::class, 
'inverse'],
 
 1082            'argumentCount' => 
'1',
 
 1086            'functionCall' => [TextData\Format::class, 
'FIXEDFORMAT'],
 
 1087            'argumentCount' => 
'1-3',
 
 1091            'functionCall' => [MathTrig\Floor::class, 
'floor'],
 
 1092            'argumentCount' => 
'1-2', 
 
 1096            'functionCall' => [MathTrig\Floor::class, 
'math'],
 
 1097            'argumentCount' => 
'1-3',
 
 1099        'FLOOR.PRECISE' => [
 
 1101            'functionCall' => [MathTrig\Floor::class, 
'precise'],
 
 1102            'argumentCount' => 
'1-2',
 
 1106            'functionCall' => [Statistical\Trends::class, 
'FORECAST'],
 
 1107            'argumentCount' => 
'3',
 
 1111            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1112            'argumentCount' => 
'3-6',
 
 1114        'FORECAST.ETS.CONFINT' => [
 
 1116            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1117            'argumentCount' => 
'3-6',
 
 1119        'FORECAST.ETS.SEASONALITY' => [
 
 1121            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1122            'argumentCount' => 
'2-4',
 
 1124        'FORECAST.ETS.STAT' => [
 
 1126            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1127            'argumentCount' => 
'3-6',
 
 1129        'FORECAST.LINEAR' => [
 
 1131            'functionCall' => [Statistical\Trends::class, 
'FORECAST'],
 
 1132            'argumentCount' => 
'3',
 
 1136            'functionCall' => [LookupRef\Formula::class, 
'text'],
 
 1137            'argumentCount' => 
'1',
 
 1138            'passCellReference' => 
true,
 
 1139            'passByReference' => [
true],
 
 1143            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1144            'argumentCount' => 
'2',
 
 1148            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1149            'argumentCount' => 
'2',
 
 1153            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1154            'argumentCount' => 
'2',
 
 1158            'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 
'futureValue'],
 
 1159            'argumentCount' => 
'3-5',
 
 1163            'functionCall' => [Financial\CashFlow\Single::class, 
'futureValue'],
 
 1164            'argumentCount' => 
'2',
 
 1168            'functionCall' => [Statistical\Distributions\Gamma::class, 
'gamma'],
 
 1169            'argumentCount' => 
'1',
 
 1173            'functionCall' => [Statistical\Distributions\Gamma::class, 
'distribution'],
 
 1174            'argumentCount' => 
'4',
 
 1178            'functionCall' => [Statistical\Distributions\Gamma::class, 
'distribution'],
 
 1179            'argumentCount' => 
'4',
 
 1183            'functionCall' => [Statistical\Distributions\Gamma::class, 
'inverse'],
 
 1184            'argumentCount' => 
'3',
 
 1188            'functionCall' => [Statistical\Distributions\Gamma::class, 
'inverse'],
 
 1189            'argumentCount' => 
'3',
 
 1193            'functionCall' => [Statistical\Distributions\Gamma::class, 
'ln'],
 
 1194            'argumentCount' => 
'1',
 
 1196        'GAMMALN.PRECISE' => [
 
 1198            'functionCall' => [Statistical\Distributions\Gamma::class, 
'ln'],
 
 1199            'argumentCount' => 
'1',
 
 1203            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'gauss'],
 
 1204            'argumentCount' => 
'1',
 
 1208            'functionCall' => [MathTrig\Gcd::class, 
'evaluate'],
 
 1209            'argumentCount' => 
'1+',
 
 1213            'functionCall' => [Statistical\Averages\Mean::class, 
'geometric'],
 
 1214            'argumentCount' => 
'1+',
 
 1218            'functionCall' => [Engineering\Compare::class, 
'GESTEP'],
 
 1219            'argumentCount' => 
'1,2',
 
 1223            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1224            'argumentCount' => 
'2+',
 
 1228            'functionCall' => [Statistical\Trends::class, 
'GROWTH'],
 
 1229            'argumentCount' => 
'1-4',
 
 1233            'functionCall' => [Statistical\Averages\Mean::class, 
'harmonic'],
 
 1234            'argumentCount' => 
'1+',
 
 1238            'functionCall' => [Engineering\ConvertHex::class, 
'toBinary'],
 
 1239            'argumentCount' => 
'1,2',
 
 1243            'functionCall' => [Engineering\ConvertHex::class, 
'toDecimal'],
 
 1244            'argumentCount' => 
'1',
 
 1248            'functionCall' => [Engineering\ConvertHex::class, 
'toOctal'],
 
 1249            'argumentCount' => 
'1,2',
 
 1253            'functionCall' => [LookupRef\HLookup::class, 
'lookup'],
 
 1254            'argumentCount' => 
'3,4',
 
 1258            'functionCall' => [DateTimeExcel\TimeParts::class, 
'hour'],
 
 1259            'argumentCount' => 
'1',
 
 1263            'functionCall' => [LookupRef\Hyperlink::class, 
'set'],
 
 1264            'argumentCount' => 
'1,2',
 
 1265            'passCellReference' => 
true,
 
 1269            'functionCall' => [Statistical\Distributions\HyperGeometric::class, 
'distribution'],
 
 1270            'argumentCount' => 
'4',
 
 1274            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1275            'argumentCount' => 
'5',
 
 1279            'functionCall' => [Logical\Conditional::class, 
'statementIf'],
 
 1280            'argumentCount' => 
'1-3',
 
 1284            'functionCall' => [Logical\Conditional::class, 
'IFERROR'],
 
 1285            'argumentCount' => 
'2',
 
 1289            'functionCall' => [Logical\Conditional::class, 
'IFNA'],
 
 1290            'argumentCount' => 
'2',
 
 1294            'functionCall' => [Logical\Conditional::class, 
'IFS'],
 
 1295            'argumentCount' => 
'2+',
 
 1299            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMABS'],
 
 1300            'argumentCount' => 
'1',
 
 1304            'functionCall' => [Engineering\Complex::class, 
'IMAGINARY'],
 
 1305            'argumentCount' => 
'1',
 
 1309            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMARGUMENT'],
 
 1310            'argumentCount' => 
'1',
 
 1314            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCONJUGATE'],
 
 1315            'argumentCount' => 
'1',
 
 1319            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCOS'],
 
 1320            'argumentCount' => 
'1',
 
 1324            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCOSH'],
 
 1325            'argumentCount' => 
'1',
 
 1329            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCOT'],
 
 1330            'argumentCount' => 
'1',
 
 1334            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCSC'],
 
 1335            'argumentCount' => 
'1',
 
 1339            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMCSCH'],
 
 1340            'argumentCount' => 
'1',
 
 1344            'functionCall' => [Engineering\ComplexOperations::class, 
'IMDIV'],
 
 1345            'argumentCount' => 
'2',
 
 1349            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMEXP'],
 
 1350            'argumentCount' => 
'1',
 
 1354            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMLN'],
 
 1355            'argumentCount' => 
'1',
 
 1359            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMLOG10'],
 
 1360            'argumentCount' => 
'1',
 
 1364            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMLOG2'],
 
 1365            'argumentCount' => 
'1',
 
 1369            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMPOWER'],
 
 1370            'argumentCount' => 
'2',
 
 1374            'functionCall' => [Engineering\ComplexOperations::class, 
'IMPRODUCT'],
 
 1375            'argumentCount' => 
'1+',
 
 1379            'functionCall' => [Engineering\Complex::class, 
'IMREAL'],
 
 1380            'argumentCount' => 
'1',
 
 1384            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMSEC'],
 
 1385            'argumentCount' => 
'1',
 
 1389            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMSECH'],
 
 1390            'argumentCount' => 
'1',
 
 1394            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMSIN'],
 
 1395            'argumentCount' => 
'1',
 
 1399            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMSINH'],
 
 1400            'argumentCount' => 
'1',
 
 1404            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMSQRT'],
 
 1405            'argumentCount' => 
'1',
 
 1409            'functionCall' => [Engineering\ComplexOperations::class, 
'IMSUB'],
 
 1410            'argumentCount' => 
'2',
 
 1414            'functionCall' => [Engineering\ComplexOperations::class, 
'IMSUM'],
 
 1415            'argumentCount' => 
'1+',
 
 1419            'functionCall' => [Engineering\ComplexFunctions::class, 
'IMTAN'],
 
 1420            'argumentCount' => 
'1',
 
 1424            'functionCall' => [LookupRef\Matrix::class, 
'index'],
 
 1425            'argumentCount' => 
'1-4',
 
 1429            'functionCall' => [LookupRef\Indirect::class, 
'INDIRECT'],
 
 1430            'argumentCount' => 
'1,2',
 
 1431            'passCellReference' => 
true,
 
 1435            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1436            'argumentCount' => 
'1',
 
 1440            'functionCall' => [MathTrig\IntClass::class, 
'evaluate'],
 
 1441            'argumentCount' => 
'1',
 
 1445            'functionCall' => [Statistical\Trends::class, 
'INTERCEPT'],
 
 1446            'argumentCount' => 
'2',
 
 1450            'functionCall' => [Financial\Securities\Rates::class, 
'interest'],
 
 1451            'argumentCount' => 
'4,5',
 
 1455            'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 
'payment'],
 
 1456            'argumentCount' => 
'4-6',
 
 1460            'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 
'rate'],
 
 1461            'argumentCount' => 
'1,2',
 
 1465            'functionCall' => [Functions::class, 
'isBlank'],
 
 1466            'argumentCount' => 
'1',
 
 1470            'functionCall' => [Functions::class, 
'isErr'],
 
 1471            'argumentCount' => 
'1',
 
 1475            'functionCall' => [Functions::class, 
'isError'],
 
 1476            'argumentCount' => 
'1',
 
 1480            'functionCall' => [Functions::class, 
'isEven'],
 
 1481            'argumentCount' => 
'1',
 
 1485            'functionCall' => [Functions::class, 
'isFormula'],
 
 1486            'argumentCount' => 
'1',
 
 1487            'passCellReference' => 
true,
 
 1488            'passByReference' => [
true],
 
 1492            'functionCall' => [Functions::class, 
'isLogical'],
 
 1493            'argumentCount' => 
'1',
 
 1497            'functionCall' => [Functions::class, 
'isNa'],
 
 1498            'argumentCount' => 
'1',
 
 1502            'functionCall' => [Functions::class, 
'isNonText'],
 
 1503            'argumentCount' => 
'1',
 
 1507            'functionCall' => [Functions::class, 
'isNumber'],
 
 1508            'argumentCount' => 
'1',
 
 1512            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1513            'argumentCount' => 
'1,2',
 
 1517            'functionCall' => [Functions::class, 
'isOdd'],
 
 1518            'argumentCount' => 
'1',
 
 1522            'functionCall' => [DateTimeExcel\Week::class, 
'isoWeekNumber'],
 
 1523            'argumentCount' => 
'1',
 
 1527            'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 
'schedulePayment'],
 
 1528            'argumentCount' => 
'4',
 
 1532            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1533            'argumentCount' => 
'1',
 
 1537            'functionCall' => [Functions::class, 
'isText'],
 
 1538            'argumentCount' => 
'1',
 
 1542            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1543            'argumentCount' => 
'?',
 
 1547            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1548            'argumentCount' => 
'1',
 
 1552            'functionCall' => [Statistical\Deviations::class, 
'kurtosis'],
 
 1553            'argumentCount' => 
'1+',
 
 1557            'functionCall' => [Statistical\Size::class, 
'large'],
 
 1558            'argumentCount' => 
'2',
 
 1562            'functionCall' => [MathTrig\Lcm::class, 
'evaluate'],
 
 1563            'argumentCount' => 
'1+',
 
 1567            'functionCall' => [TextData\Extract::class, 
'left'],
 
 1568            'argumentCount' => 
'1,2',
 
 1572            'functionCall' => [TextData\Extract::class, 
'left'],
 
 1573            'argumentCount' => 
'1,2',
 
 1577            'functionCall' => [TextData\Text::class, 
'length'],
 
 1578            'argumentCount' => 
'1',
 
 1582            'functionCall' => [TextData\Text::class, 
'length'],
 
 1583            'argumentCount' => 
'1',
 
 1587            'functionCall' => [Statistical\Trends::class, 
'LINEST'],
 
 1588            'argumentCount' => 
'1-4',
 
 1592            'functionCall' => [MathTrig\Logarithms::class, 
'natural'],
 
 1593            'argumentCount' => 
'1',
 
 1597            'functionCall' => [MathTrig\Logarithms::class, 
'withBase'],
 
 1598            'argumentCount' => 
'1,2',
 
 1602            'functionCall' => [MathTrig\Logarithms::class, 
'base10'],
 
 1603            'argumentCount' => 
'1',
 
 1607            'functionCall' => [Statistical\Trends::class, 
'LOGEST'],
 
 1608            'argumentCount' => 
'1-4',
 
 1612            'functionCall' => [Statistical\Distributions\LogNormal::class, 
'inverse'],
 
 1613            'argumentCount' => 
'3',
 
 1617            'functionCall' => [Statistical\Distributions\LogNormal::class, 
'cumulative'],
 
 1618            'argumentCount' => 
'3',
 
 1622            'functionCall' => [Statistical\Distributions\LogNormal::class, 
'distribution'],
 
 1623            'argumentCount' => 
'4',
 
 1627            'functionCall' => [Statistical\Distributions\LogNormal::class, 
'inverse'],
 
 1628            'argumentCount' => 
'3',
 
 1632            'functionCall' => [LookupRef\Lookup::class, 
'lookup'],
 
 1633            'argumentCount' => 
'2,3',
 
 1637            'functionCall' => [TextData\CaseConvert::class, 
'lower'],
 
 1638            'argumentCount' => 
'1',
 
 1642            'functionCall' => [LookupRef\ExcelMatch::class, 
'MATCH'],
 
 1643            'argumentCount' => 
'2,3',
 
 1647            'functionCall' => [Statistical\Maximum::class, 
'max'],
 
 1648            'argumentCount' => 
'1+',
 
 1652            'functionCall' => [Statistical\Maximum::class, 
'maxA'],
 
 1653            'argumentCount' => 
'1+',
 
 1657            'functionCall' => [Statistical\Conditional::class, 
'MAXIFS'],
 
 1658            'argumentCount' => 
'3+',
 
 1662            'functionCall' => [MathTrig\MatrixFunctions::class, 
'determinant'],
 
 1663            'argumentCount' => 
'1',
 
 1667            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1668            'argumentCount' => 
'5,6',
 
 1672            'functionCall' => [Statistical\Averages::class, 
'median'],
 
 1673            'argumentCount' => 
'1+',
 
 1677            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1678            'argumentCount' => 
'2+',
 
 1682            'functionCall' => [TextData\Extract::class, 
'mid'],
 
 1683            'argumentCount' => 
'3',
 
 1687            'functionCall' => [TextData\Extract::class, 
'mid'],
 
 1688            'argumentCount' => 
'3',
 
 1692            'functionCall' => [Statistical\Minimum::class, 
'min'],
 
 1693            'argumentCount' => 
'1+',
 
 1697            'functionCall' => [Statistical\Minimum::class, 
'minA'],
 
 1698            'argumentCount' => 
'1+',
 
 1702            'functionCall' => [Statistical\Conditional::class, 
'MINIFS'],
 
 1703            'argumentCount' => 
'3+',
 
 1707            'functionCall' => [DateTimeExcel\TimeParts::class, 
'minute'],
 
 1708            'argumentCount' => 
'1',
 
 1712            'functionCall' => [MathTrig\MatrixFunctions::class, 
'inverse'],
 
 1713            'argumentCount' => 
'1',
 
 1717            'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 
'modifiedRate'],
 
 1718            'argumentCount' => 
'3',
 
 1722            'functionCall' => [MathTrig\MatrixFunctions::class, 
'multiply'],
 
 1723            'argumentCount' => 
'2',
 
 1727            'functionCall' => [MathTrig\Operations::class, 
'mod'],
 
 1728            'argumentCount' => 
'2',
 
 1732            'functionCall' => [Statistical\Averages::class, 
'mode'],
 
 1733            'argumentCount' => 
'1+',
 
 1737            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1738            'argumentCount' => 
'1+',
 
 1742            'functionCall' => [Statistical\Averages::class, 
'mode'],
 
 1743            'argumentCount' => 
'1+',
 
 1747            'functionCall' => [DateTimeExcel\DateParts::class, 
'month'],
 
 1748            'argumentCount' => 
'1',
 
 1752            'functionCall' => [MathTrig\Round::class, 
'multiple'],
 
 1753            'argumentCount' => 
'2',
 
 1757            'functionCall' => [MathTrig\Factorial::class, 
'multinomial'],
 
 1758            'argumentCount' => 
'1+',
 
 1762            'functionCall' => [MathTrig\MatrixFunctions::class, 
'identity'],
 
 1763            'argumentCount' => 
'1',
 
 1767            'functionCall' => [Functions::class, 
'n'],
 
 1768            'argumentCount' => 
'1',
 
 1772            'functionCall' => [Functions::class, 
'NA'],
 
 1773            'argumentCount' => 
'0',
 
 1777            'functionCall' => [Statistical\Distributions\Binomial::class, 
'negative'],
 
 1778            'argumentCount' => 
'3',
 
 1780        'NEGBINOM.DIST' => [
 
 1782            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1783            'argumentCount' => 
'4',
 
 1787            'functionCall' => [DateTimeExcel\NetworkDays::class, 
'count'],
 
 1788            'argumentCount' => 
'2-3',
 
 1790        'NETWORKDAYS.INTL' => [
 
 1792            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1793            'argumentCount' => 
'2-4',
 
 1797            'functionCall' => [Financial\InterestRate::class, 
'nominal'],
 
 1798            'argumentCount' => 
'2',
 
 1802            'functionCall' => [Statistical\Distributions\Normal::class, 
'distribution'],
 
 1803            'argumentCount' => 
'4',
 
 1807            'functionCall' => [Statistical\Distributions\Normal::class, 
'distribution'],
 
 1808            'argumentCount' => 
'4',
 
 1812            'functionCall' => [Statistical\Distributions\Normal::class, 
'inverse'],
 
 1813            'argumentCount' => 
'3',
 
 1817            'functionCall' => [Statistical\Distributions\Normal::class, 
'inverse'],
 
 1818            'argumentCount' => 
'3',
 
 1822            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'cumulative'],
 
 1823            'argumentCount' => 
'1',
 
 1827            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'distribution'],
 
 1828            'argumentCount' => 
'1,2',
 
 1832            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'inverse'],
 
 1833            'argumentCount' => 
'1',
 
 1837            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'inverse'],
 
 1838            'argumentCount' => 
'1',
 
 1842            'functionCall' => [Logical\Operations::class, 
'NOT'],
 
 1843            'argumentCount' => 
'1',
 
 1847            'functionCall' => [DateTimeExcel\Current::class, 
'now'],
 
 1848            'argumentCount' => 
'0',
 
 1852            'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 
'periods'],
 
 1853            'argumentCount' => 
'3-5',
 
 1857            'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 
'presentValue'],
 
 1858            'argumentCount' => 
'2+',
 
 1862            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1863            'argumentCount' => 
'?',
 
 1867            'functionCall' => [TextData\Format::class, 
'NUMBERVALUE'],
 
 1868            'argumentCount' => 
'1+',
 
 1872            'functionCall' => [Engineering\ConvertOctal::class, 
'toBinary'],
 
 1873            'argumentCount' => 
'1,2',
 
 1877            'functionCall' => [Engineering\ConvertOctal::class, 
'toDecimal'],
 
 1878            'argumentCount' => 
'1',
 
 1882            'functionCall' => [Engineering\ConvertOctal::class, 
'toHex'],
 
 1883            'argumentCount' => 
'1,2',
 
 1887            'functionCall' => [MathTrig\Round::class, 
'odd'],
 
 1888            'argumentCount' => 
'1',
 
 1892            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1893            'argumentCount' => 
'8,9',
 
 1897            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1898            'argumentCount' => 
'8,9',
 
 1902            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1903            'argumentCount' => 
'7,8',
 
 1907            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1908            'argumentCount' => 
'7,8',
 
 1912            'functionCall' => [LookupRef\Offset::class, 
'OFFSET'],
 
 1913            'argumentCount' => 
'3-5',
 
 1914            'passCellReference' => 
true,
 
 1915            'passByReference' => [
true],
 
 1919            'functionCall' => [Logical\Operations::class, 
'logicalOr'],
 
 1920            'argumentCount' => 
'1+',
 
 1924            'functionCall' => [Financial\CashFlow\Single::class, 
'periods'],
 
 1925            'argumentCount' => 
'3',
 
 1929            'functionCall' => [Statistical\Trends::class, 
'CORREL'],
 
 1930            'argumentCount' => 
'2',
 
 1934            'functionCall' => [Statistical\Percentiles::class, 
'PERCENTILE'],
 
 1935            'argumentCount' => 
'2',
 
 1937        'PERCENTILE.EXC' => [
 
 1939            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1940            'argumentCount' => 
'2',
 
 1942        'PERCENTILE.INC' => [
 
 1944            'functionCall' => [Statistical\Percentiles::class, 
'PERCENTILE'],
 
 1945            'argumentCount' => 
'2',
 
 1949            'functionCall' => [Statistical\Percentiles::class, 
'PERCENTRANK'],
 
 1950            'argumentCount' => 
'2,3',
 
 1952        'PERCENTRANK.EXC' => [
 
 1954            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1955            'argumentCount' => 
'2,3',
 
 1957        'PERCENTRANK.INC' => [
 
 1959            'functionCall' => [Statistical\Percentiles::class, 
'PERCENTRANK'],
 
 1960            'argumentCount' => 
'2,3',
 
 1964            'functionCall' => [Statistical\Permutations::class, 
'PERMUT'],
 
 1965            'argumentCount' => 
'2',
 
 1969            'functionCall' => [Statistical\Permutations::class, 
'PERMUTATIONA'],
 
 1970            'argumentCount' => 
'2',
 
 1974            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1975            'argumentCount' => 
'1',
 
 1979            'functionCall' => [Functions::class, 
'DUMMY'],
 
 1980            'argumentCount' => 
'1',
 
 1984            'functionCall' => 
'pi',
 
 1985            'argumentCount' => 
'0',
 
 1989            'functionCall' => [Financial\CashFlow\Constant\Periodic\Payments::class, 
'annuity'],
 
 1990            'argumentCount' => 
'3-5',
 
 1994            'functionCall' => [Statistical\Distributions\Poisson::class, 
'distribution'],
 
 1995            'argumentCount' => 
'3',
 
 1999            'functionCall' => [Statistical\Distributions\Poisson::class, 
'distribution'],
 
 2000            'argumentCount' => 
'3',
 
 2004            'functionCall' => [MathTrig\Operations::class, 
'power'],
 
 2005            'argumentCount' => 
'2',
 
 2009            'functionCall' => [Financial\CashFlow\Constant\Periodic\Payments::class, 
'interestPayment'],
 
 2010            'argumentCount' => 
'4-6',
 
 2014            'functionCall' => [Financial\Securities\Price::class, 
'price'],
 
 2015            'argumentCount' => 
'6,7',
 
 2019            'functionCall' => [Financial\Securities\Price::class, 
'priceDiscounted'],
 
 2020            'argumentCount' => 
'4,5',
 
 2024            'functionCall' => [Financial\Securities\Price::class, 
'priceAtMaturity'],
 
 2025            'argumentCount' => 
'5,6',
 
 2029            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2030            'argumentCount' => 
'3,4',
 
 2034            'functionCall' => [MathTrig\Operations::class, 
'product'],
 
 2035            'argumentCount' => 
'1+',
 
 2039            'functionCall' => [TextData\CaseConvert::class, 
'proper'],
 
 2040            'argumentCount' => 
'1',
 
 2044            'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 
'presentValue'],
 
 2045            'argumentCount' => 
'3-5',
 
 2049            'functionCall' => [Statistical\Percentiles::class, 
'QUARTILE'],
 
 2050            'argumentCount' => 
'2',
 
 2054            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2055            'argumentCount' => 
'2',
 
 2059            'functionCall' => [Statistical\Percentiles::class, 
'QUARTILE'],
 
 2060            'argumentCount' => 
'2',
 
 2064            'functionCall' => [MathTrig\Operations::class, 
'quotient'],
 
 2065            'argumentCount' => 
'2',
 
 2069            'functionCall' => [MathTrig\Angle::class, 
'toRadians'],
 
 2070            'argumentCount' => 
'1',
 
 2074            'functionCall' => [MathTrig\Random::class, 
'rand'],
 
 2075            'argumentCount' => 
'0',
 
 2079            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2080            'argumentCount' => 
'0-5',
 
 2084            'functionCall' => [MathTrig\Random::class, 
'randBetween'],
 
 2085            'argumentCount' => 
'2',
 
 2089            'functionCall' => [Statistical\Percentiles::class, 
'RANK'],
 
 2090            'argumentCount' => 
'2,3',
 
 2094            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2095            'argumentCount' => 
'2,3',
 
 2099            'functionCall' => [Statistical\Percentiles::class, 
'RANK'],
 
 2100            'argumentCount' => 
'2,3',
 
 2104            'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 
'rate'],
 
 2105            'argumentCount' => 
'3-6',
 
 2109            'functionCall' => [Financial\Securities\Price::class, 
'received'],
 
 2110            'argumentCount' => 
'4-5',
 
 2114            'functionCall' => [TextData\Replace::class, 
'replace'],
 
 2115            'argumentCount' => 
'4',
 
 2119            'functionCall' => [TextData\Replace::class, 
'replace'],
 
 2120            'argumentCount' => 
'4',
 
 2124            'functionCall' => [TextData\Concatenate::class, 
'builtinREPT'],
 
 2125            'argumentCount' => 
'2',
 
 2129            'functionCall' => [TextData\Extract::class, 
'right'],
 
 2130            'argumentCount' => 
'1,2',
 
 2134            'functionCall' => [TextData\Extract::class, 
'right'],
 
 2135            'argumentCount' => 
'1,2',
 
 2139            'functionCall' => [MathTrig\Roman::class, 
'evaluate'],
 
 2140            'argumentCount' => 
'1,2',
 
 2144            'functionCall' => [MathTrig\Round::class, 
'round'],
 
 2145            'argumentCount' => 
'2',
 
 2147        'ROUNDBAHTDOWN' => [
 
 2149            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2150            'argumentCount' => 
'?',
 
 2154            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2155            'argumentCount' => 
'?',
 
 2159            'functionCall' => [MathTrig\Round::class, 
'down'],
 
 2160            'argumentCount' => 
'2',
 
 2164            'functionCall' => [MathTrig\Round::class, 
'up'],
 
 2165            'argumentCount' => 
'2',
 
 2169            'functionCall' => [LookupRef\RowColumnInformation::class, 
'ROW'],
 
 2170            'argumentCount' => 
'-1',
 
 2171            'passCellReference' => 
true,
 
 2172            'passByReference' => [
true],
 
 2176            'functionCall' => [LookupRef\RowColumnInformation::class, 
'ROWS'],
 
 2177            'argumentCount' => 
'1',
 
 2181            'functionCall' => [Financial\CashFlow\Single::class, 
'interestRate'],
 
 2182            'argumentCount' => 
'3',
 
 2186            'functionCall' => [Statistical\Trends::class, 
'RSQ'],
 
 2187            'argumentCount' => 
'2',
 
 2191            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2192            'argumentCount' => 
'1+',
 
 2196            'functionCall' => [TextData\Search::class, 
'insensitive'],
 
 2197            'argumentCount' => 
'2,3',
 
 2201            'functionCall' => [TextData\Search::class, 
'insensitive'],
 
 2202            'argumentCount' => 
'2,3',
 
 2206            'functionCall' => [MathTrig\Trig\Secant::class, 
'sec'],
 
 2207            'argumentCount' => 
'1',
 
 2211            'functionCall' => [MathTrig\Trig\Secant::class, 
'sech'],
 
 2212            'argumentCount' => 
'1',
 
 2216            'functionCall' => [DateTimeExcel\TimeParts::class, 
'second'],
 
 2217            'argumentCount' => 
'1',
 
 2221            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2222            'argumentCount' => 
'2',
 
 2226            'functionCall' => [MathTrig\SeriesSum::class, 
'evaluate'],
 
 2227            'argumentCount' => 
'4',
 
 2231            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2232            'argumentCount' => 
'0,1',
 
 2236            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2237            'argumentCount' => 
'0,1',
 
 2241            'functionCall' => [MathTrig\Sign::class, 
'evaluate'],
 
 2242            'argumentCount' => 
'1',
 
 2246            'functionCall' => [MathTrig\Trig\Sine::class, 
'sin'],
 
 2247            'argumentCount' => 
'1',
 
 2251            'functionCall' => [MathTrig\Trig\Sine::class, 
'sinh'],
 
 2252            'argumentCount' => 
'1',
 
 2256            'functionCall' => [Statistical\Deviations::class, 
'skew'],
 
 2257            'argumentCount' => 
'1+',
 
 2261            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2262            'argumentCount' => 
'1+',
 
 2266            'functionCall' => [Financial\Depreciation::class, 
'SLN'],
 
 2267            'argumentCount' => 
'3',
 
 2271            'functionCall' => [Statistical\Trends::class, 
'SLOPE'],
 
 2272            'argumentCount' => 
'2',
 
 2276            'functionCall' => [Statistical\Size::class, 
'small'],
 
 2277            'argumentCount' => 
'2',
 
 2281            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2282            'argumentCount' => 
'1+',
 
 2286            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2287            'argumentCount' => 
'2+',
 
 2291            'functionCall' => [MathTrig\Sqrt::class, 
'sqrt'],
 
 2292            'argumentCount' => 
'1',
 
 2296            'functionCall' => [MathTrig\Sqrt::class, 
'pi'],
 
 2297            'argumentCount' => 
'1',
 
 2301            'functionCall' => [Statistical\Standardize::class, 
'execute'],
 
 2302            'argumentCount' => 
'3',
 
 2306            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEV'],
 
 2307            'argumentCount' => 
'1+',
 
 2311            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEV'],
 
 2312            'argumentCount' => 
'1+',
 
 2316            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEVP'],
 
 2317            'argumentCount' => 
'1+',
 
 2321            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEVA'],
 
 2322            'argumentCount' => 
'1+',
 
 2326            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEVP'],
 
 2327            'argumentCount' => 
'1+',
 
 2331            'functionCall' => [Statistical\StandardDeviations::class, 
'STDEVPA'],
 
 2332            'argumentCount' => 
'1+',
 
 2336            'functionCall' => [Statistical\Trends::class, 
'STEYX'],
 
 2337            'argumentCount' => 
'2',
 
 2341            'functionCall' => [TextData\Replace::class, 
'substitute'],
 
 2342            'argumentCount' => 
'3,4',
 
 2346            'functionCall' => [MathTrig\Subtotal::class, 
'evaluate'],
 
 2347            'argumentCount' => 
'2+',
 
 2348            'passCellReference' => 
true,
 
 2352            'functionCall' => [MathTrig\Sum::class, 
'sumErroringStrings'],
 
 2353            'argumentCount' => 
'1+',
 
 2357            'functionCall' => [Statistical\Conditional::class, 
'SUMIF'],
 
 2358            'argumentCount' => 
'2,3',
 
 2362            'functionCall' => [Statistical\Conditional::class, 
'SUMIFS'],
 
 2363            'argumentCount' => 
'3+',
 
 2367            'functionCall' => [MathTrig\Sum::class, 
'product'],
 
 2368            'argumentCount' => 
'1+',
 
 2372            'functionCall' => [MathTrig\SumSquares::class, 
'sumSquare'],
 
 2373            'argumentCount' => 
'1+',
 
 2377            'functionCall' => [MathTrig\SumSquares::class, 
'sumXSquaredMinusYSquared'],
 
 2378            'argumentCount' => 
'2',
 
 2382            'functionCall' => [MathTrig\SumSquares::class, 
'sumXSquaredPlusYSquared'],
 
 2383            'argumentCount' => 
'2',
 
 2387            'functionCall' => [MathTrig\SumSquares::class, 
'sumXMinusYSquared'],
 
 2388            'argumentCount' => 
'2',
 
 2392            'functionCall' => [Logical\Conditional::class, 
'statementSwitch'],
 
 2393            'argumentCount' => 
'3+',
 
 2397            'functionCall' => [Financial\Depreciation::class, 
'SYD'],
 
 2398            'argumentCount' => 
'4',
 
 2402            'functionCall' => [TextData\Text::class, 
'test'],
 
 2403            'argumentCount' => 
'1',
 
 2407            'functionCall' => [MathTrig\Trig\Tangent::class, 
'tan'],
 
 2408            'argumentCount' => 
'1',
 
 2412            'functionCall' => [MathTrig\Trig\Tangent::class, 
'tanh'],
 
 2413            'argumentCount' => 
'1',
 
 2417            'functionCall' => [Financial\TreasuryBill::class, 
'bondEquivalentYield'],
 
 2418            'argumentCount' => 
'3',
 
 2422            'functionCall' => [Financial\TreasuryBill::class, 
'price'],
 
 2423            'argumentCount' => 
'3',
 
 2427            'functionCall' => [Financial\TreasuryBill::class, 
'yield'],
 
 2428            'argumentCount' => 
'3',
 
 2432            'functionCall' => [Statistical\Distributions\StudentT::class, 
'distribution'],
 
 2433            'argumentCount' => 
'3',
 
 2437            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2438            'argumentCount' => 
'3',
 
 2442            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2443            'argumentCount' => 
'2',
 
 2447            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2448            'argumentCount' => 
'2',
 
 2452            'functionCall' => [TextData\Format::class, 
'TEXTFORMAT'],
 
 2453            'argumentCount' => 
'2',
 
 2457            'functionCall' => [TextData\Concatenate::class, 
'TEXTJOIN'],
 
 2458            'argumentCount' => 
'3+',
 
 2460        'THAIDAYOFWEEK' => [
 
 2462            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2463            'argumentCount' => 
'?',
 
 2467            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2468            'argumentCount' => 
'?',
 
 2470        'THAIMONTHOFYEAR' => [
 
 2472            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2473            'argumentCount' => 
'?',
 
 2477            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2478            'argumentCount' => 
'?',
 
 2480        'THAINUMSTRING' => [
 
 2482            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2483            'argumentCount' => 
'?',
 
 2485        'THAISTRINGLENGTH' => [
 
 2487            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2488            'argumentCount' => 
'?',
 
 2492            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2493            'argumentCount' => 
'?',
 
 2497            'functionCall' => [DateTimeExcel\Time::class, 
'fromHMS'],
 
 2498            'argumentCount' => 
'3',
 
 2502            'functionCall' => [DateTimeExcel\TimeValue::class, 
'fromString'],
 
 2503            'argumentCount' => 
'1',
 
 2507            'functionCall' => [Statistical\Distributions\StudentT::class, 
'inverse'],
 
 2508            'argumentCount' => 
'2',
 
 2512            'functionCall' => [Statistical\Distributions\StudentT::class, 
'inverse'],
 
 2513            'argumentCount' => 
'2',
 
 2517            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2518            'argumentCount' => 
'2',
 
 2522            'functionCall' => [DateTimeExcel\Current::class, 
'today'],
 
 2523            'argumentCount' => 
'0',
 
 2527            'functionCall' => [LookupRef\Matrix::class, 
'transpose'],
 
 2528            'argumentCount' => 
'1',
 
 2532            'functionCall' => [Statistical\Trends::class, 
'TREND'],
 
 2533            'argumentCount' => 
'1-4',
 
 2537            'functionCall' => [TextData\Trim::class, 
'spaces'],
 
 2538            'argumentCount' => 
'1',
 
 2542            'functionCall' => [Statistical\Averages\Mean::class, 
'trim'],
 
 2543            'argumentCount' => 
'2',
 
 2547            'functionCall' => [Logical\Boolean::class, 
'TRUE'],
 
 2548            'argumentCount' => 
'0',
 
 2552            'functionCall' => [MathTrig\Trunc::class, 
'evaluate'],
 
 2553            'argumentCount' => 
'1,2',
 
 2557            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2558            'argumentCount' => 
'4',
 
 2562            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2563            'argumentCount' => 
'4',
 
 2567            'functionCall' => [Functions::class, 
'TYPE'],
 
 2568            'argumentCount' => 
'1',
 
 2572            'functionCall' => [TextData\CharacterConvert::class, 
'character'],
 
 2573            'argumentCount' => 
'1',
 
 2577            'functionCall' => [TextData\CharacterConvert::class, 
'code'],
 
 2578            'argumentCount' => 
'1',
 
 2582            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2583            'argumentCount' => 
'1+',
 
 2587            'functionCall' => [TextData\CaseConvert::class, 
'upper'],
 
 2588            'argumentCount' => 
'1',
 
 2592            'functionCall' => [Financial\Dollar::class, 
'format'],
 
 2593            'argumentCount' => 
'2',
 
 2597            'functionCall' => [TextData\Format::class, 
'VALUE'],
 
 2598            'argumentCount' => 
'1',
 
 2602            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2603            'argumentCount' => 
'?',
 
 2607            'functionCall' => [Statistical\Variances::class, 
'VAR'],
 
 2608            'argumentCount' => 
'1+',
 
 2612            'functionCall' => [Statistical\Variances::class, 
'VARP'],
 
 2613            'argumentCount' => 
'1+',
 
 2617            'functionCall' => [Statistical\Variances::class, 
'VAR'],
 
 2618            'argumentCount' => 
'1+',
 
 2622            'functionCall' => [Statistical\Variances::class, 
'VARA'],
 
 2623            'argumentCount' => 
'1+',
 
 2627            'functionCall' => [Statistical\Variances::class, 
'VARP'],
 
 2628            'argumentCount' => 
'1+',
 
 2632            'functionCall' => [Statistical\Variances::class, 
'VARPA'],
 
 2633            'argumentCount' => 
'1+',
 
 2637            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2638            'argumentCount' => 
'5-7',
 
 2642            'functionCall' => [LookupRef\VLookup::class, 
'lookup'],
 
 2643            'argumentCount' => 
'3,4',
 
 2647            'functionCall' => [Web\Service::class, 
'webService'],
 
 2648            'argumentCount' => 
'1',
 
 2652            'functionCall' => [DateTimeExcel\Week::class, 
'day'],
 
 2653            'argumentCount' => 
'1,2',
 
 2657            'functionCall' => [DateTimeExcel\Week::class, 
'number'],
 
 2658            'argumentCount' => 
'1,2',
 
 2662            'functionCall' => [Statistical\Distributions\Weibull::class, 
'distribution'],
 
 2663            'argumentCount' => 
'4',
 
 2667            'functionCall' => [Statistical\Distributions\Weibull::class, 
'distribution'],
 
 2668            'argumentCount' => 
'4',
 
 2672            'functionCall' => [DateTimeExcel\WorkDay::class, 
'date'],
 
 2673            'argumentCount' => 
'2-3',
 
 2677            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2678            'argumentCount' => 
'2-4',
 
 2682            'functionCall' => [Financial\CashFlow\Variable\NonPeriodic::class, 
'rate'],
 
 2683            'argumentCount' => 
'2,3',
 
 2687            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2688            'argumentCount' => 
'3-6',
 
 2692            'functionCall' => [Financial\CashFlow\Variable\NonPeriodic::class, 
'presentValue'],
 
 2693            'argumentCount' => 
'3',
 
 2697            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2698            'argumentCount' => 
'2,3',
 
 2702            'functionCall' => [Logical\Operations::class, 
'logicalXor'],
 
 2703            'argumentCount' => 
'1+',
 
 2707            'functionCall' => [DateTimeExcel\DateParts::class, 
'year'],
 
 2708            'argumentCount' => 
'1',
 
 2712            'functionCall' => [DateTimeExcel\YearFrac::class, 
'fraction'],
 
 2713            'argumentCount' => 
'2,3',
 
 2717            'functionCall' => [Functions::class, 
'DUMMY'],
 
 2718            'argumentCount' => 
'6,7',
 
 2722            'functionCall' => [Financial\Securities\Yields::class, 
'yieldDiscounted'],
 
 2723            'argumentCount' => 
'4,5',
 
 2727            'functionCall' => [Financial\Securities\Yields::class, 
'yieldAtMaturity'],
 
 2728            'argumentCount' => 
'5,6',
 
 2732            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'zTest'],
 
 2733            'argumentCount' => 
'2-3',
 
 2737            'functionCall' => [Statistical\Distributions\StandardNormal::class, 
'zTest'],
 
 2738            'argumentCount' => 
'2-3',
 
 2745            'argumentCount' => 
'*',
 
 2746            'functionCall' => [Internal\MakeMatrix::class, 
'make'],
 
 2749            'argumentCount' => 
'*',
 
 2750            'functionCall' => [Functions::class, 
'NAME'],
 
 2752        'WILDCARDMATCH' => [
 
 2753            'argumentCount' => 
'2',
 
 2754            'functionCall' => [Internal\WildcardMatch::class, 
'compare'],
 
 2760        $this->delta = 1 * 10 ** (0 - ini_get(
'precision'));
 
 2764        $this->debugLog = 
new Logger($this->cyclicReferenceStack);
 
 2770        $localeFileDirectory = __DIR__ . 
'/locale/';
 
 2771        foreach (glob($localeFileDirectory . 
'*', GLOB_ONLYDIR) as 
$filename) {
 
 2774                self::$validLocaleLanguages[] = 
$filename;
 
 2794        if (!isset(self::$instance) || (self::$instance === 
null)) {
 
 2795            self::$instance = 
new self();
 
 2826        throw new Exception(
'Cloning the calculation engine is not allowed!');
 
 2836        return self::$localeBoolean[
'TRUE'];
 
 2846        return self::$localeBoolean[
'FALSE'];
 
 2859            ($returnType == self::RETURN_ARRAY_AS_VALUE) ||
 
 2860            ($returnType == self::RETURN_ARRAY_AS_ERROR) ||
 
 2861            ($returnType == self::RETURN_ARRAY_AS_ARRAY)
 
 2863            self::$returnArrayAsType = $returnType;
 
 2898        $this->calculationCacheEnabled = $pValue;
 
 2923        $this->calculationCache = [];
 
 2933        if (isset($this->calculationCache[$worksheetName])) {
 
 2934            unset($this->calculationCache[$worksheetName]);
 
 2946        if (isset($this->calculationCache[$fromWorksheetName])) {
 
 2947            $this->calculationCache[$toWorksheetName] = &$this->calculationCache[$fromWorksheetName];
 
 2948            unset($this->calculationCache[$fromWorksheetName]);
 
 2959        $this->branchPruningEnabled = $enabled;
 
 2974        $this->branchStoreKeyCounter = 0;
 
 2989        $localeFileName = $localeDir . str_replace(
'_', DIRECTORY_SEPARATOR, $locale) .
 
 2990            DIRECTORY_SEPARATOR . $file;
 
 2991        if (!file_exists($localeFileName)) {
 
 2993            $localeFileName = $localeDir . 
$language . DIRECTORY_SEPARATOR . $file;
 
 2994            if (!file_exists($localeFileName)) {
 
 2995                throw new Exception(
'Locale file not found');
 
 2999        return $localeFileName;
 
 3012        $language = $locale = strtolower($locale);
 
 3013        if (strpos($locale, 
'_') !== 
false) {
 
 3016        if (count(self::$validLocaleLanguages) == 1) {
 
 3021        if (in_array(
$language, self::$validLocaleLanguages)) {
 
 3023            self::$localeFunctions = [];
 
 3024            self::$localeArgumentSeparator = 
',';
 
 3025            self::$localeBoolean = [
'TRUE' => 
'TRUE', 
'FALSE' => 
'FALSE', 
'NULL' => 
'NULL'];
 
 3028            if ($locale !== 
'en_us') {
 
 3029                $localeDir = implode(DIRECTORY_SEPARATOR, [__DIR__, 
'locale', 
null]);
 
 3038                $localeFunctions = file($functionNamesFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
 
 3040                    [$localeFunction] = explode(
'##', $localeFunction); 
 
 3041                    if (strpos($localeFunction, 
'=') !== 
false) {
 
 3042                        [$fName, $lfName] = array_map(
'trim', explode(
'=', $localeFunction));
 
 3043                        if ((isset(self::$phpSpreadsheetFunctions[$fName])) && ($lfName != 
'') && ($fName != $lfName)) {
 
 3044                            self::$localeFunctions[$fName] = $lfName;
 
 3049                if (isset(self::$localeFunctions[
'TRUE'])) {
 
 3050                    self::$localeBoolean[
'TRUE'] = self::$localeFunctions[
'TRUE'];
 
 3052                if (isset(self::$localeFunctions[
'FALSE'])) {
 
 3053                    self::$localeBoolean[
'FALSE'] = self::$localeFunctions[
'FALSE'];
 
 3062                $localeSettings = file($configFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
 
 3063                foreach ($localeSettings as $localeSetting) {
 
 3064                    [$localeSetting] = explode(
'##', $localeSetting); 
 
 3065                    if (strpos($localeSetting, 
'=') !== 
false) {
 
 3066                        [$settingName, $settingValue] = array_map(
'trim', explode(
'=', $localeSetting));
 
 3067                        $settingName = strtoupper($settingName);
 
 3068                        if ($settingValue !== 
'') {
 
 3069                            switch ($settingName) {
 
 3070                                case 'ARGUMENTSEPARATOR':
 
 3071                                    self::$localeArgumentSeparator = $settingValue;
 
 3080            self::$functionReplaceFromExcel = self::$functionReplaceToExcel =
 
 3081            self::$functionReplaceFromLocale = self::$functionReplaceToLocale = 
null;
 
 3082            self::$localeLanguage = $locale;
 
 3100        $strlen = mb_strlen($formula);
 
 3101        for (
$i = 0; 
$i < $strlen; ++
$i) {
 
 3102            $chr = mb_substr($formula, 
$i, 1);
 
 3112                case $fromSeparator:
 
 3114                        $formula = mb_substr($formula, 0, 
$i) . $toSeparator . mb_substr($formula, 
$i + 1);
 
 3134        if (self::$localeLanguage !== 
'en_us') {
 
 3137            if (strpos($formula, self::FORMULA_STRING_QUOTE) !== 
false) {
 
 3140                $temp = explode(self::FORMULA_STRING_QUOTE, $formula);
 
 3142                foreach ($temp as &$value) {
 
 3145                        $value = preg_replace(
$from, $to, $value);
 
 3151                $formula = implode(self::FORMULA_STRING_QUOTE, $temp);
 
 3154                $formula = preg_replace(
$from, $to, $formula);
 
 3168        if (self::$functionReplaceFromExcel === 
null) {
 
 3169            self::$functionReplaceFromExcel = [];
 
 3170            foreach (array_keys(self::$localeFunctions) as $excelFunctionName) {
 
 3171                self::$functionReplaceFromExcel[] = 
'/(@?[^\w\.])' . preg_quote($excelFunctionName, 
'/') . 
'([\s]*\()/Ui';
 
 3173            foreach (array_keys(self::$localeBoolean) as $excelBoolean) {
 
 3174                self::$functionReplaceFromExcel[] = 
'/(@?[^\w\.])' . preg_quote($excelBoolean, 
'/') . 
'([^\w\.])/Ui';
 
 3178        if (self::$functionReplaceToLocale === 
null) {
 
 3179            self::$functionReplaceToLocale = [];
 
 3180            foreach (self::$localeFunctions as $localeFunctionName) {
 
 3181                self::$functionReplaceToLocale[] = 
'$1' . trim($localeFunctionName) . 
'$2';
 
 3184                self::$functionReplaceToLocale[] = 
'$1' . trim(
$localeBoolean) . 
'$2';
 
 3188        return self::translateFormula(self::$functionReplaceFromExcel, self::$functionReplaceToLocale, $formula, 
',', self::$localeArgumentSeparator);
 
 3197        if (self::$functionReplaceFromLocale === 
null) {
 
 3198            self::$functionReplaceFromLocale = [];
 
 3199            foreach (self::$localeFunctions as $localeFunctionName) {
 
 3200                self::$functionReplaceFromLocale[] = 
'/(@?[^\w\.])' . preg_quote($localeFunctionName, 
'/') . 
'([\s]*\()/Ui';
 
 3202            foreach (self::$localeBoolean as $excelBoolean) {
 
 3203                self::$functionReplaceFromLocale[] = 
'/(@?[^\w\.])' . preg_quote($excelBoolean, 
'/') . 
'([^\w\.])/Ui';
 
 3207        if (self::$functionReplaceToExcel === 
null) {
 
 3208            self::$functionReplaceToExcel = [];
 
 3209            foreach (array_keys(self::$localeFunctions) as $excelFunctionName) {
 
 3210                self::$functionReplaceToExcel[] = 
'$1' . trim($excelFunctionName) . 
'$2';
 
 3212            foreach (array_keys(self::$localeBoolean) as $excelBoolean) {
 
 3213                self::$functionReplaceToExcel[] = 
'$1' . trim($excelBoolean) . 
'$2';
 
 3217        return self::translateFormula(self::$functionReplaceFromLocale, self::$functionReplaceToExcel, $formula, self::$localeArgumentSeparator, 
',');
 
 3222        if (self::$localeLanguage !== 
'en_us') {
 
 3223            $functionName = trim($function, 
'(');
 
 3224            if (isset(self::$localeFunctions[$functionName])) {
 
 3225                $brace = ($functionName != $function);
 
 3226                $function = self::$localeFunctions[$functionName];
 
 3245        if (is_string($value)) {
 
 3247            if (preg_match(
'/^' . self::CALCULATION_REGEXP_ERROR . 
'$/i', $value, $match)) {
 
 3254        } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
 
 3271        if (is_string($value)) {
 
 3272            if ((isset($value[0])) && ($value[0] == self::FORMULA_STRING_QUOTE) && (substr($value, -1) == self::FORMULA_STRING_QUOTE)) {
 
 3273                return substr($value, 1, -1);
 
 3276        } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
 
 3310        if ($pCell === 
null) {
 
 3317            $this->formulaError = 
null;
 
 3318            $this->debugLog->clearLog();
 
 3319            $this->cyclicReferenceStack->clear();
 
 3320            $this->cyclicFormulaCounter = 1;
 
 3326        $this->cellStack[] = [
 
 3327            'sheet' => $pCell->getWorksheet()->getTitle(),
 
 3328            'cell' => $pCell->getCoordinate(),
 
 3333            $cellAddress = array_pop($this->cellStack);
 
 3334            $this->spreadsheet->getSheetByName($cellAddress[
'sheet'])->getCell($cellAddress[
'cell']);
 
 3336            $cellAddress = array_pop($this->cellStack);
 
 3337            $this->spreadsheet->getSheetByName($cellAddress[
'sheet'])->getCell($cellAddress[
'cell']);
 
 3342        if ((is_array(
$result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
 
 3345            if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) {
 
 3349            if (count($testResult) != 1) {
 
 3352                $r = array_shift(
$r);
 
 3353                if (!is_numeric(
$r)) {
 
 3358                    $c = array_shift(
$c);
 
 3359                    if (!is_numeric(
$c)) {
 
 3364            $result = array_shift($testResult);
 
 3368        if (
$result === 
null && $pCell->getWorksheet()->getSheetView()->getShowZeros()) {
 
 3388        $formula = trim($formula);
 
 3389        if ((!isset($formula[0])) || ($formula[0] != 
'=')) {
 
 3392        $formula = ltrim(substr($formula, 1));
 
 3393        if (!isset($formula[0])) {
 
 3413        $this->formulaError = 
null;
 
 3414        $this->debugLog->clearLog();
 
 3415        $this->cyclicReferenceStack->clear();
 
 3418        if ($this->spreadsheet !== 
null && $cellID === 
null && $pCell === 
null) {
 
 3420            $pCell = $this->spreadsheet->getActiveSheet()->getCell($cellID);
 
 3424            $this->calculationCacheEnabled = 
false;
 
 3434        if ($this->spreadsheet === 
null) {
 
 3436            $this->calculationCacheEnabled = $resetCache;
 
 3447        $this->debugLog->writeDebugLog(
"Testing cache value for cell {$cellReference}");
 
 3450        if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
 
 3451            $this->debugLog->writeDebugLog(
"Retrieving value for cell {$cellReference} from cache");
 
 3454            $cellValue = $this->calculationCache[$cellReference];
 
 3468        if ($this->calculationCacheEnabled) {
 
 3469            $this->calculationCache[$cellReference] = $cellValue;
 
 3487        if ($pCell !== 
null && $pCell->getStyle()->getQuotePrefix() === 
true) {
 
 3491        if (preg_match(
'/^=\s*cmd\s*\|/miu', $formula) !== 0) {
 
 3497        $formula = trim($formula);
 
 3498        if ($formula[0] != 
'=') {
 
 3501        $formula = ltrim(substr($formula, 1));
 
 3502        if (!isset($formula[0])) {
 
 3506        $pCellParent = ($pCell !== 
null) ? $pCell->getWorksheet() : 
null;
 
 3507        $wsTitle = ($pCellParent !== 
null) ? $pCellParent->getTitle() : 
"\x00Wrk";
 
 3508        $wsCellReference = $wsTitle . 
'!' . $cellID;
 
 3510        if (($cellID !== 
null) && ($this->
getValueFromCache($wsCellReference, $cellValue))) {
 
 3513        $this->debugLog->writeDebugLog(
"Evaluating formula for cell {$wsCellReference}");
 
 3515        if (($wsTitle[0] !== 
"\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
 
 3516            if ($this->cyclicFormulaCount <= 0) {
 
 3517                $this->cyclicFormulaCell = 
'';
 
 3520            } elseif ($this->cyclicFormulaCell === $wsCellReference) {
 
 3522                if ($this->cyclicFormulaCounter >= $this->cyclicFormulaCount) {
 
 3523                    $this->cyclicFormulaCell = 
'';
 
 3527            } elseif ($this->cyclicFormulaCell == 
'') {
 
 3528                if ($this->cyclicFormulaCounter >= $this->cyclicFormulaCount) {
 
 3531                $this->cyclicFormulaCell = $wsCellReference;
 
 3535        $this->debugLog->writeDebugLog(
"Formula for cell {$wsCellReference} is {$formula}");
 
 3537        $this->cyclicReferenceStack->push($wsCellReference);
 
 3540        $this->cyclicReferenceStack->pop();
 
 3543        if ($cellID !== 
null) {
 
 3569        if (!is_array($operand1)) {
 
 3571            $operand1 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand1));
 
 3573        } elseif (!is_array($operand2)) {
 
 3575            $operand2 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand2));
 
 3581        if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
 
 3588        } elseif ($resize == 1) {
 
 3593        return [$matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns];
 
 3607        foreach (
$matrix as $rowKey => $rowValue) {
 
 3608            if (!is_array($rowValue)) {
 
 3609                $matrix[$rowKey] = [$rowValue];
 
 3610                $matrixColumns = max(1, $matrixColumns);
 
 3612                $matrix[$rowKey] = array_values($rowValue);
 
 3613                $matrixColumns = max(count($rowValue), $matrixColumns);
 
 3618        return [$matrixRows, $matrixColumns];
 
 3631    private static function resizeMatricesShrink(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns): void
 
 3633        if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
 
 3634            if ($matrix2Rows < $matrix1Rows) {
 
 3635                for (
$i = $matrix2Rows; 
$i < $matrix1Rows; ++
$i) {
 
 3636                    unset($matrix1[
$i]);
 
 3639            if ($matrix2Columns < $matrix1Columns) {
 
 3640                for (
$i = 0; 
$i < $matrix1Rows; ++
$i) {
 
 3641                    for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
 
 3642                        unset($matrix1[
$i][$j]);
 
 3648        if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
 
 3649            if ($matrix1Rows < $matrix2Rows) {
 
 3650                for (
$i = $matrix1Rows; 
$i < $matrix2Rows; ++
$i) {
 
 3651                    unset($matrix2[
$i]);
 
 3654            if ($matrix1Columns < $matrix2Columns) {
 
 3655                for (
$i = 0; 
$i < $matrix2Rows; ++
$i) {
 
 3656                    for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
 
 3657                        unset($matrix2[
$i][$j]);
 
 3674    private static function resizeMatricesExtend(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns): void
 
 3676        if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
 
 3677            if ($matrix2Columns < $matrix1Columns) {
 
 3678                for (
$i = 0; 
$i < $matrix2Rows; ++
$i) {
 
 3679                    $x = $matrix2[
$i][$matrix2Columns - 1];
 
 3680                    for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
 
 3681                        $matrix2[
$i][$j] = 
$x;
 
 3685            if ($matrix2Rows < $matrix1Rows) {
 
 3686                $x = $matrix2[$matrix2Rows - 1];
 
 3687                for (
$i = 0; 
$i < $matrix1Rows; ++
$i) {
 
 3693        if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
 
 3694            if ($matrix1Columns < $matrix2Columns) {
 
 3695                for (
$i = 0; 
$i < $matrix1Rows; ++
$i) {
 
 3696                    $x = $matrix1[
$i][$matrix1Columns - 1];
 
 3697                    for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
 
 3698                        $matrix1[
$i][$j] = 
$x;
 
 3702            if ($matrix1Rows < $matrix2Rows) {
 
 3703                $x = $matrix1[$matrix1Rows - 1];
 
 3704                for (
$i = 0; 
$i < $matrix2Rows; ++
$i) {
 
 3720        if ($this->debugLog->getWriteDebugLog()) {
 
 3722            if (count($testArray) == 1) {
 
 3723                $value = array_pop($testArray);
 
 3726            if (is_array($value)) {
 
 3728                $pad = $rpad = 
', ';
 
 3729                foreach ($value as 
$row) {
 
 3730                    if (is_array(
$row)) {
 
 3731                        $returnMatrix[] = implode($pad, array_map([$this, 
'showValue'], 
$row));
 
 3734                        $returnMatrix[] = $this->
showValue($row);
 
 3738                return '{ ' . implode($rpad, $returnMatrix) . 
' }';
 
 3739            } elseif (is_string($value) && (trim($value, self::FORMULA_STRING_QUOTE) == $value)) {
 
 3741            } elseif (is_bool($value)) {
 
 3742                return ($value) ? self::$localeBoolean[
'TRUE'] : self::$localeBoolean[
'FALSE'];
 
 3758        if ($this->debugLog->getWriteDebugLog()) {
 
 3760            if (count($testArray) == 1) {
 
 3761                $value = array_pop($testArray);
 
 3764            if ($value === 
null) {
 
 3765                return 'a NULL value';
 
 3766            } elseif (is_float($value)) {
 
 3767                $typeString = 
'a floating point number';
 
 3768            } elseif (is_int($value)) {
 
 3769                $typeString = 
'an integer number';
 
 3770            } elseif (is_bool($value)) {
 
 3771                $typeString = 
'a boolean';
 
 3772            } elseif (is_array($value)) {
 
 3773                $typeString = 
'a matrix';
 
 3776                    return 'an empty string';
 
 3777                } elseif ($value[0] == 
'#') {
 
 3778                    return 'a ' . $value . 
' error';
 
 3780                $typeString = 
'a string';
 
 3783            return $typeString . 
' with a value of ' . $this->
showValue($value);
 
 3797        static $matrixReplaceTo = [
'MKMATRIX(MKMATRIX(', 
'),MKMATRIX(', 
'))'];
 
 3800        if (strpos($formula, self::FORMULA_OPEN_FUNCTION_BRACE) !== 
false) {
 
 3802            if (strpos($formula, self::FORMULA_STRING_QUOTE) !== 
false) {
 
 3805                $temp = explode(self::FORMULA_STRING_QUOTE, $formula);
 
 3807                $openCount = $closeCount = 0;
 
 3809                foreach ($temp as &$value) {
 
 3812                        $openCount += substr_count($value, self::FORMULA_OPEN_FUNCTION_BRACE);
 
 3813                        $closeCount += substr_count($value, self::FORMULA_CLOSE_FUNCTION_BRACE);
 
 3814                        $value = str_replace($matrixReplaceFrom, $matrixReplaceTo, $value);
 
 3819                $formula = implode(self::FORMULA_STRING_QUOTE, $temp);
 
 3822                $openCount = substr_count($formula, self::FORMULA_OPEN_FUNCTION_BRACE);
 
 3823                $closeCount = substr_count($formula, self::FORMULA_CLOSE_FUNCTION_BRACE);
 
 3824                $formula = str_replace($matrixReplaceFrom, $matrixReplaceTo, $formula);
 
 3827            if ($openCount < $closeCount) {
 
 3828                if ($openCount > 0) {
 
 3833            } elseif ($openCount > $closeCount) {
 
 3834                if ($closeCount > 0) {
 
 3854        '>' => 0, 
'<' => 0, 
'=' => 0, 
'>=' => 0, 
'<=' => 0, 
'<>' => 0, 
 
 3859    private static $comparisonOperators = [
'>' => 
true, 
'<' => 
true, 
'=' => 
true, 
'>=' => 
true, 
'<=' => 
true, 
'<>' => 
true];
 
 3873        '>' => 0, 
'<' => 0, 
'=' => 0, 
'>=' => 0, 
'<=' => 0, 
'<>' => 0, 
 
 3891        $pCellParent = ($pCell !== 
null) ? $pCell->getWorksheet() : 
null;
 
 3893        $regexpMatchString = 
'/^(' . self::CALCULATION_REGEXP_FUNCTION .
 
 3894            '|' . self::CALCULATION_REGEXP_CELLREF .
 
 3895            '|' . self::CALCULATION_REGEXP_COLUMN_RANGE .
 
 3896            '|' . self::CALCULATION_REGEXP_ROW_RANGE .
 
 3897            '|' . self::CALCULATION_REGEXP_NUMBER .
 
 3898            '|' . self::CALCULATION_REGEXP_STRING .
 
 3899            '|' . self::CALCULATION_REGEXP_OPENBRACE .
 
 3900            '|' . self::CALCULATION_REGEXP_DEFINEDNAME .
 
 3901            '|' . self::CALCULATION_REGEXP_ERROR .
 
 3906        $stack = 
new Stack();
 
 3908        $expectingOperator = 
false; 
 
 3910        $expectingOperand = 
false; 
 
 3915        $pendingStoreKey = 
null;
 
 3917        $pendingStoreKeysStack = [];
 
 3918        $expectingConditionMap = []; 
 
 3919        $expectingThenMap = []; 
 
 3920        $expectingElseMap = []; 
 
 3921        $parenthesisDepthMap = []; 
 
 3928            $currentCondition = 
null;
 
 3929            $currentOnlyIf = 
null;
 
 3930            $currentOnlyIfNot = 
null;
 
 3931            $previousStoreKey = 
null;
 
 3932            $pendingStoreKey = end($pendingStoreKeysStack);
 
 3934            if ($this->branchPruningEnabled) {
 
 3936                if (isset($expectingConditionMap[$pendingStoreKey]) && $expectingConditionMap[$pendingStoreKey]) {
 
 3937                    $currentCondition = $pendingStoreKey;
 
 3938                    $stackDepth = count($pendingStoreKeysStack);
 
 3939                    if ($stackDepth > 1) { 
 
 3940                        $previousStoreKey = $pendingStoreKeysStack[$stackDepth - 2];
 
 3943                if (isset($expectingThenMap[$pendingStoreKey]) && $expectingThenMap[$pendingStoreKey]) {
 
 3944                    $currentOnlyIf = $pendingStoreKey;
 
 3945                } elseif (isset($previousStoreKey)) {
 
 3946                    if (isset($expectingThenMap[$previousStoreKey]) && $expectingThenMap[$previousStoreKey]) {
 
 3947                        $currentOnlyIf = $previousStoreKey;
 
 3950                if (isset($expectingElseMap[$pendingStoreKey]) && $expectingElseMap[$pendingStoreKey]) {
 
 3951                    $currentOnlyIfNot = $pendingStoreKey;
 
 3952                } elseif (isset($previousStoreKey)) {
 
 3953                    if (isset($expectingElseMap[$previousStoreKey]) && $expectingElseMap[$previousStoreKey]) {
 
 3954                        $currentOnlyIfNot = $previousStoreKey;
 
 3959            $opCharacter = $formula[
$index]; 
 
 3961            if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > 
$index) && (isset(self::$comparisonOperators[$formula[
$index + 1]]))) {
 
 3962                $opCharacter .= $formula[++
$index];
 
 3965            $isOperandOrFunction = (bool) preg_match($regexpMatchString, substr($formula, 
$index), $match);
 
 3967            if ($opCharacter == 
'-' && !$expectingOperator) {                
 
 3969                $stack->push(
'Unary Operator', 
'~', 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 3971            } elseif ($opCharacter == 
'%' && $expectingOperator) {
 
 3973                $stack->push(
'Unary Operator', 
'%', 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 3975            } elseif ($opCharacter == 
'+' && !$expectingOperator) {            
 
 3977            } elseif ((($opCharacter == 
'~') || ($opCharacter == 
'|')) && (!$isOperandOrFunction)) {    
 
 3979            } elseif ((isset(self::$operators[$opCharacter]) || $isOperandOrFunction) && $expectingOperator) {    
 
 3981                    $stack->count() > 0 &&
 
 3982                    ($o2 = $stack->last()) &&
 
 3983                    isset(self::$operators[$o2[
'value']]) &&
 
 3984                    @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2[
'value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2[
'value']])
 
 3990                $stack->push(
'Binary Operator', $opCharacter, 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 3993                $expectingOperator = 
false;
 
 3994            } elseif ($opCharacter == 
')' && $expectingOperator) {            
 
 3995                $expectingOperand = 
false;
 
 3996                while (($o2 = $stack->pop()) && $o2[
'value'] != 
'(') {        
 
 4002                $d = $stack->last(2);
 
 4006                if (!empty($pendingStoreKey)) {
 
 4007                    --$parenthesisDepthMap[$pendingStoreKey];
 
 4010                if (is_array(
$d) && preg_match(
'/^' . self::CALCULATION_REGEXP_FUNCTION . 
'$/miu', 
$d[
'value'], $matches)) {    
 
 4011                    if (!empty($pendingStoreKey) && $parenthesisDepthMap[$pendingStoreKey] == -1) {
 
 4013                        if (
$d[
'value'] != 
'IF(') {
 
 4016                        if ($expectingConditionMap[$pendingStoreKey]) {
 
 4019                        $expectingThenMap[$pendingStoreKey] = 
false;
 
 4020                        $expectingElseMap[$pendingStoreKey] = 
false;
 
 4021                        --$parenthesisDepthMap[$pendingStoreKey];
 
 4022                        array_pop($pendingStoreKeysStack);
 
 4023                        unset($pendingStoreKey);
 
 4026                    $functionName = $matches[1]; 
 
 4028                    $argumentCount = 
$d[
'value']; 
 
 4031                    if (isset(self::$controlFunctions[$functionName])) {
 
 4032                        $expectedArgumentCount = self::$controlFunctions[$functionName][
'argumentCount'];
 
 4033                        $functionCall = self::$controlFunctions[$functionName][
'functionCall'];
 
 4034                    } elseif (isset(self::$phpSpreadsheetFunctions[$functionName])) {
 
 4035                        $expectedArgumentCount = self::$phpSpreadsheetFunctions[$functionName][
'argumentCount'];
 
 4036                        $functionCall = self::$phpSpreadsheetFunctions[$functionName][
'functionCall'];
 
 4038                        return $this->
raiseFormulaError(
'Formula Error: Internal error, non-function on stack');
 
 4041                    $argumentCountError = 
false;
 
 4042                    $expectedArgumentCountString = 
null;
 
 4043                    if (is_numeric($expectedArgumentCount)) {
 
 4044                        if ($expectedArgumentCount < 0) {
 
 4045                            if ($argumentCount > abs($expectedArgumentCount)) {
 
 4046                                $argumentCountError = 
true;
 
 4047                                $expectedArgumentCountString = 
'no more than ' . abs($expectedArgumentCount);
 
 4050                            if ($argumentCount != $expectedArgumentCount) {
 
 4051                                $argumentCountError = 
true;
 
 4052                                $expectedArgumentCountString = $expectedArgumentCount;
 
 4055                    } elseif ($expectedArgumentCount != 
'*') {
 
 4056                        $isOperandOrFunction = preg_match(
'/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch);
 
 4057                        switch ($argMatch[2]) {
 
 4059                                if ($argumentCount < $argMatch[1]) {
 
 4060                                    $argumentCountError = 
true;
 
 4061                                    $expectedArgumentCountString = $argMatch[1] . 
' or more ';
 
 4066                                if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
 
 4067                                    $argumentCountError = 
true;
 
 4068                                    $expectedArgumentCountString = 
'between ' . $argMatch[1] . 
' and ' . $argMatch[3];
 
 4073                                if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
 
 4074                                    $argumentCountError = 
true;
 
 4075                                    $expectedArgumentCountString = 
'either ' . $argMatch[1] . 
' or ' . $argMatch[3];
 
 4081                    if ($argumentCountError) {
 
 4082                        return $this->
raiseFormulaError(
"Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, " . $expectedArgumentCountString . 
' expected');
 
 4086            } elseif ($opCharacter == 
',') {            
 
 4088                    !empty($pendingStoreKey) &&
 
 4089                    $parenthesisDepthMap[$pendingStoreKey] == 0
 
 4092                    if ($expectingConditionMap[$pendingStoreKey]) {
 
 4093                        $expectingConditionMap[$pendingStoreKey] = 
false;
 
 4094                        $expectingThenMap[$pendingStoreKey] = 
true;
 
 4095                    } elseif ($expectingThenMap[$pendingStoreKey]) {
 
 4096                        $expectingThenMap[$pendingStoreKey] = 
false;
 
 4097                        $expectingElseMap[$pendingStoreKey] = 
true;
 
 4098                    } elseif ($expectingElseMap[$pendingStoreKey]) {
 
 4102                while (($o2 = $stack->pop()) && $o2[
'value'] != 
'(') {        
 
 4110                if (($expectingOperand) || (!$expectingOperator)) {
 
 4111                    $output[] = [
'type' => 
'NULL Value', 
'value' => self::$excelConstants[
'NULL'], 
'reference' => 
null];
 
 4114                $d = $stack->last(2);
 
 4115                if (!preg_match(
'/^' . self::CALCULATION_REGEXP_FUNCTION . 
'$/miu', 
$d[
'value'], $matches)) {
 
 4119                $itemStoreKey = 
$d[
'storeKey'] ?? 
null;
 
 4120                $itemOnlyIf = 
$d[
'onlyIf'] ?? 
null;
 
 4121                $itemOnlyIfNot = 
$d[
'onlyIfNot'] ?? 
null;
 
 4122                $stack->push(
$d[
'type'], ++
$d[
'value'], 
$d[
'reference'], $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); 
 
 4123                $stack->push(
'Brace', 
'(', 
null, $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); 
 
 4124                $expectingOperator = 
false;
 
 4125                $expectingOperand = 
true;
 
 4127            } elseif ($opCharacter == 
'(' && !$expectingOperator) {
 
 4128                if (!empty($pendingStoreKey)) { 
 
 4129                    ++$parenthesisDepthMap[$pendingStoreKey];
 
 4131                $stack->push(
'Brace', 
'(', 
null, $currentCondition, $currentOnlyIf, $currentOnlyIf);
 
 4133            } elseif ($isOperandOrFunction && !$expectingOperator) {    
 
 4134                $expectingOperator = 
true;
 
 4135                $expectingOperand = 
false;
 
 4137                $length = strlen($val);
 
 4139                if (preg_match(
'/^' . self::CALCULATION_REGEXP_FUNCTION . 
'$/miu', $val, $matches)) {
 
 4140                    $val = preg_replace(
'/\s/u', 
'', $val);
 
 4141                    if (isset(self::$phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) {    
 
 4142                        $valToUpper = strtoupper($val);
 
 4144                        $valToUpper = 
'NAME.ERROR(';
 
 4148                    if ($this->branchPruningEnabled && ($valToUpper == 
'IF(')) { 
 
 4150                        $pendingStoreKeysStack[] = $pendingStoreKey;
 
 4151                        $expectingConditionMap[$pendingStoreKey] = 
true;
 
 4152                        $parenthesisDepthMap[$pendingStoreKey] = 0;
 
 4154                        if (!empty($pendingStoreKey) && array_key_exists($pendingStoreKey, $parenthesisDepthMap)) {
 
 4155                            ++$parenthesisDepthMap[$pendingStoreKey];
 
 4159                    $stack->push(
'Function', $valToUpper, 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 4161                    $ax = preg_match(
'/^\s*\)/u', substr($formula, 
$index + $length));
 
 4163                        $stack->push(
'Operand Count for Function ' . $valToUpper . 
')', 0, 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 4164                        $expectingOperator = 
true;
 
 4166                        $stack->push(
'Operand Count for Function ' . $valToUpper . 
')', 1, 
null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 4167                        $expectingOperator = 
false;
 
 4169                    $stack->push(
'Brace', 
'(');
 
 4170                } elseif (preg_match(
'/^' . self::CALCULATION_REGEXP_CELLREF . 
'$/i', $val, $matches)) {
 
 4174                    $testPrevOp = $stack->last(1);
 
 4175                    if ($testPrevOp !== 
null && $testPrevOp[
'value'] === 
':') {
 
 4177                        if ($matches[2] == 
'') {
 
 4181                            preg_match(
'/^' . self::CALCULATION_REGEXP_CELLREF . 
'$/i', $rangeStartCellRef, $rangeStartMatches);
 
 4182                            if ($rangeStartMatches[2] > 
'') {
 
 4183                                $val = $rangeStartMatches[2] . 
'!' . $val;
 
 4187                            preg_match(
'/^' . self::CALCULATION_REGEXP_CELLREF . 
'$/i', $rangeStartCellRef, $rangeStartMatches);
 
 4188                            if ($rangeStartMatches[2] !== $matches[2]) {
 
 4192                    } elseif (strpos($val, 
'!') === 
false && $pCellParent !== 
null) {
 
 4193                        $worksheet = $pCellParent->getTitle();
 
 4194                        $val = 
"'{$worksheet}'!{$val}";
 
 4197                    $outputItem = $stack->getStackItem(
'Cell Reference', $val, $val, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 4201                    $localeConstant = 
false;
 
 4202                    $stackItemType = 
'Value';
 
 4203                    $stackItemReference = 
null;
 
 4206                    $testPrevOp = $stack->last(1);
 
 4207                    if ($testPrevOp !== 
null && $testPrevOp[
'value'] === 
':') {
 
 4208                        $stackItemType = 
'Cell Reference';
 
 4210                        [$rangeWS1, $startRowColRef] = Worksheet::extractSheetTitle($startRowColRef, 
true);
 
 4211                        $rangeSheetRef = $rangeWS1;
 
 4212                        if ($rangeWS1 !== 
'') {
 
 4215                        $rangeSheetRef = trim($rangeSheetRef, 
"'");
 
 4216                        [$rangeWS2, $val] = Worksheet::extractSheetTitle($val, 
true);
 
 4217                        if ($rangeWS2 !== 
'') {
 
 4220                            $rangeWS2 = $rangeWS1;
 
 4223                        $refSheet = $pCellParent;
 
 4224                        if ($pCellParent !== 
null && $rangeSheetRef !== 
'' && $rangeSheetRef !== $pCellParent->getTitle()) {
 
 4225                            $refSheet = $pCellParent->getParent()->getSheetByName($rangeSheetRef);
 
 4228                        if (ctype_digit($val) && $val <= 1048576) {
 
 4230                            $stackItemType = 
'Row Reference';
 
 4231                            $endRowColRef = ($refSheet !== 
null) ? $refSheet->getHighestDataColumn($val) : 
'XFD'; 
 
 4232                            $val = 
"{$rangeWS2}{$endRowColRef}{$val}";
 
 4233                        } elseif (ctype_alpha($val) && strlen($val) <= 3) {
 
 4235                            $stackItemType = 
'Column Reference';
 
 4236                            $endRowColRef = ($refSheet !== 
null) ? $refSheet->getHighestDataRow($val) : 1048576; 
 
 4237                            $val = 
"{$rangeWS2}{$val}{$endRowColRef}";
 
 4239                        $stackItemReference = $val;
 
 4240                    } elseif ($opCharacter == self::FORMULA_STRING_QUOTE) {
 
 4242                        $val = 
self::wrapResult(str_replace(
'""', self::FORMULA_STRING_QUOTE, self::unwrapResult($val)));
 
 4243                    } elseif (isset(self::$excelConstants[trim(strtoupper($val))])) {
 
 4244                        $stackItemType = 
'Constant';
 
 4245                        $excelConstant = trim(strtoupper($val));
 
 4246                        $val = self::$excelConstants[$excelConstant];
 
 4247                    } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== 
false) {
 
 4248                        $stackItemType = 
'Constant';
 
 4249                        $val = self::$excelConstants[$localeConstant];
 
 4251                        preg_match(
'/^' . self::CALCULATION_REGEXP_ROW_RANGE . 
'/miu', substr($formula, 
$index), $rowRangeReference)
 
 4253                        $val = $rowRangeReference[1];
 
 4254                        $length = strlen($rowRangeReference[1]);
 
 4255                        $stackItemType = 
'Row Reference';
 
 4257                        if (($testPrevOp !== 
null && $testPrevOp[
'value'] === 
':') && $pCellParent !== 
null) {
 
 4258                            $column = $pCellParent->getHighestDataColumn($val);
 
 4260                        $val = 
"{$rowRangeReference[2]}{$column}{$rowRangeReference[7]}";
 
 4261                        $stackItemReference = $val;
 
 4263                        preg_match(
'/^' . self::CALCULATION_REGEXP_COLUMN_RANGE . 
'/miu', substr($formula, 
$index), $columnRangeReference)
 
 4265                        $val = $columnRangeReference[1];
 
 4266                        $length = strlen($val);
 
 4267                        $stackItemType = 
'Column Reference';
 
 4269                        if (($testPrevOp !== 
null && $testPrevOp[
'value'] === 
':') && $pCellParent !== 
null) {
 
 4270                            $row = $pCellParent->getHighestDataRow($val);
 
 4272                        $val = 
"{$val}{$row}";
 
 4273                        $stackItemReference = $val;
 
 4274                    } elseif (preg_match(
'/^' . self::CALCULATION_REGEXP_DEFINEDNAME . 
'.*/miu', $val, $match)) {
 
 4275                        $stackItemType = 
'Defined Name';
 
 4276                        $stackItemReference = $val;
 
 4277                    } elseif (is_numeric($val)) {
 
 4278                        if ((strpos($val, 
'.') !== 
false) || (stripos($val, 
'e') !== 
false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
 
 4279                            $val = (float) $val;
 
 4285                    $details = $stack->getStackItem($stackItemType, $val, $stackItemReference, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
 
 4286                    if ($localeConstant) {
 
 4287                        $details[
'localeValue'] = $localeConstant;
 
 4292            } elseif ($opCharacter == 
'$') {    
 
 4294            } elseif ($opCharacter == 
')') {    
 
 4295                if ($expectingOperand) {
 
 4296                    $output[] = [
'type' => 
'NULL Value', 
'value' => self::$excelConstants[
'NULL'], 
'reference' => 
null];
 
 4297                    $expectingOperand = 
false;
 
 4298                    $expectingOperator = 
true;
 
 4302            } elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
 
 4303                return $this->
raiseFormulaError(
"Formula Error: Unexpected operator '$opCharacter'");
 
 4308            if (
$index == strlen($formula)) {
 
 4311                if ((isset(self::$operators[$opCharacter])) && ($opCharacter != 
'%')) {
 
 4312                    return $this->
raiseFormulaError(
"Formula Error: Operator '$opCharacter' has no operands");
 
 4318            while (($formula[
$index] == 
"\n") || ($formula[
$index] == 
"\r")) {
 
 4322            if ($formula[
$index] == 
' ') {
 
 4323                while ($formula[
$index] == 
' ') {
 
 4330                    ($expectingOperator) &&
 
 4331                    ((preg_match(
'/^' . self::CALCULATION_REGEXP_CELLREF . 
'.*/Ui', substr($formula, 
$index), $match)) &&
 
 4333                        (preg_match(
'/^' . self::CALCULATION_REGEXP_DEFINEDNAME . 
'.*/miu', substr($formula, 
$index), $match)) &&
 
 4338                        $stack->count() > 0 &&
 
 4339                        ($o2 = $stack->last()) &&
 
 4340                        isset(self::$operators[$o2[
'value']]) &&
 
 4341                        @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2[
'value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2[
'value']])
 
 4345                    $stack->push(
'Binary Operator', 
'|'); 
 
 4346                    $expectingOperator = 
false;
 
 4351        while (($op = $stack->pop()) !== 
null) {    
 
 4352            if ((is_array($op) && $op[
'value'] == 
'(') || ($op === 
'(')) {
 
 4363        $operand = $operandData[
'value'];
 
 4364        if (($operandData[
'reference'] === 
null) && (is_array($operand))) {
 
 4365            $rKeys = array_keys($operand);
 
 4366            $rowKey = array_shift($rKeys);
 
 4367            $cKeys = array_keys(array_keys($operand[$rowKey]));
 
 4368            $colKey = array_shift($cKeys);
 
 4369            if (ctype_upper($colKey)) {
 
 4370                $operandData[
'reference'] = $colKey . $rowKey;
 
 4387        if ($tokens == 
false) {
 
 4393        $pCellWorksheet = ($pCell !== 
null) ? $pCell->getWorksheet() : 
null;
 
 4394        $pCellParent = ($pCell !== 
null) ? $pCell->getParent() : 
null;
 
 4395        $stack = 
new Stack();
 
 4398        $fakedForBranchPruning = [];
 
 4402        foreach ($tokens as $tokenData) {
 
 4403            $token = $tokenData[
'value'];
 
 4406            $storeKey = $tokenData[
'storeKey'] ?? 
null;
 
 4407            if ($this->branchPruningEnabled && isset($tokenData[
'onlyIf'])) {
 
 4408                $onlyIfStoreKey = $tokenData[
'onlyIf'];
 
 4409                $storeValue = $branchStore[$onlyIfStoreKey] ?? 
null;
 
 4410                $storeValueAsBool = ($storeValue === 
null) ?
 
 4412                if (is_array($storeValue)) {
 
 4413                    $wrappedItem = end($storeValue);
 
 4414                    $storeValue = end($wrappedItem);
 
 4422                        || ($storeValue === 
'Pruned branch')
 
 4426                    if (!isset($fakedForBranchPruning[
'onlyIf-' . $onlyIfStoreKey])) {
 
 4427                        $stack->push(
'Value', 
'Pruned branch (only if ' . $onlyIfStoreKey . 
') ' . 
$token);
 
 4428                        $fakedForBranchPruning[
'onlyIf-' . $onlyIfStoreKey] = 
true;
 
 4431                    if (isset($storeKey)) {
 
 4434                        $branchStore[$storeKey] = 
'Pruned branch';
 
 4435                        $fakedForBranchPruning[
'onlyIfNot-' . $storeKey] = 
true;
 
 4436                        $fakedForBranchPruning[
'onlyIf-' . $storeKey] = 
true;
 
 4443            if ($this->branchPruningEnabled && isset($tokenData[
'onlyIfNot'])) {
 
 4444                $onlyIfNotStoreKey = $tokenData[
'onlyIfNot'];
 
 4445                $storeValue = $branchStore[$onlyIfNotStoreKey] ?? 
null;
 
 4446                $storeValueAsBool = ($storeValue === 
null) ?
 
 4448                if (is_array($storeValue)) {
 
 4449                    $wrappedItem = end($storeValue);
 
 4450                    $storeValue = end($wrappedItem);
 
 4457                        || ($storeValue === 
'Pruned branch'))
 
 4460                    if (!isset($fakedForBranchPruning[
'onlyIfNot-' . $onlyIfNotStoreKey])) {
 
 4461                        $stack->push(
'Value', 
'Pruned branch (only if not ' . $onlyIfNotStoreKey . 
') ' . 
$token);
 
 4462                        $fakedForBranchPruning[
'onlyIfNot-' . $onlyIfNotStoreKey] = 
true;
 
 4465                    if (isset($storeKey)) {
 
 4468                        $branchStore[$storeKey] = 
'Pruned branch';
 
 4469                        $fakedForBranchPruning[
'onlyIfNot-' . $storeKey] = 
true;
 
 4470                        $fakedForBranchPruning[
'onlyIf-' . $storeKey] = 
true;
 
 4478            if (isset(self::$binaryOperators[
$token])) {
 
 4480                if (($operand2Data = $stack->pop()) === 
null) {
 
 4481                    return $this->
raiseFormulaError(
'Internal error - Operand value missing from stack');
 
 4483                if (($operand1Data = $stack->pop()) === 
null) {
 
 4484                    return $this->
raiseFormulaError(
'Internal error - Operand value missing from stack');
 
 4492                    $this->debugLog->writeDebugLog(
'Evaluating Range ', $this->
showValue($operand1Data[
'reference']), 
' ', 
$token, 
' ', $this->
showValue($operand2Data[
'reference']));
 
 4494                    $this->debugLog->writeDebugLog(
'Evaluating ', $this->
showValue($operand1), 
' ', 
$token, 
' ', $this->
showValue($operand2));
 
 4507                        if (isset($storeKey)) {
 
 4508                            $branchStore[$storeKey] = 
$result;
 
 4514                        if (strpos($operand1Data[
'reference'], 
'!') !== 
false) {
 
 4515                            [$sheet1, $operand1Data[
'reference']] = Worksheet::extractSheetTitle($operand1Data[
'reference'], 
true);
 
 4517                            $sheet1 = ($pCellParent !== 
null) ? $pCellWorksheet->getTitle() : 
'';
 
 4520                        [$sheet2, $operand2Data[
'reference']] = Worksheet::extractSheetTitle($operand2Data[
'reference'], 
true);
 
 4521                        if (empty($sheet2)) {
 
 4525                        if ($sheet1 == $sheet2) {
 
 4526                            if ($operand1Data[
'reference'] === 
null) {
 
 4527                                if ((trim($operand1Data[
'value']) != 
'') && (is_numeric($operand1Data[
'value']))) {
 
 4528                                    $operand1Data[
'reference'] = $pCell->getColumn() . $operand1Data[
'value'];
 
 4529                                } elseif (trim($operand1Data[
'reference']) == 
'') {
 
 4530                                    $operand1Data[
'reference'] = $pCell->getCoordinate();
 
 4532                                    $operand1Data[
'reference'] = $operand1Data[
'value'] . $pCell->getRow();
 
 4535                            if ($operand2Data[
'reference'] === 
null) {
 
 4536                                if ((trim($operand2Data[
'value']) != 
'') && (is_numeric($operand2Data[
'value']))) {
 
 4537                                    $operand2Data[
'reference'] = $pCell->getColumn() . $operand2Data[
'value'];
 
 4538                                } elseif (trim($operand2Data[
'reference']) == 
'') {
 
 4539                                    $operand2Data[
'reference'] = $pCell->getCoordinate();
 
 4541                                    $operand2Data[
'reference'] = $operand2Data[
'value'] . $pCell->getRow();
 
 4545                            $oData = array_merge(explode(
':', $operand1Data[
'reference']), explode(
':', $operand2Data[
'reference']));
 
 4547                            foreach ($oData as $oDatum) {
 
 4553                            if ($pCellParent !== 
null) {
 
 4554                                $cellValue = $this->
extractCellRange($cellRef, $this->spreadsheet->getSheetByName($sheet1), 
false);
 
 4559                            $stack->push(
'Cell Reference', $cellValue, $cellRef);
 
 4567                        if (isset($storeKey)) {
 
 4568                            $branchStore[$storeKey] = 
$result;
 
 4574                        if (isset($storeKey)) {
 
 4575                            $branchStore[$storeKey] = 
$result;
 
 4581                        if (isset($storeKey)) {
 
 4582                            $branchStore[$storeKey] = 
$result;
 
 4588                        if (isset($storeKey)) {
 
 4589                            $branchStore[$storeKey] = 
$result;
 
 4595                        if (isset($storeKey)) {
 
 4596                            $branchStore[$storeKey] = 
$result;
 
 4604                        if (is_bool($operand1)) {
 
 4605                            $operand1 = ($operand1) ? self::$localeBoolean[
'TRUE'] : self::$localeBoolean[
'FALSE'];
 
 4607                        if (is_bool($operand2)) {
 
 4608                            $operand2 = ($operand2) ? self::$localeBoolean[
'TRUE'] : self::$localeBoolean[
'FALSE'];
 
 4610                        if ((is_array($operand1)) || (is_array($operand2))) {
 
 4618                                $matrixResult = 
$matrix->concat($operand2);
 
 4619                                $result = $matrixResult->getArray();
 
 4621                                $this->debugLog->writeDebugLog(
'JAMA Matrix Exception: ', $ex->getMessage());
 
 4625                            $result = self::FORMULA_STRING_QUOTE . str_replace(
'""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)) . 
self::FORMULA_STRING_QUOTE;
 
 4628                        $stack->push(
'Value', 
$result);
 
 4630                        if (isset($storeKey)) {
 
 4631                            $branchStore[$storeKey] = 
$result;
 
 4636                        $rowIntersect = array_intersect_key($operand1, $operand2);
 
 4637                        $cellIntersect = $oCol = $oRow = [];
 
 4638                        foreach (array_keys($rowIntersect) as 
$row) {
 
 4640                            foreach ($rowIntersect[
$row] as $col => 
$data) {
 
 4642                                $cellIntersect[
$row] = array_intersect_key($operand1[
$row], $operand2[
$row]);
 
 4646                            $this->debugLog->writeDebugLog(
'Evaluation Result is ', $this->
showTypeDetails($cellIntersect));
 
 4651                            $this->debugLog->writeDebugLog(
'Evaluation Result is ', $this->
showTypeDetails($cellIntersect));
 
 4652                            $stack->push(
'Value', $cellIntersect, $cellRef);
 
 4660                if (($arg = $stack->pop()) === 
null) {
 
 4661                    return $this->
raiseFormulaError(
'Internal error - Operand value missing from stack');
 
 4663                $arg = $arg[
'value'];
 
 4665                    $this->debugLog->writeDebugLog(
'Evaluating Negation of ', $this->
showValue($arg));
 
 4668                    $this->debugLog->writeDebugLog(
'Evaluating Percentile of ', $this->
showValue($arg));
 
 4671                if (is_array($arg)) {
 
 4676                        $matrixResult = $matrix1->arrayTimesEquals($multiplier);
 
 4677                        $result = $matrixResult->getArray();
 
 4679                        $this->debugLog->writeDebugLog(
'JAMA Matrix Exception: ', $ex->getMessage());
 
 4683                    $stack->push(
'Value', 
$result);
 
 4684                    if (isset($storeKey)) {
 
 4685                        $branchStore[$storeKey] = 
$result;
 
 4690            } elseif (preg_match(
'/^' . self::CALCULATION_REGEXP_CELLREF . 
'$/i', 
$token ?? 
'', $matches)) {
 
 4693                if (isset($matches[8])) {
 
 4694                    if ($pCell === 
null) {
 
 4698                        $cellRef = $matches[6] . $matches[7] . 
':' . $matches[9] . $matches[10];
 
 4699                        if ($matches[2] > 
'') {
 
 4700                            $matches[2] = trim($matches[2], 
"\"'");
 
 4701                            if ((strpos($matches[2], 
'[') !== 
false) || (strpos($matches[2], 
']') !== 
false)) {
 
 4705                            $matches[2] = trim($matches[2], 
"\"'");
 
 4706                            $this->debugLog->writeDebugLog(
'Evaluating Cell Range ', $cellRef, 
' in worksheet ', $matches[2]);
 
 4707                            if ($pCellParent !== 
null) {
 
 4708                                $cellValue = $this->
extractCellRange($cellRef, $this->spreadsheet->getSheetByName($matches[2]), 
false);
 
 4712                            $this->debugLog->writeDebugLog(
'Evaluation Result for cells ', $cellRef, 
' in worksheet ', $matches[2], 
' is ', $this->
showTypeDetails($cellValue));
 
 4714                            $this->debugLog->writeDebugLog(
'Evaluating Cell Range ', $cellRef, 
' in current worksheet');
 
 4715                            if ($pCellParent !== 
null) {
 
 4720                            $this->debugLog->writeDebugLog(
'Evaluation Result for cells ', $cellRef, 
' is ', $this->
showTypeDetails($cellValue));
 
 4724                    if ($pCell === 
null) {
 
 4728                        $cellRef = $matches[6] . $matches[7];
 
 4729                        if ($matches[2] > 
'') {
 
 4730                            $matches[2] = trim($matches[2], 
"\"'");
 
 4731                            if ((strpos($matches[2], 
'[') !== 
false) || (strpos($matches[2], 
']') !== 
false)) {
 
 4735                            $this->debugLog->writeDebugLog(
'Evaluating Cell ', $cellRef, 
' in worksheet ', $matches[2]);
 
 4736                            if ($pCellParent !== 
null) {
 
 4737                                $cellSheet = $this->spreadsheet->getSheetByName($matches[2]);
 
 4738                                if ($cellSheet && $cellSheet->cellExists($cellRef)) {
 
 4739                                    $cellValue = $this->
extractCellRange($cellRef, $this->spreadsheet->getSheetByName($matches[2]), 
false);
 
 4740                                    $pCell->attach($pCellParent);
 
 4742                                    $cellRef = ($cellSheet !== 
null) ? 
"{$matches[2]}!{$cellRef}" : $cellRef;
 
 4748                            $this->debugLog->writeDebugLog(
'Evaluation Result for cell ', $cellRef, 
' in worksheet ', $matches[2], 
' is ', $this->
showTypeDetails($cellValue));
 
 4750                            $this->debugLog->writeDebugLog(
'Evaluating Cell ', $cellRef, 
' in current worksheet');
 
 4751                            if ($pCellParent->has($cellRef)) {
 
 4753                                $pCell->attach($pCellParent);
 
 4757                            $this->debugLog->writeDebugLog(
'Evaluation Result for cell ', $cellRef, 
' is ', $this->
showTypeDetails($cellValue));
 
 4762                $stack->push(
'Cell Value', $cellValue, $cellRef);
 
 4763                if (isset($storeKey)) {
 
 4764                    $branchStore[$storeKey] = $cellValue;
 
 4768            } elseif (preg_match(
'/^' . self::CALCULATION_REGEXP_FUNCTION . 
'$/miu', 
$token ?? 
'', $matches)) {
 
 4770                    $pCell->attach($pCellParent);
 
 4773                $functionName = $matches[1];
 
 4774                $argCount = $stack->pop();
 
 4775                $argCount = $argCount[
'value'];
 
 4776                if ($functionName != 
'MKMATRIX') {
 
 4777                    $this->debugLog->writeDebugLog(
'Evaluating Function ', self::localeFunc($functionName), 
'() with ', (($argCount == 0) ? 
'no' : $argCount), 
' argument', (($argCount == 1) ? 
'' : 
's'));
 
 4779                if ((isset(self::$phpSpreadsheetFunctions[$functionName])) || (isset(self::$controlFunctions[$functionName]))) {    
 
 4780                    $passByReference = 
false;
 
 4781                    $passCellReference = 
false;
 
 4782                    $functionCall = 
null;
 
 4783                    if (isset(self::$phpSpreadsheetFunctions[$functionName])) {
 
 4784                        $functionCall = self::$phpSpreadsheetFunctions[$functionName][
'functionCall'];
 
 4785                        $passByReference = isset(self::$phpSpreadsheetFunctions[$functionName][
'passByReference']);
 
 4786                        $passCellReference = isset(self::$phpSpreadsheetFunctions[$functionName][
'passCellReference']);
 
 4787                    } elseif (isset(self::$controlFunctions[$functionName])) {
 
 4788                        $functionCall = self::$controlFunctions[$functionName][
'functionCall'];
 
 4789                        $passByReference = isset(self::$controlFunctions[$functionName][
'passByReference']);
 
 4790                        $passCellReference = isset(self::$controlFunctions[$functionName][
'passCellReference']);
 
 4793                    $args = $argArrayVals = [];
 
 4794                    for (
$i = 0; 
$i < $argCount; ++
$i) {
 
 4795                        $arg = $stack->pop();
 
 4796                        $a = $argCount - 
$i - 1;
 
 4798                            ($passByReference) &&
 
 4799                            (isset(self::$phpSpreadsheetFunctions[$functionName][
'passByReference'][$a])) &&
 
 4800                            (self::$phpSpreadsheetFunctions[$functionName][
'passByReference'][$a])
 
 4802                            if ($arg[
'reference'] === 
null) {
 
 4804                                if ($functionName != 
'MKMATRIX') {
 
 4805                                    $argArrayVals[] = $this->
showValue($cellID);
 
 4808                                $args[] = $arg[
'reference'];
 
 4809                                if ($functionName != 
'MKMATRIX') {
 
 4810                                    $argArrayVals[] = $this->
showValue($arg[
'reference']);
 
 4815                            if ($functionName != 
'MKMATRIX') {
 
 4816                                $argArrayVals[] = $this->
showValue($arg[
'value']);
 
 4824                    if (($passByReference) && ($argCount == 0)) {
 
 4826                        $argArrayVals[] = $this->
showValue($cellID);
 
 4829                    if ($functionName != 
'MKMATRIX') {
 
 4830                        if ($this->debugLog->getWriteDebugLog()) {
 
 4831                            krsort($argArrayVals);
 
 4832                            $this->debugLog->writeDebugLog(
'Evaluating ', self::localeFunc($functionName), 
'( ', implode(self::$localeArgumentSeparator . 
' ', 
Functions::flattenArray($argArrayVals)), 
' )');
 
 4837                    $args = $this->
addCellReference($args, $passCellReference, $functionCall, $pCell);
 
 4839                    if (!is_array($functionCall)) {
 
 4840                        foreach ($args as &$arg) {
 
 4846                    $result = call_user_func_array($functionCall, $args);
 
 4848                    if ($functionName != 
'MKMATRIX') {
 
 4849                        $this->debugLog->writeDebugLog(
'Evaluation Result for ', self::localeFunc($functionName), 
'() function call is ', $this->
showTypeDetails(
$result));
 
 4851                    $stack->push(
'Value', self::wrapResult(
$result));
 
 4852                    if (isset($storeKey)) {
 
 4853                        $branchStore[$storeKey] = 
$result;
 
 4858                if (isset(self::$excelConstants[strtoupper(
$token ?? 
'')])) {
 
 4859                    $excelConstant = strtoupper(
$token);
 
 4860                    $stack->push(
'Constant Value', self::$excelConstants[$excelConstant]);
 
 4861                    if (isset($storeKey)) {
 
 4862                        $branchStore[$storeKey] = self::$excelConstants[$excelConstant];
 
 4864                    $this->debugLog->writeDebugLog(
'Evaluating Constant ', $excelConstant, 
' as ', $this->
showTypeDetails(self::$excelConstants[$excelConstant]));
 
 4866                    $stack->push(
'Value', 
$token);
 
 4867                    if (isset($storeKey)) {
 
 4868                        $branchStore[$storeKey] = 
$token;
 
 4871                } elseif (preg_match(
'/^' . self::CALCULATION_REGEXP_DEFINEDNAME . 
'$/miu', 
$token, $matches)) {
 
 4872                    $definedName = $matches[6];
 
 4873                    if ($pCell === 
null || $pCellWorksheet === 
null) {
 
 4877                    $this->debugLog->writeDebugLog(
'Evaluating Defined Name ', $definedName);
 
 4879                    if ($namedRange === 
null) {
 
 4884                    if (isset($storeKey)) {
 
 4885                        $branchStore[$storeKey] = 
$result;
 
 4893        if ($stack->count() != 1) {
 
 4904        if (is_array($operand)) {
 
 4905            if ((count($operand, COUNT_RECURSIVE) - count($operand)) == 1) {
 
 4907                    $operand = array_pop($operand);
 
 4908                } 
while (is_array($operand));
 
 4912        if (is_string($operand)) {
 
 4915            if ($operand > 
'' && $operand[0] == self::FORMULA_STRING_QUOTE) {
 
 4919            if (!is_numeric($operand)) {
 
 4921                if ($operand > 
'' && $operand[0] == 
'#') {
 
 4922                    $stack->push(
'Value', $operand);
 
 4923                    $this->debugLog->writeDebugLog(
'Evaluation Result is ', $this->
showTypeDetails($operand));
 
 4928                    $stack->push(
'Error', 
'#VALUE!');
 
 4929                    $this->debugLog->writeDebugLog(
'Evaluation Result is a ', $this->
showTypeDetails(
'#VALUE!'));
 
 4951        if (!is_array($operand2)) {
 
 4953            foreach ($operand1 as 
$x => $operandData) {
 
 4954                $this->debugLog->writeDebugLog(
'Evaluating Comparison ', $this->
showValue($operandData), 
' ', $operation, 
' ', $this->
showValue($operand2));
 
 4959        } elseif (!is_array($operand1)) {
 
 4961            foreach ($operand2 as 
$x => $operandData) {
 
 4962                $this->debugLog->writeDebugLog(
'Evaluating Comparison ', $this->
showValue($operand1), 
' ', $operation, 
' ', $this->
showValue($operandData));
 
 4969            if (!$recursingArrays) {
 
 4972            foreach ($operand1 as 
$x => $operandData) {
 
 4973                $this->debugLog->writeDebugLog(
'Evaluating Comparison ', $this->
showValue($operandData), 
' ', $operation, 
' ', $this->
showValue($operand2[
$x]));
 
 4999        if ((is_array($operand1)) || (is_array($operand2))) {
 
 5000            return $this->
executeArrayComparison($cellID, $operand1, $operand2, $operation, $stack, $recursingArrays);
 
 5004        if (is_string($operand1) && $operand1 > 
'' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
 
 5007        if (is_string($operand2) && $operand2 > 
'' && $operand2[0] == self::FORMULA_STRING_QUOTE) {
 
 5013            if (is_string($operand1)) {
 
 5016            if (is_string($operand2)) {
 
 5024        switch ($operation) {
 
 5027                if ($useLowercaseFirstComparison) {
 
 5030                    $result = ($operand1 > $operand2);
 
 5036                if ($useLowercaseFirstComparison) {
 
 5039                    $result = ($operand1 < $operand2);
 
 5045                if (is_numeric($operand1) && is_numeric($operand2)) {
 
 5054                if (is_numeric($operand1) && is_numeric($operand2)) {
 
 5056                } elseif ($useLowercaseFirstComparison) {
 
 5065                if (is_numeric($operand1) && is_numeric($operand2)) {
 
 5067                } elseif ($useLowercaseFirstComparison) {
 
 5076                if (is_numeric($operand1) && is_numeric($operand2)) {
 
 5077                    $result = (abs($operand1 - $operand2) > 1E-14);
 
 5085                throw new Exception(
'Unsupported binary comparison operation');
 
 5109        return strcmp($inversedStr1 ?? 
'', $inversedStr2 ?? 
'');
 
 5122        return strcmp($str1 ?? 
'', $str2 ?? 
'');
 
 5147        if ((is_array($operand1)) || (is_array($operand2))) {
 
 5155                $matrixResult = 
$matrix->$matrixFunction($operand2);
 
 5156                $result = $matrixResult->getArray();
 
 5158                $this->debugLog->writeDebugLog(
'JAMA Matrix Exception: ', $ex->getMessage());
 
 5164                ((is_string($operand1) && !is_numeric($operand1) && strlen($operand1) > 0) ||
 
 5165                    (is_string($operand2) && !is_numeric($operand2) && strlen($operand2) > 0))
 
 5170                switch ($operation) {
 
 5173                        $result = $operand1 + $operand2;
 
 5178                        $result = $operand1 - $operand2;
 
 5183                        $result = $operand1 * $operand2;
 
 5188                        if ($operand2 == 0) {
 
 5190                            $stack->push(
'Error', 
'#DIV/0!');
 
 5191                            $this->debugLog->writeDebugLog(
'Evaluation Result is ', $this->
showTypeDetails(
'#DIV/0!'));
 
 5195                        $result = $operand1 / $operand2;
 
 5200                        $result = $operand1 ** $operand2;
 
 5205                        throw new Exception(
'Unsupported numeric binary operation');
 
 5213        $stack->push(
'Value', 
$result);
 
 5221        $this->formulaError = $errorMessage;
 
 5222        $this->cyclicReferenceStack->clear();
 
 5223        if (!$this->suppressFormulaErrors) {
 
 5226        trigger_error($errorMessage, E_USER_ERROR);
 
 5245        if ($pSheet !== 
null) {
 
 5246            $pSheetName = $pSheet->getTitle();
 
 5248            if (strpos($pRange, 
'!') !== 
false) {
 
 5249                [$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, 
true);
 
 5250                $pSheet = $this->spreadsheet->getSheetByName($pSheetName);
 
 5255            $pRange = $pSheetName . 
'!' . $pRange;
 
 5256            if (!isset($aReferences[1])) {
 
 5260                sscanf($aReferences[0], 
'%[A-Z]%d', $currentCol, $currentRow);
 
 5261                if ($pSheet->cellExists($aReferences[0])) {
 
 5262                    $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
 
 5264                    $returnValue[$currentRow][$currentCol] = 
null;
 
 5268                foreach ($aReferences as $reference) {
 
 5272                    sscanf($reference, 
'%[A-Z]%d', $currentCol, $currentRow);
 
 5273                    if ($pSheet->cellExists($reference)) {
 
 5274                        $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
 
 5276                        $returnValue[$currentRow][$currentCol] = 
null;
 
 5282        return $returnValue;
 
 5299        if ($pSheet !== 
null) {
 
 5300            $pSheetName = $pSheet->getTitle();
 
 5301            if (strpos($pRange, 
'!') !== 
false) {
 
 5302                [$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, 
true);
 
 5303                $pSheet = $this->spreadsheet->getSheetByName($pSheetName);
 
 5308            if ($namedRange === 
null) {
 
 5312            $pSheet = $namedRange->getWorksheet();
 
 5313            $pRange = $namedRange->getValue();
 
 5316            if (ctype_alpha($splitRange[0][0])) {
 
 5317                $pRange = $splitRange[0][0] . 
'1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow();
 
 5318            } elseif (ctype_digit($splitRange[0][0])) {
 
 5319                $pRange = 
'A' . $splitRange[0][0] . 
':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1];
 
 5324            if (!isset($aReferences[1])) {
 
 5327                if ($pSheet->cellExists($aReferences[0])) {
 
 5328                    $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
 
 5330                    $returnValue[$currentRow][$currentCol] = 
null;
 
 5334                foreach ($aReferences as $reference) {
 
 5337                    if ($pSheet->cellExists($reference)) {
 
 5338                        $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
 
 5340                        $returnValue[$currentRow][$currentCol] = 
null;
 
 5346        return $returnValue;
 
 5358        $pFunction = strtoupper($pFunction);
 
 5359        $notImplemented = !isset(self::$phpSpreadsheetFunctions[$pFunction]) || (is_array(self::$phpSpreadsheetFunctions[$pFunction][
'functionCall']) && self::$phpSpreadsheetFunctions[$pFunction][
'functionCall'][1] === 
'DUMMY');
 
 5361        return !$notImplemented;
 
 5380        foreach (self::$phpSpreadsheetFunctions as $functionName => $function) {
 
 5382                $returnValue[] = $functionName;
 
 5386        return $returnValue;
 
 5399        if ($passCellReference) {
 
 5400            if (is_array($functionCall)) {
 
 5401                $className = $functionCall[0];
 
 5402                $methodName = $functionCall[1];
 
 5404                $reflectionMethod = 
new ReflectionMethod($className, $methodName);
 
 5405                $argumentCount = count($reflectionMethod->getParameters());
 
 5406                while (count($args) < $argumentCount - 1) {
 
 5422        return $storeKeyValue;
 
 5427        $tokensStr = array_map(
function (
$token) {
 
 5428            $value = 
$token[
'value'] ?? 
'no value';
 
 5429            while (is_array($value)) {
 
 5430                $value = array_pop($value);
 
 5436        return '[ ' . implode(
' | ', $tokensStr) . 
' ]';
 
 5444        $definedNameScope = $namedRange->
getScope();
 
 5445        if ($definedNameScope !== 
null && $definedNameScope !== $pCellWorksheet) {
 
 5453        $definedNameValue = $namedRange->
getValue();
 
 5454        $definedNameType = $namedRange->
isFormula() ? 
'Formula' : 
'Range';
 
 5457        if ($definedNameValue[0] !== 
'=') {
 
 5458            $definedNameValue = 
'=' . $definedNameValue;
 
 5461        $this->debugLog->writeDebugLog(
"Defined Name is a {$definedNameType} with a value of {$definedNameValue}");
 
 5463        $recursiveCalculationCell = ($definedNameWorksheet !== 
null && $definedNameWorksheet !== $pCellWorksheet)
 
 5464            ? $definedNameWorksheet->getCell(
'A1')
 
 5466        $recursiveCalculationCellAddress = $recursiveCalculationCell->
getCoordinate();
 
 5469        $definedNameValue = self::$referenceHelper->updateFormulaReferencesAnyWorksheet(
 
 5475        $this->debugLog->writeDebugLog(
"Value adjusted for relative references is {$definedNameValue}");
 
 5478        $recursiveCalculator->getDebugLog()->setWriteDebugLog($this->
getDebugLog()->getWriteDebugLog());
 
 5479        $recursiveCalculator->getDebugLog()->setEchoDebugLog($this->
getDebugLog()->getEchoDebugLog());
 
 5480        $result = $recursiveCalculator->_calculateFormulaValue($definedNameValue, $recursiveCalculationCellAddress, $recursiveCalculationCell);
 
 5483            $this->debugLog->mergeDebugLog(array_slice($recursiveCalculator->getDebugLog()->getLog(), 3));
 
 5484            $this->debugLog->writeDebugLog(
"Evaluation Result for Named {$definedNameType} {$namedRange->getName()} is {$this->showTypeDetails($result)}");
 
An exception for terminatinating execution or to throw for unit testing.
getLocale()
Get the currently defined locale code.
clearCalculationCacheForWorksheet($worksheetName)
Clear calculation cache for a specified worksheet.
executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays=false)
setBranchPruningEnabled($enabled)
Enable/disable calculation cache.
static $comparisonOperators
getUnusedBranchStoreKey()
const RETURN_ARRAY_AS_VALUE
static $functionReplaceToLocale
executeNumericBinaryOperation($operand1, $operand2, $operation, $matrixFunction, &$stack)
_translateFormulaToLocale($formula)
const FORMULA_CLOSE_FUNCTION_BRACE
getCalculationCacheEnabled()
Is calculation caching enabled?
static $phpSpreadsheetFunctions
isImplemented($pFunction)
Is a specific function implemented?
const CALCULATION_REGEXP_DEFINEDNAME
const CALCULATION_REGEXP_OPENBRACE
static translateFormula(array $from, array $to, $formula, $fromSeparator, $toSeparator)
const CALCULATION_REGEXP_FUNCTION
disableCalculationCache()
Disable calculation cache.
const CALCULATION_REGEXP_NUMBER
Constants
__clone()
__clone implementation.
const CALCULATION_REGEXP_CELLREF
const CALCULATION_REGEXP_STRING
static $functionReplaceToExcel
strcmpLowercaseFirst($str1, $str2)
Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters.
enableCalculationCache()
Enable calculation cache.
executeArrayComparison($cellID, $operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays)
saveValueToCache($cellReference, $cellValue)
evaluateDefinedName(Cell $pCell, DefinedName $namedRange, Worksheet $pCellWorksheet, Stack $stack)
static resizeMatricesExtend(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns)
Ensure that paired matrix operands are both matrices of the same size.
const CALCULATION_REGEXP_COLUMN_RANGE
strcmpAllowNull($str1, $str2)
PHP8.1 deprecates passing null to strcmp.
static setArrayReturnType($returnType)
Set the Array Return Type (Array or Value of first element in the array).
const CALCULATION_REGEXP_CELLREF_RELATIVE
static $functionReplaceFromExcel
static localeFunc($function)
getImplementedFunctionNames()
Get a list of implemented Excel function names.
clearCalculationCache()
Clear calculation cache.
const CALCULATION_REGEXP_ERROR
static dataTestReference(&$operandData)
renameCalculationCacheForWorksheet($fromWorksheetName, $toWorksheetName)
Rename calculation cache for a specified worksheet.
processTokenStack($tokens, $cellID=null, ?Cell $pCell=null)
static $functionReplaceFromLocale
const FORMULA_OPEN_FUNCTION_BRACE
addCellReference(array $args, $passCellReference, $functionCall, ?Cell $pCell=null)
Add cell reference if needed while making sure that it is the last argument.
static $validLocaleLanguages
internalParseFormula($formula, ?Cell $pCell=null)
static $returnArrayAsType
showValue($value)
Format details of an operand for display in the log (based on operand type).
raiseFormulaError($errorMessage)
const FORMULA_STRING_QUOTE
static getTRUE()
Return the locale-specific translation of TRUE.
getValueFromCache(string $cellReference, &$cellValue)
setCalculationCacheEnabled($pValue)
Enable/disable calculation cache.
static getFALSE()
Return the locale-specific translation of FALSE.
const RETURN_ARRAY_AS_ERROR
constants
const CALCULATION_REGEXP_ROW_RANGE
extractNamedRange(&$pRange='A1', ?Worksheet $pSheet=null, $resetLog=true)
Extract range values.
getTokensAsString($tokens)
static wrapResult($value)
Wrap string values in quotes.
getDebugLog()
Get the Logger for this calculation engine instance.
getLocaleFile(string $localeDir, string $locale, string $language, string $file)
calculateFormula($formula, $cellID=null, ?Cell $pCell=null)
Calculate the value of a formula.
setLocale(string $locale)
Set the locale code.
static checkMatrixOperands(&$operand1, &$operand2, $resize=1)
Ensure that paired matrix operands are both matrices and of the same size.
static $operatorPrecedence
static $localeArgumentSeparator
_calculateFormulaValue($formula, $cellID=null, ?Cell $pCell=null)
Parse a cell formula and calculate its value.
__construct(?Spreadsheet $spreadsheet=null)
static $operatorAssociativity
const RETURN_ARRAY_AS_ARRAY
static resizeMatricesShrink(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns)
Ensure that paired matrix operands are both matrices of the same size.
calculateCellValue(?Cell $pCell=null, $resetLog=true)
Calculate the value of a cell formula.
parseFormula($formula)
Validate and parse a formula string.
getFunctions()
Get a list of all implemented functions as an array of function objects.
showTypeDetails($value)
Format type and details of an operand for display in the log (based on operand type).
convertMatrixReferences($formula)
static getArrayReturnType()
Return the Array Return Type (Array or Value of first element in the array).
const CALCULATION_REGEXP_ROWRANGE_RELATIVE
flushInstance()
Flush the calculation cache for any existing instance of this class but only if a Calculation instanc...
const CALCULATION_REGEXP_COLUMNRANGE_RELATIVE
static translateSeparator($fromSeparator, $toSeparator, $formula, &$inBraces)
static getMatrixDimensions(array &$matrix)
Read the dimensions of a matrix, and re-index it with straight numeric keys starting from row 0,...
static unwrapResult($value)
Remove quotes used as a wrapper to identify string values.
_translateFormulaToEnglish($formula)
static getInstance(?Spreadsheet $spreadsheet=null)
Get an instance of this class.
calculate(?Cell $pCell=null)
Calculate cell value (using formula from a cell ID) Retained for backward compatibility.
extractCellRange(&$pRange='A1', ?Worksheet $pSheet=null, $resetLog=true)
Extract range values.
validateBinaryOperand(&$operand, &$stack)
const CATEGORY_TEXT_AND_DATA
const CATEGORY_DATE_AND_TIME
const CATEGORY_MATH_AND_TRIG
const CATEGORY_INFORMATION
const CATEGORY_LOOKUP_AND_REFERENCE
const CATEGORY_STATISTICAL
const CATEGORY_ENGINEERING
static flattenArray($array)
Convert a multi-dimensional array to a simple 1-dimensional array.
static flattenSingleValue($value='')
Convert an array to a single scalar value by extracting the first element.
static isError($value='')
IS_ERROR.
const COMPATIBILITY_OPENOFFICE
static getCompatibilityMode()
Return the current Compatibility Mode.
push( $type, $value, $reference=null, $storeKey=null, $onlyIf=null, $onlyIfNot=null)
Push a new entry onto the stack.
pop()
Pop the last entry from the stack.
getColumn()
Get cell coordinate column.
getCoordinate()
Get cell coordinate.
getRow()
Get cell coordinate row.
Helper class to manipulate cell coordinates.
static coordinateFromString($pCoordinateString)
Coordinate from string.
static columnIndexFromString($pString)
Column index from string.
static stringFromColumnIndex($columnIndex)
String from column index.
static splitRange($pRange)
Split range into coordinate strings.
static extractAllCellReferencesInRange($cellRange)
Extract all cell references in range, which may be comprised of multiple cell ranges.
static resolveName(string $pDefinedName, Worksheet $pSheet, string $sheetName='')
Resolve a named range to a regular cell range or formula.
getValue()
Get range or formula value.
isFormula()
Identify whether this is a named range or a named formula.
getWorksheet()
Get worksheet.
static getInstance()
Get an instance of this class.
static strToUpper($pValue)
Convert a UTF-8 encoded string to upper case.
static strCaseReverse($pValue)
Reverse the case of a string, so that all uppercase characters become lowercase and all lowercase cha...
static convertToNumberIfFraction(&$operand)
Identify whether a string contains a fractional numeric value, and convert it to a numeric if it is.
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d