From 726fc1399d0d1d368cce599385a200700b962455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher?= Date: Wed, 27 Nov 2024 20:07:00 +0100 Subject: [PATCH] UPDATE: Adds FORMULATEXT for Steve --- base/src/functions/information.rs | 39 +++++++++++++++++++++++++ base/src/functions/mod.rs | 8 ++++- base/src/test/mod.rs | 1 + base/src/test/test_fn_formulatext.rs | 17 +++++++++++ xlsx/tests/calc_tests/FORMULATEXT.xlsx | Bin 0 -> 10133 bytes 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 base/src/test/test_fn_formulatext.rs create mode 100644 xlsx/tests/calc_tests/FORMULATEXT.xlsx diff --git a/base/src/functions/information.rs b/base/src/functions/information.rs index 6d2aaa7..fca7280 100644 --- a/base/src/functions/information.rs +++ b/base/src/functions/information.rs @@ -293,4 +293,43 @@ impl Model { message: "Invalid name".to_string(), } } + + pub(crate) fn fn_formulatext(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 1 { + return CalcResult::new_args_number_error(cell); + } + if let CalcResult::Range { left, right } = self.evaluate_node_with_reference(&args[0], cell) + { + if left.sheet != right.sheet { + return CalcResult::Error { + error: Error::ERROR, + origin: cell, + message: "3D ranges not supported".to_string(), + }; + } + if left.row != right.row && left.column != right.column { + // FIXME: Implicit intersection or dynamic arrays + return CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "argument must be a reference to a single cell".to_string(), + }; + } + if let Ok(Some(f)) = self.get_cell_formula(left.sheet, left.row, left.column) { + CalcResult::String(f) + } else { + CalcResult::Error { + error: Error::NA, + origin: cell, + message: "Reference does not have a formula".to_string(), + } + } + } else { + CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "Argument must be a reference".to_string(), + } + } + } } diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index 6fcff67..9f3a0aa 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -75,6 +75,7 @@ pub enum Function { // Information ErrorType, + Formulatext, Isblank, Iserr, Iserror, @@ -247,7 +248,7 @@ pub enum Function { } impl Function { - pub fn into_iter() -> IntoIter { + pub fn into_iter() -> IntoIter { [ Function::And, Function::False, @@ -332,6 +333,7 @@ impl Function { Function::Isodd, Function::Iseven, Function::ErrorType, + Function::Formulatext, Function::Isformula, Function::Type, Function::Sheet, @@ -482,6 +484,7 @@ impl Function { Function::Valuetotext => "_xlfn.VALUETOTEXT".to_string(), Function::Isformula => "_xlfn.ISFORMULA".to_string(), Function::Sheet => "_xlfn.SHEET".to_string(), + Function::Formulatext => "_xlfn.FORMULATEXT".to_string(), _ => self.to_string(), } } @@ -592,6 +595,7 @@ impl Function { "ISODD" => Some(Function::Isodd), "ISEVEN" => Some(Function::Iseven), "ERROR.TYPE" => Some(Function::ErrorType), + "FORMULATEXT" | "_XLFN.FORMULATEXT" => Some(Function::Formulatext), "ISFORMULA" | "_XLFN.ISFORMULA" => Some(Function::Isformula), "TYPE" => Some(Function::Type), "SHEET" | "_XLFN.SHEET" => Some(Function::Sheet), @@ -798,6 +802,7 @@ impl fmt::Display for Function { Function::Isodd => write!(f, "ISODD"), Function::Iseven => write!(f, "ISEVEN"), Function::ErrorType => write!(f, "ERROR.TYPE"), + Function::Formulatext => write!(f, "FORMULATEXT"), Function::Isformula => write!(f, "ISFORMULA"), Function::Type => write!(f, "TYPE"), Function::Sheet => write!(f, "SHEET"), @@ -1033,6 +1038,7 @@ impl Model { Function::Isodd => self.fn_isodd(args, cell), Function::Iseven => self.fn_iseven(args, cell), Function::ErrorType => self.fn_errortype(args, cell), + Function::Formulatext => self.fn_formulatext(args, cell), Function::Isformula => self.fn_isformula(args, cell), Function::Type => self.fn_type(args, cell), Function::Sheet => self.fn_sheet(args, cell), diff --git a/base/src/test/mod.rs b/base/src/test/mod.rs index a6571f0..222fe1b 100644 --- a/base/src/test/mod.rs +++ b/base/src/test/mod.rs @@ -15,6 +15,7 @@ mod test_fn_concatenate; mod test_fn_count; mod test_fn_exact; mod test_fn_financial; +mod test_fn_formulatext; mod test_fn_if; mod test_fn_maxifs; mod test_fn_minifs; diff --git a/base/src/test/test_fn_formulatext.rs b/base/src/test/test_fn_formulatext.rs new file mode 100644 index 0000000..622ecfa --- /dev/null +++ b/base/src/test/test_fn_formulatext.rs @@ -0,0 +1,17 @@ +#![allow(clippy::unwrap_used)] + +use crate::test::util::new_empty_model; + +#[test] +fn simple_cases() {} + +#[test] +fn wrong_number_of_arguments() { + let mut model = new_empty_model(); + model._set("A1", "=UNICODE()"); + model._set("A2", "=UNICODE(\"B\",\"A\")"); + model.evaluate(); + + assert_eq!(model._get_text("A1"), *"#ERROR!"); + assert_eq!(model._get_text("A2"), *"#ERROR!"); +} diff --git a/xlsx/tests/calc_tests/FORMULATEXT.xlsx b/xlsx/tests/calc_tests/FORMULATEXT.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1b5ceae2af150d28ec2dd9ca755e2ff9996282a7 GIT binary patch literal 10133 zcmeHt1y@|z(stt>++Bma2e-jBcyOn22=49#cMAk<2u^Uf;M%xr@DSWyGWXtZW-{~r zf_wK`efH`;r)r(OyPkS#SCz6H6f_n97618qA)?;?JwITZm4N02^fP8uWf8)P+2S7<(iao5zp{LTV;>irwwT>e26-!2) z=rn93WK<^vObQ=)373|(%uU2fKw^iVR0!{%JHEKm)asekFhS3ZrP#cS)`HdG|8!ht zdOE!KkYk1yqTbDmM7;!6v+(22x@Os{GrEQ;1r$3e>=0WMDrLAKptV@~&QhWfT(zk` zSg!@qK^$}P#f3XC#>0kd-sL-d@_bsF;PL)N0F}RJ$|!0;h2~K3wUiusM3Q~Q-A)22 zG2&NwHZ5QrPjHuev3ScxV;9?LvMgp@pbfd0H#&;ZS@uRQGe|f~7k5vRpH@%Z3gPRJ zf;cwq1RNS7(0@LSqC%3g?r~RWD>pE{*i3*`+N+&vxd;8g4@zl#7(GEgj=aAOf~fgO zrf$3m2VzDSnG-(<>S5+&<3snLhXND31G-}K-b1N9ZkI-iZ9p!^q%)~mBp{&=|~{{lgz7mOM>nb|nA zF#o*%51aqRfc(?aK?w><|H9@&*x>c-$_F$tIX6-17V@{g{xZv`^)Urhgex7diO}8> z1VR1g*XH~1b!kN)=G!3o)g~t>3Ipp6WrJHqXzHEgdpLR;rxYni&_*x1>+I$1Rr+tT z9<;7)arEV1O7i7~)+nW>&n2qS#+fw<5HLRxh2jXN2k7)GXs;UIR6@*(sU25@RyFeE zeM=nA^aH099iRw@^T{7grDG2|8(S~@P zK-UYep}y>lyA6w*y%W&b-X8dq#6aq{_659XPrg%+aJ_EUnT-H?JyEh|+2b?O7 z{MBzQ05J`PahtF4(7%(zWNr~F*}>3^x*$VvVoJoI(V}-+BwBio6CMbFofw3>cXa2(@{jmp%Mxgj+=Dsn@ z9-&o|jm*6clgJ>Yx6R_bE9+biS#+U>e8b!7QcLW82VC%HYrD=I4M;4zk%cwERAd6A zA28M3(ox|;t~_tmrC1KAq17Ch8mq%tdZj#{1%eeR^~c8H&J~cW)&w7cHz*0kM-0iv25K~8JN0I>ao19 zgqpivB(^v_$wO-6hlcWfA4)Ig46HGx_qIkUVXs(WORz!pG$8j7bs#Mc*Rvd z?>$_@dRF9W{^_c>0b?LrtBVr}G%?od@QvRi<24lFkJvE>FUSfb?nTk_#ycr$2Zciq z=_;#1>0ELaId&`u?~1(l5QyOEbvz84u*D$T8TH~&{NBC*5=Te&u6*Fe@;M_9ye)$R z@lr-}dbU@hz_6MUSZeKQ^4SsY6+v8o2li;qM^z>&rkss&%dr%?V-fi!fB#djno``t zd5Fl9=n=-$;CWfKwfa_@U3bg`1!sF#vhp4S-|w)96KC87Wnm{XF?=9O!7m?DS`F)FGzN=kI+zk4JC!w)saBrXLe;1#W@y z&wL~SPi*;?v|mWz(m$%u;0nJ0@b3^!fJ-`pegUuW3rq;|(l{bdd_1QiJs`3wYez2=y zlkUDIiD+5!bE~+aA|d8X3WSUmoDz#rr^dO+gr~8>R0D*Q8p$H_ z(o(XkoUJ#cst>rR|u?TzEtu2$z(lk~FTyfe0 z>7qYymcp2!&_RhrHe&O3t8y~bmU_-dF*G`{wu`dQd1C42lJGV4mq`sxW(g;kA#dF$ z&J3w&1DVFlwGf%m_<(|ap>-sBAA>?u7qd?+Rb6k47O>~qm=j4Qv?qk4&P}Vwinhqc ziex@8hm{*PX@i1z@naItJ=0%Jbs6yICPQ{OXkxP|W4pv}XPU|v+>Y=}C_%iww^k%t z@`XZJhRC2wa(Qf;^;{FY372D|sPM}ZXFush*B~v>wwYD)TPJLRh=6BOxY#Y3O%6D z?#ZCPJ?sVh)8D+9!}D{YhMxUL5v)fBm%ERp*vwk>u+k!IYzM~1w$qI$a%?Mwjy&tl zD}HNDofG(Yw6#90Dgw)V&L;y+u2%_E#p*7R@7_FKYRVBqN(}q{HW2NrD<5$Mn@FoK z@T^O%okgVdimji<@fa_k#F*F^Jw|AJf4UYpf45M7`92QNr-`;JFmm<o)Nnm969s& zVXB*#f@$QtToTQ=gj`~fxHoX4Cpzh1swTINKb*nH)@RJ~V`qkOc_0T6Cd^Ss8~43B z#w;7|G5ablniwOAED*OgGgV1&7&%dm@yw~- zVaVM(1_;Y^?D_WCgOuE)-__x?xm1v#g=6`t zZBNNqvD|mo%fc$PaA)hw4H0dFyG&~W5@ux>doJ-toqycDF4fH)F>Nl#+>%KzOGB=^ zlL3II88S{jK9aVzgypS1bq_z@ik$FizstTO?}(MsxM`2ENhJ(ZUHL%kdkWv zxwXHvu%EhzYldr4Sd=pVlMesRs#k_}qF>+u0Cb9<8JyoeqKl=Otr^Sj*WaDtkJ>TdeQFhY|miLn;_P5$BS?s)lXi*6rW6PlWr zshpF^Me6Vlxk3o4vld^#s{a#+!;%3dV>>F$Ih_Dz9NPdA}*sQuBpm+$=P3}Y*V+0E{& zcA;C@A|^W&x4 ze#i6E5~{(|P)w@XL%HA6(`@6~W0I$qbqJmQ(`~t?f#2nK7QdS(QUm_FYv`Pm4NL;e z2*p8a&k+-M5fj8r;q=H%8F>nMCIq4YyRdKZk&Np@1RS`PN;a56*dNT^b>5d-;DBqT zL0Ioc9#|up*4g$z;~~=k)XR6&NJ<(*Q-V!e$&PVs?GB@Yoe?|hlk_1!WcBFb(5o$T z*t2L`sSs48pZmuV9AEMwNjk2AMI2q!2DCr$C4JYVrgdm_wJt@j#T-&*cb>O;L8UkzuPdGn=MPzpZ!Q+jg@ky z_$0R*@4v^y_edVvyX$h#raQo`O6z$t5d>fJmD~|#4$5YrtX(NQm|X_U)k60@T$aIf zd@$j3!@0FR#eI%9qI$mg7P{3gM&@ENLU%lPSm&Z@TzMYc< zO~DQE_}q_gofI0ageo>ogvJ-Mi#oO~Xp*$Bw|t=ploojF%HD?BHGCHxwHIHh(#y~| z4E0ZGLx`9%<&MY*k^pkt5MVSrU-@de5HT+5Joc-!vNoxYDA`ic&y=+jej;{>e(vJ zysxk`pL;c&vsh?kLic5{o}z9DCUlDL&B&+|%XT_LvgV>gh(@4m+uB`>z7HBVEOy5V zp8B`?W&hkW|a{* zlBWXk+-K|8xHA%J>J5_)UEXpFBVAub9g2y$M%9fm{XYl0x2{*p5I z9&69T*QXvS@Yxo8G4-IW!Q6yXW0ExvPl~J!nQc{)!Z-5K@xk53UmGFJk_@hB^_?Ej z3Ay0LJ50k-V-XR|Q<;O=rt(S{*F1D2Wia0XRoeWs3xX``r4n=itXhhL4nA$Z`DK?- zjP<(T=jedx1Zrx^`h?)6G9?mcC1o_UD6C8)Vr=TjvLH?pg^Ps-9cWY4@_9^6bkhC-L529Kod$EUGW@cLvmoF0V#!&WY3V zW+u2`Df<{&$O8c8i1SM#&P#eMeZK;#2A2T8Sva5-6k;EI@$k-(Keu`yWYT`^Kjb(o z=%v~pBK`8iP?_|XI*XjET{WaIlAMxh#y-ClyU%kiO9J0Dx?Fddn5~W~wvNZ5aCw$i zm<`}m94>5K)1Sl2mwmiMfMHPz!yDaTlN!pKutcW5+Ej>kHAa8If%e#xuJ=T+`o8$V ztHv@KtJWU)ULHhJEjz|ugnQ@6UJqjo!e>1WH||yITQNp~PBg_j3fLLC`O;^1iBu1z z7*7X1%=d)<6tWkVYq+<)Ao%v>gY|DDTN*i;nX0)sS=m|q4(NBWUDiFUXfUTQsh@eE zrD>R|Y&@1&$pLvj8qvP`e5Mvz#kfuZY;SX;Wcn3uzhy z#&BZaU;aRh>{B~5p{Y9yLIz&n7^X>%>KY?uOFtKJ@etFD4=+=W?j(h6oAqyinn))a zm&s)#J=L*T_-{q>G6WK|++n#?Z%7>P$HyETq?Wh0!lj}(?ld2UzFkxapKxE^Yx?90 zvG#kj*f!DHD~^L#u>WbfZeadb-(HsK`cl7oN!$F)*_asFn21{%S=s&cT`mbL)==bV zA*V<_aOwBGTvpShb0|QWoID?ZqpfRKt|WD#y#e9i)Yt@J*Z6rBN5S#aCh?o4q+&d( z@b^$7u$Wl4Mk7Wu-yMO>NzZJs zV?%z9cmMYL(j}Ko4@C`BkGcl;0Um|gt#(8aFhL5{4>3TdHN4@8#SYTv{7P?ft{H=> zo^|wq9)y=Ukm~6shpq7q@&`T2cq{4yF^;?PCExpMu!^TOoSD`` z9Kw8|{g6aCl4N<sl|Np0kVVn9_HEVB`DZ0{p@>y zx+6tiA>^}FK@I>JOKbk9GKNTSwNNZF$*-Xb2gM(Ol^P~z7F-u&NLloSK9-!k%4YDC zHx2sS>!cD1*@jSmc`qw)O2RB06^Q4J!t4&}MVDDVh*Gjn6zlE9DILVgp`ToLl!{wI}vW(KPd5IPcsCf>^eOl;vZ~bDqIOog4gd6DYi5 z)WV40(2ca#U~MQWJoPUvc?$!NKDTxyM=*s_3o)oqi*Dj$NJHw;+=w)^=u$7;myR&B`6g~L;wH{*>qvmF|s);OKVc!cAENJx|0VisaP+H& zUn7h^G?5bM0RV4O0N`(|{Hyq1{pg>?@5%op{%^0UEC=&q8$TO) PkO1v3#NS2r^V|OcHg(bN literal 0 HcmV?d00001