From 130d3c3510ef376182bae38ddb3dcd78a67bc9c5 Mon Sep 17 00:00:00 2001 From: aparajit-pratap Date: Sun, 6 Aug 2023 22:21:38 -0400 Subject: [PATCH] Migrating formula node deserialization to code block nodes (#14196) * attempt at migrating formula node deserialization to code block nodes * use DS parser to migrate formula node code, remove ncalc. * delete formula nodemodel and view customization files * review comments * add migration for more builtin methods * fix net6 build by removing unused usings * review comments, add ncalc to remove_me * review comment * cleanup, add migration test * add xml migration for formula node * cleanup * cleanup, merge master * update tests, warning message * remove unused usings --- extern/legacy_remove_me/nodes/NCalc.dll | Bin 0 -> 194560 bytes src/DynamoCore/Engine/MigrateFormulaToDS.cs | 94 +++++ src/DynamoCore/Graph/Nodes/CodeBlockNode.cs | 15 + .../Graph/Nodes/NodeLoaders/NodeFactory.cs | 2 +- src/DynamoCore/Graph/Nodes/NodeModel.cs | 5 +- .../Workspaces/SerializationConverters.cs | 88 +++-- .../Properties/Resources.Designer.cs | 22 +- .../Properties/Resources.en-US.resx | 6 + src/DynamoCore/Properties/Resources.resx | 6 + .../CoreNodeModels/CoreNodeModels.csproj | 8 - src/Libraries/CoreNodeModels/Formula.cs | 274 ++------------ .../NodeViewCustomizations/Formula.cs | 41 --- src/Libraries/CoreNodes/CoreNodes.csproj | 4 - src/Libraries/CoreNodes/Math.cs | 16 +- test/DynamoCoreTests/DSEvaluationModelTest.cs | 9 - test/DynamoCoreTests/Nodes/FormulaTests.cs | 35 +- test/DynamoCoreWpfTests/RecordedTests.cs | 6 +- test/DynamoCoreWpfTests/SerializationTests.cs | 32 -- .../DynamoMSOfficeTests/ExcelTests.cs | 8 - test/core/formula/formula4.dyn | 341 ++++++++++++++++++ 20 files changed, 602 insertions(+), 410 deletions(-) create mode 100644 extern/legacy_remove_me/nodes/NCalc.dll create mode 100644 src/DynamoCore/Engine/MigrateFormulaToDS.cs delete mode 100644 src/Libraries/CoreNodeModelsWpf/NodeViewCustomizations/Formula.cs create mode 100644 test/core/formula/formula4.dyn diff --git a/extern/legacy_remove_me/nodes/NCalc.dll b/extern/legacy_remove_me/nodes/NCalc.dll new file mode 100644 index 0000000000000000000000000000000000000000..e1c52cd7613aee7a36ef0c8251a6cdf4620929dd GIT binary patch literal 194560 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

@g=(MfN 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�Lb2VHfTo9N?QjPJ0bUe2oL zk%v;p&2XH_ot9xXkjmsa>Rqk|b08?CJ^XZa>bzM3^?>duI>R`%cs2B@Y20b`I_s+h zRC-wM-9l=(F%n)>n$>BHS0{bVl{;|#{EKnv^A7V8%(^?|=fX@g*V1(<`Yb@}2**f1 z%-W1MTbD~&F1(4O^bjPpN~uzPP0}FUbX*lsf~Foww`(1|QW>p0qq?($ONm6-VRo6Ew zarbt$e3}P$?%(%DBA`eFItBTWcoN*08OOhNd_zG2YPbWYmC`V!A}e(19cAIpvT#>f zcvo3?cUgE(S$J<*xD>z6GWgE3rTI(o>oleKb>a&HrTI(o z>nx*RR~dd?W%zZK;n!7$UsoA^U0|nh{at1Fb(P`Qg-mO^a_vG@oz9vre<6 z7T@Xn9;?$l5+}LfizDt=Y8naVcWm+BlV@u2lQ#TWJOu>-id?Bh0fl_>8uJiZ8jrw1_{3;$J3iZhFE-%2 z52F?O)UOnVW~Q>36+h%iq81 zj&r9U{*R8aAG~yb;zQpYdC4E_{KOmIv8VQyQ|1@H(0a{>u6W(1xBTuyH@*LT=U0FI zZLfdiia(ec{fB#RyJzI8SAF|UuYTv79=SLA$jz74XOoYAb<3(heob-bXV29A@Mqui zH<7zctOjVsh+7OunOKs}S~@Lsn(16l=Q285=xnC5iq0lF8|iGIvz|^Z9jr@D?1%V^ zHPN?@P6Hh*QcVo=q^+%yK1_oq2F=XGppcmu)+Hu(6CK#yOl&(HY$cmmf{x&K1$|rT zw9-k@xsnbz(Zuk{A`=6pO$_X5V)(+3iCs%anuVpYiLId%r^63uh?8_*;8_*^0MDxM z_ji)a%9i2P&?toNI@-t!lyMpuCSY+ev`Sk2?=)3e|XY$_pLQOqBdNhpB zgMu_+MARQj)agi&ep&~g0E-P3Gc%ym)8_lXsmmzj)tHx!oyitjC-_nFJifl@9#Fx5T=L(rtFE@R$HJzJmoynd)Q*1qzX`MZTPk&CfdUM6rg6HLSw4Ow^ETG`? zsjbB`ERtzGpDmtgl~0cLjP1u{el5OLb$mL5k^*%WpT)%2Z!fm?d2_jH0sP0f*bV=SIpxD^f##W7ps;wqxKiH`vutMOhmm|VA&q7eQ)Bq;1-$!O znMHsCd}`@NI%Bo1ShlPccfGiK#qAgOsJI8k-5JFP8=-oq>LiG-Qr0v!##?Jrd!=}4 zZ!opQ%F#4>TOJR*gnJsgX~T8Yos2SVeeS z8UdlPG0|#d;g|#n>xtB~V9oY$EwV2yihIAf4~Y9(aUT@-A#vX%?pwswQjd!N-QvDq z+z*QTA#pz}?&IQqOx!2X?&juN6KQT{gPYkldLr~hYSFCb&Dzu(>sw=~g~rs4sf*3h zlm(KdsmGF~sfUqGJxNkxC%BPq-ibQkB|Y#+AgSqyq%<9o+(!ty861lYNjj?}x*KJi zj*C}aR@j_cn>3Ns0RI86WOH-O)I^Yie$alpLlM231yfyhB(HKl!oFA9a5vh(I+~?K zQ!_D3t!-*X=S2XuCK5+YYa7vipnsR5e;0cW)tS`d*MTaCM%+m-B7xXH1=*4UY4Mv$ ziFpiQfcI*GY)%+($Uh3lG-H&kX^r9WBz*E8y~i#9v?Q@%4tXZwNw!9t`9v!t%}Kgg zsUs(r{qzdgB6~f$gXQpFfF3Kf=LEz@lDZq zBd~_>X=!9A%Bqt|v<=>Ocl{E4AWxcI&4ph$BHKz zy+w?xr-=AE1GgCl5Y5xPDwJ3G099$lLK&2Mf)Fs)NfhFx?t_|%y(8q4!bu1%9rkFj zrRW{(rDO!%gWh=pq`e<)0JWZgT#=_wnujrXIR0DMrS$0IL527PB7iM{z^7n97y-j4 zVmLq+pGvLPK7I;*p$YN`sTz~Ysq6{lj^IIPtA!N_l*maFKO;D^FB(C2j4-;5gaQ#2 zRr)NourE?eE$Cs;n@<3Q=Sq|mm|rAU5j;k|f>;D@ zUltjeRM!5okQSISC)(7^QN}0vvAJ3L9Rpj7V_r(vw7~xluh4cox5myzrnG zFu0b!j|g%Q_#5G73TLE(ktof-Cggcg8SZfqAH{W4q4S>sTcOKNw%= zlx%DeTCBw+mnw1qV!V-bgiR(zQ-D}=st)4@U^#qoxkS+%5Gl`8} zpzy_~gj9_I`H*25%BZJNea#cz|nQfGiC zD6vR_Hn!G+pz7C2Et$fk25Cug`(=>~=teTjQ=z~TSb%JPqjVaWX$+8)sXCT~FhW=o zz=iar7Mc}yb7}$kQgsxiO-@v=U%z4i6=@HWuf&_KAW=v}pH6}+qIUA=m>)G3PLYvP7{JwS$DXV%rAKO^hR z+I2N-5dK(bH6|Q5O^dHbD2c+62*v}c)7;!(ASK?Y|7$VnC}RLr15^W=;|Wy#Zxuh8 zrzT-)QUgs(Zw9p>w>BIYlL7usI4| zlq`3}+A!wer4rQ!`q1})xKD}ugt!li`x$W`7xziJOPk?he8&7o@~ZEj?iWGw0V7E#$lZssu#J1FrmQ)en_i8v!AS7|HWm zmj|!_@oS}dUfY^jt?^RXL#25D`CTiaIrZ#{<~t* zXtIo;^uZlO|3d;)N-ceuY_RlrY6;4kc0JjOOb7CPXb&s-aFAVzWL;(t|F`r-xes5- z?tVN}PC-WqTOdDvHFJE-<{%2>P2KPGx$k2FMiEnNwLrk1PhdQ>G{S;_VbNTdh&2uI zAGEnxq?tYpy=IPzowXPrkQ*4lLv)TeBx+&NNTvp`{HsmCNfJZ^-ln0*`b2GN>3@Pf zu-mF`Q%__AM$Fx*yOYpaF*QKSHb?MpL!vg4x=VLioAKaAZ0g23jzN)1Qttq(Y`#)0 z4vm@_HWSSbPXs>f$U;M-=>`#40Jo;Dj$;HzQmeZXO_9`C5_z~y%i`Rgr9Sakb87MJ zsm0$X*|5ECK`)E(t-k_>V1E@qq}7|Jb-H5lbz8 z53v6c|ABmJ2?C`S3UD*Xi>wdGvI+56(y#=&osa~9=U14=}p`X@2>V?v1}>(C#%@I&sFhGac4c?|m4 z;@j(q?_0omSlR&+9vc#?@puaqEaF2iA1W{xA7H;Xg9M2Gnlu0^BU*xqi)D!hG{s_5 z0^|$L2^-kkd9D=rBRPcK-{IPFHh97V#$S(EcMb^x|%aU z1gm*K!$OATzY9vDAEMGJ+XSmGGXs*o4634TP^nqMPpu)9pMpItwX_NvDtZP*r3HQz zo8tlzmKWvp`{WFX23tv7GusB>U&DVSf?fzbDA~4Qg~R^EY>9fK7)FhWB-(>ke;*@& z$N+nESS)oP)CDpRJ<@<1r8QXSBw|q&OnbEG8>1(LJiXP}ws znGq_Nk##kCY=i;&RFmZ~6Kbu@sM;yhR5xXuYNm`+y)^lo_uO^cmaZpXgI%z<|Bv6U zdGmd}Ll6AgUp(=?H(ivSu?XDTxBf;0maWG8M@^@}HZ1q7PUH6geqG4$L9ASM_gkhnh~?v%J+Sj#+T`|@yKCoz8_F%OCVUE+RlH}gCu{@)Py z^WuI*+^>oISK@wK-0zC}Z{j{BZls?OR*8FsxHpRXEvc)!pS2J6kMzgQDTyzN`%1X4 zHb33ZHojT%yj$WwB<{!izl8kXK&ej2Q*XZ8|8Iz?8(^uaUSob&;$Llw@PFFE*)YIb zu0)==X%l~!xCh03p}2QT>Xi7;4G`v%xUZG?w}|^8N&UzGG5@%@pO^T*8TcNSlK(0G z=wRbu+_Z{&!yw~#i+hW>FBErF+*5uF%^JR9-X$=qCG=hMxa91Tod0Y-E;)}#+P^UbtnZMte>Z<1X{QiMnjbKPwBkP29;^A5r2W6` zy$yWL_5c6>x;W!(oU83@w%Ntmkd3jq2t}DJQ4=B&xhP7dND{R)EEhF}Bubf5RH{{K zl!{u5P_w8h6(v*(@hLtZ)$j3qzFvEuBcJ+yf4}eV_rLvazyEh`=izmKJ)f`Zi}%Gj z=Y6(zpjx}+4@{-7-6H%_!B2=K_`=V2>`F0GO27E>+ym!s7eUZ+>gCQseB`i^OhcA_ z(Y$l}&f7sDwq0ax&Ez!L27t&`z@DQ(lSPuej%|}V-vL{aoWi!*Oikqs&gB8lB}*>n z(r@cTxn#*V*!B=S=>r6BaxP1`glxH)bEyE`Aadm=a$3kQwy`Z&?v@ht3DS8)p8TEZ z2T+;lB!h}2^xt%tmoX|AQI=xo1O0@^Nm$P%XKKwCv0`3TdSplZ=imN9+Ug?gf& ze46XB3$#@9m+LvteVpeYSM}@v!Rg$faxqvQWLqX^JLm_6E);D+ z*vBHZ<{(|3 zd|f`o^pvGVoXgwiw?_%D%f(FZae1%HGN$dwWxIGoKFRbAsIPoizQ^g3 zj_I&GkI9u!xg3@GOd+OYvO7~3rhmvDOaqyImA#lIFrAczOmmq2CHpWv$@H7NjOksb zKjh_1pD{@_i0K%URzsLXH>yjN8pagMR9}r`%3_LEqg?1-aSrG<(Lh}X@{4@XcF>JX z{h55~W~OVI64WFnI$~o#Q^hV!Y*7NbO(d$>t|x>LPk;od)HNNw`x1L5s=1tQ9cZ6S zRP&f>*p{RgFdbn^Q46`A$rlK*TZGgirn5lDvGXiuIu}$VGSw0u&3>TmphsOUv|%_? zwp!}aD19nZj#}=j51MD`Nv7qXhAK}z%~Wn_71QgWplYL@L(PPE7j&Cwqn>v~foee6 zpqE@3c&7i%GFU)I5_!&yhM-oQGZbu#N6ti`M|SxZ?L zur6kOoOK23v#hVMu4R3TwUYG%)@`gGv+iR3iuGI8A6SpF{>mDqs0SLbCPVubXQ-ag zmaJ#9c4h6wI*@e~>p0dsSnpw-$ND(bC7xH8KwnmU8@3T^)#cF5YB02h^>cL`~ zb$Q7@h4pOKzN|N~KFaz!>p@oSBmWjqDK7MlgI?vE1Rd?00xkCSgqj_X_BtsR`HGw! zZ#BXLi_2MGVO`Jq0qZW-J*)>=e_}n(dXiQ6DF+v83~P`zowWsPd)BT{DK7FCL$C3d zK#TpRK69M`{%-EJ8LcLUe*K93~|_BfZ2P(KOd>0 z#Ug03cm#UBpnP0`$1%f0fu8Vb7nlO=7FdbBVqoB9#9tYxfR2OD>1m5OrZiB1_@|Io ziuD1ix#{QPz&i+2Z^wx*1MegJbD$dfdtfItHntn`Y#h5A+6v);#plLOK{!8lFtmWR zXY5r77qa%{m@8O^$Bsn&4MfsYZfjIJS6xRUZ)VN6qXL3wa z)@*1!(It-NQeT9nxDr0~I81s2!c@b7#n-?(uy`WtOx7~i*PtE5n{ho+&zd;Dr(ba` zVxmxbJl;j!A4hHffn$DTrE;SLl^Z1vvz|n4@m6Dy>e(>Z6S)Nt#+u?7)1nT+-Ka?~ z#MBc5IG$QmPYeqtLq{WqN=)}?L8WLxrD!gt?&x1Ao1&EQoc|QoX{?K(1B+K8hk?bf zvA)6j7VCD_z0eNg2rC`gJBUAm4LluiSB$g~G)iQ~Qyn5(*BmkT*nY^3r~aX_h!XAD z^IWJ)bdAqOt$J~|Pkd{Hsl5Y>&H2MX#1AYU%4*IlMsRo(>sZzaP?wm5{9WAky78qx zuP3I)cYw}_pMr8t9sYeiP2C0-&p~cdtc<6b_7ZQh8&=Rh&CjVRS+ zP^_ay7ox0*h_5H^Z8QbCn8PbM`~rvHVBOT{5_p;!zMW&fWj)SHrQe|LBU#Owtt)Y|Rr$En)`95(f;(t!8MxUR=xYQGWB+}ZX zwG(C6PUM=3Nuu~fR$5b1G*6lVHT7wiMC&e}t!8h@<@Go$I2+^J5Ak)o-;ktxw6Taqg9 z*_ysgGcCgXkpPh_1%R3hf01i#qCG+&e@Re1uUEQ@S2#cJOcPpqhP zsKyf~4q193X^ST){Mp9yg`^r!yy#?UEo=#5s6#cLMxw;hM%WU?Du-%3Nut`)HrSHI zaffO=jYUceQ^FqDQbfK(HJ(&4#?lY4rHN99YCP#;jisN^hLEUrsK$ftqc=y;zLT(J zilz?Lc$$bpORvDzRE&41#?wqJwp0$=Sz^6IHJ;{TpQYol;X^m{MOBn=+*jkt7I~I_ zLp@uF0S?u8T8bh|G5#%{98u;_ji;5^WGM(+YjMb-8c(hWwlXE8!4%K+tiPe_c!`5C@J5=L2Tby935-PbCNAxcAwOdgo8zk=r^<*+LxufXIL^Jto zPe)N=$Q_$}$aAh(VX0a2Tu`~CPOx-VfbTw>U#3@UYVCy2>^nG8~x96hJ2jkg-X{@C-OdBk9 zVhVONo?V&7Sn9#F-coNSe<$NPfN7MaAxvv6UCq>x-#3~mu4fuyX*|;!OOu$~ct?c# z^Dd^83NAFXnyFzALu-u9 z(i=>xE;6<)OvUuZEb`pRRBdS=)0$pns}cv9))x{@6Gxb8ndT=(rFgvsVpKn}(VUM3 zO?D{Bd!blt$lWldiT5J0)>2AJ7O0Y`%AJ$a+S^m?vqW>gr*K_n$}3B12ixxcT!OoE zN+)kGaf)f0yGKes$UT5;Ria-?FYm=-JQGGGKlhxW>>|DU(1&*BUyWQUqFhgQ5DV(?R7o8%jx?4GK;$ zl#_ZtX!31_x~47!4u6Dp9T$`W$2F7)gafshVDsy88o}p z(8AQUpoR|+nK3F9ekLLd%fslh>sm(#ZXIh>=-M? zSfb;@O=7ksIzHSa7FtSA)4rR<8cSJeZqNoMQ_pc?tFfUxuW!6KXg%AcHS$dm?jN`= z?)ss(rQvCrpnN8i=R{FxY{)a)cbgbvJ;$XT^4u~N^NZ>l)%P*308 zBKTvSXK!DzXz$P`-f3chA@|(0&EDx^qNRt^wt298t+MQ*2GU)pwt8AEsQ$^FhyCF^XxvIG8rYcfVNS*p_%65XHypJePUqiNxb| z^pt15$a3g8&jLJyhR*k=iNk4AeGiI#ppcm9KABeHdkAl*8}g=?_!fy2dLt5^XQkik zdsq}QQC(j0ED`JRrW2(*Cw;!}5m9TY59m>GoZgT^x-sc{y-P(?diw^RMd=Uw9v20c z?n_?|>dRzylx6S=uc|ttRdug#xwTcv=(N?oCmo_ywNg~tJReD~@U0U2EIpk*40Oa0 z#^|W$8T;*TT7T<(&x%49*9TjAxqW{#W`@P?5Dog${XM z5lgKtIW!lv%GfYpHhb5I_PE-t8>2O%uO%9zSH)OMG!Czc*_LP=D#Qv%~4p=<5p4dU5JBa(g)!*t)}WGSmL(3qm#CH^pp2vR~*&-jy^wms_l_vF zwgs?NiiMUQMO`Yz3QNy1t+Di0C>oxXhUBJ@2bAOI(xX2LZT41)E=+sn?ohnHO7vu! zCZaPupi)ag5FZ#(>#C@XjAOnJ5Td`TsAixoVmEs(5-lHknnWSTEJ zWi#^hd^QKX0W>v6+SbpAn)z z^gM_+R;G@b5Bhm4Wy;T7;{S!*@K+Vp3$~L6K$j!kzZ|+I^O*0HLpNof@crh{?eP4= zp?fmN`+0jtOjXo_nPq+@kMsCdNg4-iHFyRIY?8*Io(x%{afp$5mT3GM$Sw}`@HdpJ zEYTQwXk^V-~9W?1iX58RUmU)(FR8nNV zB^s4fS!jtyC0!1+M57XtV=PhcX3EKysCS#nQcKjk&E--{)Vp|S3;$I`(cEp}5Y1~m zE5h1nY;zo$$ynxW9i+@kNm^rT0_yFW!8E|$PG-3#P^w>`bWr~NtDYX@q6YM{*iLFrAAG@ z^rWhL^t47N#hmQJ3%T5mc>c3VNIn>>Eom|YcNE9~t z-9JXIcPJ`wy*%WQCvc-oX>4j%*d!rvv+T=MCCh!Gzyw)r>4ntpzFTFbr9Mr%`zA^( zEE*$uRg>(%ZL-u*^mR>Yyp!Z6Ya7>OGpKzkdq&gIX_8!QNZ!^YFEB~&v2;tQyYF@x z!o!Lv&!Q&L{>d`OQVCNhON*ME9hfXjEIr=jTu>>~e6hMoSI|OZ6pN@I`Xt@8to6$1x>sA z9E$4Kw8Asp@w~ZdjW^LO>SBn;W-U?hHdvoQdGyxkpagR^)cw%xEfg#B|sptQ~wbr`h{6Wt9h zmGijg%}OnmizCLt@$^vJ!<3cQ-4`Zm``o$`Jf~24n5ZZ2cWhD3y8FVE(k$BlfMd&o zElllUo9EcN!xkp$`T36RvSvp?tDQDX4=j+C4$TQHl(h~m2s|uLI8+vRL>6aIMl*3= z^Vr{gaEt3U?uoF!WER%g5dM&VA4t40QzzR9Wp|ZeAInj_PLFvz8 zWpn9babt3E_CS1z;kjbQ&lvrs?~C>C7R`{<$6mrnycjoOEi9~Wu+lW zGkLW{&&B2$&5)%dC`cBs4WRk^{^I*ie4a;rmI0~^(#5AD`z7rm>t!KRm85mFo(jWXm5bJq zL%iY~;*}F7TE$_aRU9T-#c$T->7i8|CYtka$)1hGWT_>Zbz9{^OSEfj zm1UM_er}ViEYWVWO|D_8iar;4ekc=js1r*>@3TG*d?+WjBAV%*0NY2h$Wk%N`$*0< z#AgE4a-KsQ{ME9I$-HA!Bi*ez7xt`?euw@D)X1iW-1nn|oifML<7oR%+1}D~X!}l? z&t&raMD8;-&hry_$RT&^C-PK;XRRE?r?qC>Yvovn{IRvNh{@#nncU;pDmhz8}i99<(VA2TV^p;$+hU0FJz9T_s`0R{nD9{G(+~tJd@771FhX7^DTXk zbbDl9LwF2cjd!mcVRNC~bgy)^p^U2Va{3_d_e3^ za=fKE&4M4fXCdS&zlK)Cs1U;>N6Kd}Vl0 zXJea{^>l1~b_j z1g({Hb8H``?C!p>Z8mbrc03<|EldxCS~xa3Luy$^9y)sp6OCq=X#B!N$AB==Xy!P% z(6PgzsHJE_t2$fMvh4k_tyNJE>Irjgn5RmaXbv9r@R(e{aHID10svT+)cZu5LP^-90Rmvq)0_BqBy-eje)G4mN zDsZS<+~sP7L%rgzP-6{=H?#Z14N_|@eUyDg++cOw()8@1aaXEfA(c=fc4uD`H$;^& z%@p5c-xzn5+T_r!al=(XZ?20tnEjxCr0VI=opINwLQ6L$O^X|?hBB3ipR@0c8>6;5 zwuj?JZ`+2?9j@%TU7~DiTES?`MBHE#6HGzWX9UK$!Z1DB3z@t88=0h zTU$kw_u`7w2Bw9gUW+&5rmCTRIUV|}!ZS@3IkY8inyPl_L}0o)&QujmXMi)*DMN0$ znwX*7{V10zH(fW*P)#k-ZaPEdTcUL|LoKvKD`$o}XlXf9@G_GNohQ#wAxm_gT%rms z(Rp%-8pJeHcw1C>@coqjCLLV|+@tzhqU(Tr)KE)w9WYakvP9PbGu1>xxI;G}FiRC# zqO<#1&aSaEyCyD7SuJYfX4ly~IW2a@&8ed(mApSTlD>+&Ppvh1Mt5nk**jOQx74G> zHqa(ZePO#_ZM8HQw)<7BrK@3kK<&14BWw?-gO(=3HcuU5qB&pTnWv6B6bqYcK;76T zdFQJjQxzY_9#rj_Dg_y2RRKv?n z&(raCi3%E$bd*`5axBqN=22C^Wa{~tDs;#n`UEK^$@ z+fmqdJ9Id%OdV&c;+j37P8q`9b2#n^RXULBIZZ5Y@k`tawSvji2;R6=*(O10Xd-{MxOgATca&#T~| zx-mKtcu|!zRYlV}DpzYQ(fyZlRcVRV(MxKpB|09xq-rhEs(M-Nu|&tCm(?LlbpPcQ zb=(r&e|bgW%ek~}qu*^2?O&tZmTFpb_pMPuOM78^Ri#)u4BM+J%M#tUc}?Y6qWdFV=5iWo+6j2a9CZsqn`Du*pP_Bk@8Kob_CgQ7YE12H`NIyGe&PJ_sF_*CjxJ& zp$@r&Z>xz8B?mXEg-m9QD%Da;G)9$bl_eUZ_f)wh8l(5rdP_7$RjSewjZu}VwnSs} zzN)oEWAwh-XNmfHlR9LH`g)T(VTt;4v%;68c{Hg%H>-x0XdFIJxJk}78ix;5&=B|a z7H0>`YB4F`kmnrq=hix#hxURn(WkY-)U)L$VZvG0q`NLcRN?tjiR+Dx&a=K$d6wwB?km;B5}nt5r3wu3dEHlP4AXnKFS6PDm8!P% zXv;}~uhh^RC{NrmLmT#}9hTO%#I?3saURck$IG{08+3`rWXZ`2Vcv)3I^Vl0(c;?_CQ{sXEL6F%92kv^cdGQB6` zb6N+#Q)_P`&qX3Lr$g|ND!bWGZq9kZAJy@3L}nNMNu4s}z5sdtq+H|K=Ej3Kd_O6_ zrAuKutP(8^fbFnqYKV`2M^uhO1;Hb#fXUSQnA+snaHX%R9qJuCrVd7U{-O$Qq0;x` zQws6^U(^UDGwXg);~i=q{8be>G%$El9bqaFSLRfBPAT^UZUbnW_mo=5R3b*_6#9Qt z2QATP{;tN{YRaRz`-hrsiRP}*rrwli`HYAX5xWKSzfItTcSDP(#6)3=7dX^8k?Afo{!R%mP#=y z_4E--bd_9BC*EdSM6;)!&SR>Qw8moe086ySV)PhGw8k3fd6sC6HP8z!(Hd*0%b3g> z^XPJGqc!HyTP@KV^XeUzXpMRGZbQ7ry!wx=}?6yT@P^RC};%J zBJpg__+Us^T6zhTp|kF!To#Gy)JefiJ;u^jP!qk%(yKX>f=%@vOY3rqg3WYckxBPn zPL-#*9>rwZo~6e+l;zFRMGoQafi5+K&!$ZeX6wAW>e^7@X{iS}G$+_nk8x;TFh@^j zs=}^c6W3a&Or>;HI3m=<vQyOLp-m~(TA8SCG9<+VrqM({4S?Y;2hm$nxWr8=j!oHRWiBN&e+bn z%u?%C-F@fjYD-;Ped0Y|@3wSBt1*GD`h-J^gI%?2y6N33T9pO6>2imj3l``N4!st< zNLMpe%95O#xQlhq8Jv#i^(A^dlbI8j=wgTF1TWF^9GVv_)MZTX$&sxpJeTTfrYd$k4 zewrR{>8Vz@*4D*LmGY@pSHzX*)t26BwI}u-y}{C_tpf40^l_$X;%m@soifYR?0BnM z&m5iS5Uz{$Y(qTm_vxk9rjpxv@6+XuZGUX3-r(30HU4Q`ZfRia8t+Pdkf}=0d&w*HDQml- z^)cT{-S7db%QSH_Xq8T}bQkCuoyAn;rlZWWI?oavWuDbtm`od<(*+Loh<{EGaHx0u zYCX!Ni!N<_Mf?kTtfghGdw?bz;%nv?^=u|{PvAwp*b?0nDAzlTC*M6-qmNsn_jA_h zP4lP?Rs5dftGb%$Jwfl9ysGyYo1ph)*6NA#*;CLx>UDabA--SmhCXG9?iakNgA2&h zTu;BPCo-AVzO9Q4;XGuU_ia7fQYp@mHt4mMUT#ga$w@aoutD!|=&Ja4^d5(#8u?afh{`3REhWBbNyR%Q)A<6lC8QulerJJO?R?HS7+OF zz9qWXwM`dTqI+H2bWclkuj@lyXo>E1eW?2y;=5EI=>eALF4aeRHPcK{fm!~M&RJ;c zSNzRCTBkh35y-l2CG;&r=24|`&pmpwM=GgKh+x|JU`WYB0N9U zMMSOc=PsRRZB+U$-8aH>mmU$}`I#OQ;rW@K9pU+zUL4{1 zxh{+F{9JE{@cdj?M|kemwGp1X^@#}2-P-*~U4K@1zR-TADmT^h3!P_)TJ(j^kMR6b z_l)rTQjdx7{8CSj@cc>_M|ggv%OX6#(&Z7Jd-U1}&po;}!gG&47~#2BABphXtNo9L zdw#DDF`1tKT4z}swdiZzGs5$0Jt)HS8$BYz^BY|p;rWf87vZ^2FOKlsr`JY!?$eth zJipb|5uV@bBN3k8YOyrj^ZT`%$@Khwon?u7e!uP%;dwykM|d94BO*Kx=!C2#H%@rQNdq3WCA(x>{=34uR-eHM8BX~rYmQlJYL7x#ks>_)6N7Lu-kLq$u^#0#by}=NF z?*6E*wl@0Q{V~1A+UTnMm_EW}+I~!*aA;NhG3{P%%A-BX6!XPddx9pg%5qILAEKgN~CMBmog=565Wg3oeJgKhy)2Jtt z8HZF?Ux$8-s($pjb$=>NXRvj=^oVV zWPHfA(0Yb)RYDWjQbT-nYU=9pR9zcR#y55KWU9h0`dO)<)OijT72A6ra{Kp#wyvHJ^h~hy-HmVDs9%FJdJ!x~sdRC$<=g^Jy(gcd>3#BLA{O<`zwxVG$+#=JK?kHD@i@9{N zD$(yxVJ!wC#wEy8is7u8m=8)&kNrn|bq9V9U5RTsRb)*}=_VgD$Ii4;jKb4v!gY@H z`TMZRe?mmLk!$3y`ZlsAk^UweUPnsY5s|a0No4PtwG&yxNUMqeU+a03He5F)OdHRP z341Cr?Tp$+*6lwNp2ImTa8%jV5ss09!gcYBI2?$hvHPp=QqIlj44zSDEl^n6b@4d+ z4CIyg1c#?{*sQho@YHxR6U|SP)>tV|C7xsdmpHtR!#g-<{C*YkkBr~QK3mu)9M*Ua z7I~T&6Ast8Ze~Wt7#~wlQ-__%Q;R*EbJ$Y~WBuNVSAxRY*7?s?<6oC*7_Z`RZVFEe zqk2-j5{EdSQ&1O|Qnw5JRbNH+SUBgu?!EtW{r2Zp|3`h&pgpxZtV+ZpMvEkl5BHB0 zW<*lCmm){gjCj~naUY)E+kfA;CasyD|2}6W{%#J`l@&Q>!n2~zN~QeI*NxVQ6x}$j z3Dc8MPLFBEG3{7Qn2ujcT);8CSo^SE&N_tk-|wFq&kLmd!&VdH62qKSQkWb@oDmZl zUxXv06r@@Rr7h#|4eV2986h#k+ZTngu@!oo(zv*IG&zN8TP*cqfnRDoRux+ z+L9{qIEPIsRHDMO6{)t*aJ;EQIKFNdHCA)1p;=mY{zfr4_VK(mRx`)So!pdI6A}J% zStg&z(iIdLL)w5F6dIJ}GJ|3?Tbu`42Him6LQVQsCK@%f~QImkX|#vFIj*5yDY zYVl9RyKK+kQKL5hIv>-wku#?e`qS()_z`;!hxY_&`@!^*X_4tS;~B1%#FHJVb*4q% zqb5=WxOA(Wb7Z;3hmLfL&k9TpC7vxxF^Qb^On;NA-5EJY=3`Qw%|4_`boo9I@yTap;XF_Gr&2VYWf(5Ylsg6W#HxYTSIYj5U>K0+s&P`^?=)Rku$@j%;K&a&DL~?Et6G^T?PpSBFUzId3Dwk-O7)9zoK& zSrHkY#WzIrpat>#<=sy$F6?rPr2deo}l3J^@b9!b4)e&A*tdOAw}d$H?@syMP&G|dcedRrQWW~+4THB zxx~nP!eK2oa;^S8#^ht_d1n3dlW11Fk9-uK*jg8^+ojFwrjb?l`qX$*pVVEkni%q_ zi!nX+zm_(#tdF@?wa~hpKj#>e^O;st6N=Y@Qn^m6^O^Bx#)k8eg7U|cbh#ADp{{4b zY5yvwF5Zlzx%Xw%jLz3iZuDGa>d$bD;uvjX_OoYrE#r&=F-jcf_;6T@;~W#2n_0{M zm8*t-ah~R?;dc%jHFLWGM)~w3)S2;T9;ZZya4MROb!VPuo|Q!&zaqo+Ifwsx>rA^& z^0`6e-eUGuYF*t}(0*HYpXXt|!ZI3}>i=~3?{_vl?j5y_=boW3p8e0`6?q5D#7D+N z=9$bn&^3GA@#4=hF1{Zdb=r<(CazmKP9PE!pjEj^2xYHrTc!tv&wL*1F4 z$urV3@~khilr(O;xhoQ>EjhjexA7bfhxZn3@4c9D|Eu`$K4A7A+*{!DD3dDEYT_gN zHoSHe_n~(BFj?%xuS4v@Ynwk& zDDfOoaS8svg#X_r28ca)RU(JIcs(y}L!P%G&q?@y68@he_Q*T&D#B|T?9)YW{8}8n z#~Ki%(N?o^kK&2X^y$!m=$_jmVL3hlUF*pZC$sYsGVqR6hlGH*I5*mlRH5?_zC5=8 zO8$ez@Z4SrZN#;?eGNcqZ|0a^@JwtfozhNB zXvj~n2#Q5b?o3#Y5~n3>hR#g59(o^AQMrQ!eY5Wt#4Jh(a@ruLS}vF5E=`ytmgg={ zSi)sxi05-xq0Z}aUw}TJTfzD!>$|L*SwCXk$@)3;J@((hx`*`;lv=bmVVBsNx*y?R za}RO&D8hf_{>tG~2-nY3jmW2dqi({V=izWH!ijl_98N_zBd-aEvk=bCYt7+y2)E5U zhr{P1+&Qm+!@UqL$m_%57f?zyN+&(adWy9^tktQptf{P7tnFCOXYIxMLc(6|v4FfZ z?{efkFz?Dn0e*L~n;4ll#n%+p&%I3ry_-K++?ZGE$w3Uhdx{<&*(gWcnsU~_hu2tN=a>x~uFRW?_z&`CK|kX7k6CM3 zcSEVfslLJD+q}|7gT+zSKk^nd%9i!oEP>tcT_o;f13%}2!h=lNYq?CFGDK==0erT*DNx zAattHSd{KgoXDl8@aRnB5(}-*tWYqq2tJ|268L=3XbFGnf3T#_KMa;sH+*IvTF7Zj zIaML&ypVHV$~hNuZI`lVDX%iL2&;9Sqj-W2(suW)lk_CSb&{TWxQ?G^xK7d&58;U? z9l{6wvrf{J4NC>-I!RA5Tqo(7h3h1JW@4SB-YDfhDMh(CiQ7@i3EyVe8LrziT&uyn zYn?<4J;Q~{-7Jr`>7Te<{(^C#-QySD{YE6x9(XO{=`$Yd`8PS%@fy-FklB&UzcBr|qoa_U_<3N#_Je7qFH= z>G?c6xZIQIw?h9(wBr5XNm;LLci%}lJ@@@!Kv7GnXMW+mbS!$q*S2Rv-d7P`)as7J z40SZUI5A1Zw>^rPpWe3CvrFc*otfB1b!fX3yKB$3r3lk=g$Lsswx#gz-m_?5ud_9Nhc=2N5GnlbI`nF5@Y|nN{pZB3LeT_%tEpEj& zDEW#TPrWCrGgq83d-4j;fu^|?j9+V*IpIjUZp{f$oY+*{6{s3;X5w5?90vhcK3 zo}bT1ddlVw9+4e9QagCm=ELXn#8N^1ybtZ29w42=x`4F|O7meKkI`~TpA4dT_)X$+ zlRxwm?@JtB$GVYqGqk&JJG8>Hi(~e(e#d&0^(3p*g?Ig;eUGRIKZjmpZg%*exp*`^{pKeho)r+!!$mzq9EUW5jOgSp0UTTa3qNtK2x#_yIau9Dx>ze?W`zgV}C;viT3_ zY=Pf97o{Q^I!}0^3q>4sF@E*YEtZN@Xc>Ny(JfYp=Fn9l2f7-+nTX%p5FMavL}%z) zkq=!jE`)9n7egyWALu4A0J>EShE|JV&>i9$Xss9n-7Ri{?hzB9`^4?ggQ7@z#UU{b zdPK~G9vAmPPl$!kQ(`$($QPh4Spjv+^R!nqlovq#vKAVYH@Lhw>*^APK9Ltf$H40pdzXo>WbP4^+$aMof!2M zbavD}Xlc}U(0NfmK^I0HgD#Fb0bLsP8}wk5s*iG`>O+r2HH03I3P4XpB|uL_HHM0M zA*icfGiaxJEuc&5!~&}#R! z^;?V2qi=+M6MYNxhv?g($D)@*{}sIks$(`n8^nA7jf?pX+BoJov`NfAp)F&CyR~Q+ zQ_qbv&zOLF8Z^PZ9NO5u5gKxTBf7^lbLY#>F)iF9ptcXxeB%sK9|`kiCC zyEj04y7xePW14i1xy&7cUg6G%4s~DS?Hn`G9rAaMxz?Qzz0o})*g0mryBK<#dk^#u zw}|f?bGLgBw8SkEI>*d$hoJYn^PvyAM?e?5i=mIX_duU;i$n5NMg z(Cp|9(ALo#q3xpgKs!b6g`O8J(mTgo5FLVE6x}VM)c_)QxqdE>mRcsrg%*M zn5{ASEcGBFW1xXJlElqkd zX;sqdr1k%s{%uU!%>O=2s`)Se`!wmBq$5e6@;`TSa&iV<*~v9YZIe4Dw@v;Kb?%Z} zkbH6S)yelJzmQy$d@MQG`0U1`8b8|j{l>={H%+-RWlqY*ly6epsV!35q;_!r<)`MS z_DWrq^dZ-CK~nG3%ThO^Ck7$*D#Z7~|5vBpoH{XeO6uLI4<{`|+^VE!p&L>^NUdg~ zn4PJ=rq)ZNTs&zPq*0Fj(*~!lO1e6YT7E;?t!a0p%}tt>HaG2|v}OG7sk9ehdnIjs z+B<0|3rHIbYJ>`w50U(^qQm=>1U@eOY4$;S^Aau z|Jw9%>66oo(-+u(2T=Onw1?A|fKD2q)GKv(Xmn^?=(f;3q5DFMLr;ZX46O@o3~dc9NdF}CVbUIW z90>gw+7mi}x}E~5j0PF88PsFFQWG=MGtSCrm9ZebZE}~4?ub2*b{1lKW?YsrIAcV{ zwft{v#*~bjr0E&=WgJL*2%&MIWf`mBI}YW(lCdshd&a}*4KiPW^~0q2%mwKklY6DQ zLX9)$CN;~<$!weXA;!&=_xIWcW8OKlM`rKL18J9M4ns~0(&KTzsS)mP3H&bSAZRkq zkRrnx_9)zqazmpi$iP`xHnfGv z#MxI<+~916v#sX%z0WMs3zmMcTqauM>?&7Wi8HeyqK&v3cX&qO?#{KMqqqTQXcNUb zxL#T}nnxZ`s_?)WS~PLJS@&r+PPJt=zQjA?*)8f|z6zpMHz z&efh5SBaOzFq|2=B z59?yqRjkG*(ptgsZ?l@TrgT%TDa+&^nd*a%gPhV$O-#;_WtrSQ?l=sd)3d2=yE=}7 ze#PzD$0eE?nw-Dmm=mn36Zv~PQ4g3L8gWcEs~OqzJ5kS=u{Pmeoo;}?37b@rbsoTJ zBim>^BYh&nrXP%tsri4tpUt?Ko*C9@JZg0Vw`Dx*ZLD{&&geAhPjxmWKG2E!>aWIY z8MozGRx@^Mxb3EOf0Zh7l#Ty}h&q_Hv!xTwB@@4ot)?H0)zr<@*?1n}I{cIM6zlJt z%H$B~ADO?&v*9^3f{{IA`pTp-KE@h6r|3_;WZG!j8#(LF93wN6jhdeS|3-)KzF~Hc z(Mi)$f7735uJJQt$kQ#pz>&Z&zJw|q2k6+)0P4mab{FEmhAMF$juiCE&QXZ}7mgTy zTu0VJd{wT@j9gDp5~%L%2Rv;flOF)GIGUj1Q_r9NrJXyI-;wGy(64DA7pvh9=5B z&}7*UdY9}EeL!9goiDF|E|-I$Pskz2=Se8~Q(lGeDyYJJlHt(j>kL6Z`E1?R{zPSzI zDyS0g%i9s&1Xbc=IR&~C@7XBvrMwIJmAo5D@7^ffftdmQM&1McNzOv5!%&4Q_&Eq4 zg`$V$ebAF~E@J)(RpMXr0fbLMmH180hq}~*h>3!tht)#}*N5W#M?H*iG!!#mEkU>e z6g{sVMc4yH|EtFk_Cc{q)G~wvP<#?vEr$lxlZc6jD$!Uy1x-;a5t9m4qNREUnxmdW zOe?4o9o6&D0`(&FLiG}~w|WISP`wJhQdPin2vmuoY8~_{^#*j9dJ{Tay$v0qHbO_L zcj0+86e~-;2fa(Z51pzuBmQov62)o@!qcEi%u?GBo()xEj`|4Ud!d*iYCCkX`WP`w zpcqZH6S_ft3f-u7LEllIL*G?jKr7W((D&3{_*X$On(7;bH$j#7Kz)nw7N`J8&DD-P}3^Ct8vEtM}px>%rp@-E; z=r8JD(BIT=@cA8zm8JebSm-|xmRd?F6jTYV@t<%(m59<&2-kz+J4m`d!fvP%(K;I8 z7$`o;sv98O5UPYndl2?QF|yi+a0*n3R2@J#4XQ-Cjzc&ERU$*jBb*6UqKR&Va8sxf z&2$pNXF>597u^`)EGXuNPKD;^bZ9G`f%w+C3Bql4Gw9j6IrKuE4ZT>mgkGXsK?`** zJbOcxxKy`6xDQl`%XB;FAbmDs217BIbVr1TK=H^YeGc?y-5EMgp9dYUyTW=46yI;r z-4MPNs&F5xJHod?m6)L~gwEC%LFedRh`$%A#C`e_giE0ccdB|L{0tO3iS7ff(EXsl z>;8!U1By{_U5>B|icxS~0gZ7DhNilPK+{}TLDOBs;S++QCtV{E&V(wF?Yaiq!ZjM& z(sdoQwd;Clp6fG@L;GCLtJwZ9ty=;cHM{Ya41%>Yc9f9L+M`K0|<|XVsu>dp|`jm zgidfh1fA%57<#8`3AD)dD0HgpG3X4}GH8iwIdrD$N$4`yQ!*KMmHQ#L`naM?z|pZ8 zj$>!zSlvtX$Mw@FTnA0W@wi0Xi#ye$Gsk2;j%%zJa6R=Vu8X$d?(&$-7x20<^H$jI z$}G;jm;Yawxis_X%<|0FGoOYpr5cmzDyGji(Ak3d`-0XXR$=(BGV>ojiB6Bp=}vLO zkZw3$BXFKD60fWAx(2UNc#X#ETD-2qYYbl3<8=dGH{vxGubc3?8Lx48jmPU2ye8nx z;a0pR;%fCaye8pwJFZ$M<63nJUU%SiCtgK(-G$dwyza)U7+0RtaMd|oTrOtdRf5+& zc+JFXmbe0U_$N|z#l`4R`rF6<7kKFk+x%UL@Z<=ti>Ln!o%rG1$4w|0JGS@8>u(k} z-FnTq38P219yN9>JO9yavX?uBDV&D!zvcgm9*{V{#r3qnggNa`@~p=XGM^DoZZ!P| zg*1-7MCNa{qB}AJu^xv*FT{P5{#c!T#HHX~&>jfW-&ne%=k$M9w$i7y zPG4CRU4R#MA*`qg$me>jmeI)bW~`=hWX7EvN;Lr1k%+w&_K}$1*TZ@<+i^YUI*8)1 zt08^@EH`5no|#i6`{dzHkNMXg>z96%x;?H8q~l+J(r?A8rhLYqR?elOJ4zl4n?O2u zM4Ev}GXbf>b!vnAO6~CKgqJBJ2L9A4d?En8H*-#xLT>`&euk5GYu@i@jpbuEl(?@n z8m*ynyQ9V9u`f`~uEQQfYrH?KSHpTM*K{=U4Pk7?fpI?uS4TMBT7T*l%B8Mfi2l0l z9PX38NIMSoxeaZeh&tA#h^#O5AN9rQzJKnKKleu`PSXwbycI3D32hjQmW412PVdP- dr$e*;`|odifZl-?V(j^U>-68o|3`b^e*j&*5?TNN literal 0 HcmV?d00001 diff --git a/src/DynamoCore/Engine/MigrateFormulaToDS.cs b/src/DynamoCore/Engine/MigrateFormulaToDS.cs new file mode 100644 index 00000000000..da90a992fac --- /dev/null +++ b/src/DynamoCore/Engine/MigrateFormulaToDS.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using ProtoCore; +using ProtoCore.AST.AssociativeAST; +using ProtoCore.SyntaxAnalysis; +using ProtoCore.Utils; + +namespace Dynamo.Engine +{ + internal class MigrateFormulaToDS : AstReplacer + { + private static readonly TextInfo textInfo = CultureInfo.InvariantCulture.TextInfo; + + ///

+ /// Regex to match "if(, , )" pattern in Formula node and extract the parts of the + /// "if" statement to construct the corresponding conditional AST in DS. This is because the DS parser does not + /// recognize this "if" syntax. + /// + private const string ifCond = @"(if\s*)\(\s*(.*?)\s*\)$"; + private static readonly Regex ifRgx = new Regex(ifCond, RegexOptions.IgnoreCase); + + + internal string ConvertFormulaToDS(string formula) + { + CodeBlockNode cbn = null; + var match = ifRgx.Match(formula); + + List dsAst = new List(); + if (match.Success) + { + var cond = match.Groups[2].Value; + var expArray = $"[{cond}];"; + + cbn = ParserUtils.Parse(expArray); + var asts = MigrateFormulaToCodeBlockNode(cbn.Body).ToList(); + var exprList = (asts[0] as BinaryExpressionNode).RightNode as ExprListNode; + var condAst = exprList.Exprs[0]; + var trueAst = exprList.Exprs[1]; + var falseAst = exprList.Exprs[2]; + + dsAst.Add(AstFactory.BuildConditionalNode(condAst, trueAst, falseAst)); + } + else + { + cbn = ParserUtils.Parse(formula + ";"); + dsAst.AddRange(MigrateFormulaToCodeBlockNode(cbn.Body)); + } + var codegen = new CodeGenDS(dsAst); + return codegen.GenerateCode(); + } + + private IEnumerable MigrateFormulaToCodeBlockNode(IEnumerable nodes) + { + return nodes.Select(node => node.Accept(new MigrateFormulaToDS())); + } + + public override AssociativeNode VisitFunctionCallNode(FunctionCallNode node) + { + node = base.VisitFunctionCallNode(node) as FunctionCallNode; + var funcName = textInfo.ToTitleCase(node.Function.Name); + + if (funcName == "Sin" || funcName == "Cos" || funcName == "Tan") + { + funcName = $"DSCore.Math.{funcName}"; + node.Function.Name = funcName; + (node.Function as IdentifierNode).Value = funcName; + + var arg = node.FormalArguments.FirstOrDefault(); + + var newArg = AstFactory.BuildFunctionCall("DSCore.Math", "RadiansToDegrees", new List { arg }); + node.FormalArguments = new List { newArg }; + } + else if (funcName == "Asin" || funcName == "Acos" || funcName == "Atan") + { + funcName = $"DSCore.Math.{funcName}"; + node.Function.Name = funcName; + (node.Function as IdentifierNode).Value = funcName; + + node = AstFactory.BuildFunctionCall( + "DSCore.Math", "DegreesToRadians", new List { node }) as FunctionCallNode; + } + else if(funcName == "Exp" || funcName == "Log10" || funcName == "Pow" || funcName == "Sqrt" || funcName == "Abs" + || funcName == "Floor" || funcName == "Ceiling" || funcName == "Round") + { + funcName = $"DSCore.Math.{funcName}"; + node.Function.Name = funcName; + (node.Function as IdentifierNode).Value = funcName; + } + return node; + } + } +} diff --git a/src/DynamoCore/Graph/Nodes/CodeBlockNode.cs b/src/DynamoCore/Graph/Nodes/CodeBlockNode.cs index c8ef0974e7f..7c06be527a6 100644 --- a/src/DynamoCore/Graph/Nodes/CodeBlockNode.cs +++ b/src/DynamoCore/Graph/Nodes/CodeBlockNode.cs @@ -658,6 +658,21 @@ internal void ProcessCodeDirect(ProcessCodeDelegate handler, bool isCodeBlockNod OnNodeModified(); } + internal void FormulaMigrationWarning(string p) + { + State = ElementState.MigratedFormula; + if (!Infos.Any(x => x.Message.Equals(p))) + { + var texts = p.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var infoList = new List(); + foreach (var text in texts) + { + infoList.Add(new Info(text, State)); + } + Infos.AddRange(infoList); + } + } + /// /// Undefine a function definition in a code block node if it has any. /// diff --git a/src/DynamoCore/Graph/Nodes/NodeLoaders/NodeFactory.cs b/src/DynamoCore/Graph/Nodes/NodeLoaders/NodeFactory.cs index 13e7c4fd0f4..487dee1884e 100644 --- a/src/DynamoCore/Graph/Nodes/NodeLoaders/NodeFactory.cs +++ b/src/DynamoCore/Graph/Nodes/NodeLoaders/NodeFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Xml; using Dynamo.Graph.Nodes.CustomNodes; diff --git a/src/DynamoCore/Graph/Nodes/NodeModel.cs b/src/DynamoCore/Graph/Nodes/NodeModel.cs index 2b1b8101ae6..b71c5c0ed87 100644 --- a/src/DynamoCore/Graph/Nodes/NodeModel.cs +++ b/src/DynamoCore/Graph/Nodes/NodeModel.cs @@ -1841,7 +1841,7 @@ protected virtual void SetNodeStateBasedOnConnectionAndDefaults() if (State == ElementState.PersistentWarning) return; - if (Infos.Any(x => x.State == ElementState.PersistentWarning)) + if (Infos.Any(x => x.State == ElementState.PersistentWarning || x.State == ElementState.MigratedFormula)) { State = ElementState.PersistentWarning; return; @@ -2921,7 +2921,8 @@ public enum ElementState PersistentWarning, Error, AstBuildBroken, - Info + Info, + MigratedFormula }; /// diff --git a/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs b/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs index 8f82282bca5..7ec3cddd186 100644 --- a/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs +++ b/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs @@ -46,6 +46,39 @@ public class NodeReadConverter : JsonConverter // Map of all loaded assemblies including LoadFrom context assemblies private Dictionary> loadedAssemblies; + private CodeBlockNodeModel DeserializeAsCBN(string code, JObject obj, Guid guid) + { + var codeBlockNode = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver); + + // If the code block node is in an error state read the extra port data + // and initialize the input and output ports + if (codeBlockNode.IsInErrorState) + { + List inPortNames = new List(); + var inputs = obj["Inputs"]; + foreach (var input in inputs) + { + inPortNames.Add(input["Name"].ToString()); + } + + // NOTE: This could be done in a simpler way, but is being implemented + // in this manner to allow for possible future port line number + // information being available in the file + List outPortLineIndexes = new List(); + var outputs = obj["Outputs"]; + int outputLineIndex = 0; + foreach (var output in outputs) + { + outPortLineIndexes.Add(outputLineIndex++); + } + + codeBlockNode.SetErrorStatePortData(inPortNames, outPortLineIndexes); + } + return codeBlockNode; + } + + + [Obsolete("This constructor will be removed in Dynamo 3.0, please use new NodeReadConverter constructor with additional parameters to support node migration.")] public NodeReadConverter(CustomNodeManager manager, LibraryServices libraryServices, bool isTestMode = false) { @@ -111,7 +144,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { type = Type.GetType(obj["$type"].Value()); typeName = obj["$type"].Value().Split(',').FirstOrDefault(); - + if (typeName.Equals("Dynamo.Graph.Nodes.ZeroTouch.DSFunction")) { // If it is a zero touch node, then get the whole function name including the namespace. @@ -165,7 +198,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // If the id is not a guid, makes a guid based on the id of the node var guid = GuidUtility.tryParseOrCreateGuid(obj["Id"].Value()); - + var replication = obj["Replication"].Value(); var inPorts = obj["Inputs"].ToArray().Select(t => t.ToObject()).ToArray(); @@ -176,9 +209,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist bool remapPorts = true; - // If type is still null at this point return a dummy node if (type == null) { + // If type is still null at this point return a dummy node node = CreateDummyNode(obj, typeName, assemblyName, functionName, inPorts, outPorts); } // Attempt to create a valid node using the type @@ -197,37 +230,10 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist if (isUnresolved) function.UpdatePortsForUnresolved(inPorts, outPorts); } - else if (type == typeof(CodeBlockNodeModel)) { var code = obj["Code"].Value(); - CodeBlockNodeModel codeBlockNode = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver); - node = codeBlockNode; - - // If the code block node is in an error state read the extra port data - // and initialize the input and output ports - if (node.IsInErrorState) - { - List inPortNames = new List(); - var inputs = obj["Inputs"]; - foreach (var input in inputs) - { - inPortNames.Add(input["Name"].ToString()); - } - - // NOTE: This could be done in a simpler way, but is being implemented - // in this manner to allow for possible future port line number - // information being available in the file - List outPortLineIndexes = new List(); - var outputs = obj["Outputs"]; - int outputLineIndex = 0; - foreach (var output in outputs) - { - outPortLineIndexes.Add(outputLineIndex++); - } - - codeBlockNode.SetErrorStatePortData(inPortNames, outPortLineIndexes); - } + node = DeserializeAsCBN(code, obj, guid); } else if (typeof(DSFunctionBase).IsAssignableFrom(type)) { @@ -263,7 +269,25 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } else if (type.ToString() == "CoreNodeModels.Formula") { - node = (NodeModel)obj.ToObject(type); + var code = obj["Formula"].Value(); + var formulaConverter = new MigrateFormulaToDS(); + string convertedCode = string.Empty; + bool conversionFailed = false; + try + { + convertedCode = formulaConverter.ConvertFormulaToDS(code); + } + catch (BuildHaltException) + { + node = DeserializeAsCBN(code + ";", obj, guid); + (node as CodeBlockNodeModel).FormulaMigrationWarning(Resources.FormulaDSConversionFailure); + conversionFailed = true; + } + if (!conversionFailed) + { + node = DeserializeAsCBN(convertedCode + ";", obj, guid); + (node as CodeBlockNodeModel).FormulaMigrationWarning(Resources.FormulaMigrated); + } } else { diff --git a/src/DynamoCore/Properties/Resources.Designer.cs b/src/DynamoCore/Properties/Resources.Designer.cs index c901902b459..917980b34bc 100644 --- a/src/DynamoCore/Properties/Resources.Designer.cs +++ b/src/DynamoCore/Properties/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -19,7 +19,7 @@ namespace Dynamo.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -731,6 +731,24 @@ public static string FileNotOpenedCorrectly { } } + /// + /// Looks up a localized string similar to Formula failed to convert to DesignScript code. Please edit the formula manually to use it in a CodeBlock node.. + /// + public static string FormulaDSConversionFailure { + get { + return ResourceManager.GetString("FormulaDSConversionFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Formula node has been deprecated. It has been automatically migrated to a CodeBlock node. Note that results may vary after the migration depending on lacing options selected on the original Formula node. Appropriate replication guides might need to be applied to the CodeBlock node script.. + /// + public static string FormulaMigrated { + get { + return ResourceManager.GetString("FormulaMigrated", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attempting to load customNode {0} loaded by package {1}, but a previous definition named {2} exists with no associated package. The new customNode definition has been loaded, but Dynamo may be in an unstable state, please avoid loading multiple custom nodes with the id.. /// diff --git a/src/DynamoCore/Properties/Resources.en-US.resx b/src/DynamoCore/Properties/Resources.en-US.resx index dbc18de0f7c..70da17d6afc 100644 --- a/src/DynamoCore/Properties/Resources.en-US.resx +++ b/src/DynamoCore/Properties/Resources.en-US.resx @@ -902,4 +902,10 @@ This package likely contains an assembly that is blocked. You will need to load English,Čeština,Deutsch,Español,Français,Italiano,日本語,한국어,Polski,Português (Brasil),Русский,简体中文,繁體中文 + + Formula failed to convert to DesignScript code. Please edit the formula manually to use it in a CodeBlock node. + + + Formula node has been deprecated. It has been automatically migrated to a CodeBlock node. Note that results may vary after the migration depending on lacing options selected on the original Formula node. Appropriate replication guides might need to be applied to the CodeBlock node script. + \ No newline at end of file diff --git a/src/DynamoCore/Properties/Resources.resx b/src/DynamoCore/Properties/Resources.resx index eae3ecfdf31..523bd8cf3ea 100644 --- a/src/DynamoCore/Properties/Resources.resx +++ b/src/DynamoCore/Properties/Resources.resx @@ -905,4 +905,10 @@ This package likely contains an assembly that is blocked. You will need to load English,Čeština,Deutsch,Español,Français,Italiano,日本語,한국어,Polski,Português (Brasil),Русский,简体中文,繁體中文 + + Formula failed to convert to DesignScript code. Please edit the formula manually to use it in a CodeBlock node. + + + Formula node has been deprecated. It has been automatically migrated to a CodeBlock node. Note that results may vary after the migration depending on lacing options selected on the original Formula node. Appropriate replication guides might need to be applied to the CodeBlock node script. + \ No newline at end of file diff --git a/src/Libraries/CoreNodeModels/CoreNodeModels.csproj b/src/Libraries/CoreNodeModels/CoreNodeModels.csproj index 2d3f81254d6..65517fc2627 100644 --- a/src/Libraries/CoreNodeModels/CoreNodeModels.csproj +++ b/src/Libraries/CoreNodeModels/CoreNodeModels.csproj @@ -24,11 +24,6 @@ - - true - - runtime - @@ -96,9 +91,6 @@ Resources.en-US.Designer.cs - - - diff --git a/src/Libraries/CoreNodeModels/Formula.cs b/src/Libraries/CoreNodeModels/Formula.cs index 11c8dc07ee9..3cd29265b2c 100644 --- a/src/Libraries/CoreNodeModels/Formula.cs +++ b/src/Libraries/CoreNodeModels/Formula.cs @@ -1,14 +1,10 @@ -using System; -using System.Collections.Generic; using System.Linq; -using System.Xml; +using Dynamo.Engine; using Dynamo.Graph; using Dynamo.Graph.Nodes; -using NCalc; -using Newtonsoft.Json; +using Dynamo.Graph.Nodes.NodeLoaders; +using Dynamo.Migration; using ProtoCore; -using ProtoCore.AST.AssociativeAST; -using Expression = NCalc.Expression; namespace CoreNodeModels { @@ -20,262 +16,40 @@ namespace CoreNodeModels [AlsoKnownAs("DSCoreNodesUI.Formula")] public class Formula : NodeModel { - private string formulaString = ""; - - [JsonProperty("Formula")] - public string FormulaString + [NodeMigration(version: "3.0.0.0")] + public static NodeMigrationData MigrateToCodeBlockNode(NodeMigrationData data) { - get - { - return formulaString; - } - - set - { - if (formulaString == null || !formulaString.Equals(value)) - { - formulaString = value; - if (value != null) - { - ElementState oldState = State; - { - ProcessFormula(); - RaisePropertyChanged("FormulaString"); - - OnNodeModified(); - } - - if (oldState != State) - RaisePropertyChanged("State"); - } - } - } - } + var migrationData = new NodeMigrationData(data.Document); + var node = data.MigratedNodes.ElementAt(0); - /// - /// The NodeType property provides a name which maps to the - /// server type for the node. This property should only be - /// used for serialization. - /// - public override string NodeType - { - get + var child = node.FirstChild; + if (child == null) { - return "FormulaNode"; + return migrationData; } - } - - [JsonConstructor] - private Formula(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) - { - ArgumentLacing = LacingStrategy.Auto; - } - - public Formula() - { - ArgumentLacing = LacingStrategy.Auto; - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("", Properties.Resources.FormulaPortDataResultToolTip))); - RegisterAllPorts(); - } - - protected override bool UpdateValueCore(UpdateValueParams updateValueParams) - { - string name = updateValueParams.PropertyName; - string value = updateValueParams.PropertyValue; - - if (name == "FormulaString") - { - FormulaString = value; - return true; // UpdateValueCore handled. - } - - return base.UpdateValueCore(updateValueParams); - } - - #region Serialization/Deserialization methods - - protected override void SerializeCore(XmlElement element, SaveContext context) - { - base.SerializeCore(element, context); //Base implementation must be called - var formStringNode = element.OwnerDocument.CreateElement("FormulaText"); - formStringNode.InnerText = FormulaString; - element.AppendChild(formStringNode); - } - - protected override void DeserializeCore(XmlElement nodeElement, SaveContext context) - { - base.DeserializeCore(nodeElement, context); //Base implementation must be called - - if (nodeElement.Attributes != null) - { - var formulaAttr = nodeElement.Attributes["formula"]; - if (formulaAttr != null) - { - FormulaString = formulaAttr.Value; - return; - } - } - - var formStringNode = nodeElement.ChildNodes.Cast().FirstOrDefault(childNode => childNode.Name == "FormulaText"); - FormulaString = formStringNode != null - ? formStringNode.InnerText - : nodeElement.InnerText; - } - - #endregion - -/* - private static readonly HashSet reservedFuncNames = new HashSet { - "abs", "acos", "asin", "atan", "ceiling", "cos", - "exp", "floor", "ieeeremainder", "log", "log10", - "max", "min", "pow", "round", "sign", "sin", "sqrt", - "tan", "truncate", "in", "if" - }; -*/ - - private static readonly HashSet reservedParamNames = new HashSet { - "pi", "π" - }; - - private void ProcessFormula() - { - Expression e; - try - { - e = new Expression( - FormulaString.ToLower() - .Replace(" and ", "+").Replace("&&", "+") - .Replace(" or ", "+").Replace("||", "+"), - EvaluateOptions.IgnoreCase); - } - catch (Exception ex) - { - Error(ex.Message); - return; - } - - if (e.HasErrors()) - { - Error(e.Error); - return; - } - - var parameters = new List(); - var paramSet = new HashSet(); - - e.EvaluateParameter += delegate(string name, ParameterArgs args) - { - if (!paramSet.Contains(name) && !reservedParamNames.Contains(name)) - { - paramSet.Add(name); - parameters.Add(name); - } - - args.Result = 0; - }; - - e.EvaluateFunction += delegate(string name, FunctionArgs args) - { - foreach (var p in args.Parameters) - { - p.Evaluate(); - } - - args.Result = 0; - }; + var formula = child.InnerText; + string convertedCode = string.Empty; + bool conversionFailed = false; + var newNode = MigrationManager.CreateCodeBlockNodeFrom(node); + newNode.SetAttribute("guid", node.Attributes["guid"].Value); try { - e.Evaluate(); + var formulaConverter = new MigrateFormulaToDS(); + convertedCode = formulaConverter.ConvertFormulaToDS(formula); } - catch { } - - InPorts.Clear(); - - foreach (var p in parameters) + catch (BuildHaltException) { - InPorts.Add(new PortModel(PortType.Input, this, new PortData(p, "variable"))); - } - - ClearErrorsAndWarnings(); - } + newNode.Attributes["CodeText"].Value = formula; - public override IEnumerable BuildOutputAst(List inputAstNodes) - { - Func backingMethod = DSCore.Math.EvaluateFormula; - - // Format input names to be used as function parameters - var inputs = InPorts.Select(x => x.Name.Replace(' ', '_')).ToList(); - - - /* def formula_partial() { - * return = DSCore.Formula.Evaluate(, , ); - * } - */ - - var functionDef = new FunctionDefinitionNode - { - Name = "__formula_" + AstIdentifierGuid, - Signature = - new ArgumentSignatureNode - { - Arguments = inputs.Select(AstFactory.BuildParamNode).ToList() - }, - ReturnType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.Var), - FunctionBody = - new CodeBlockNode - { - Body = - new List - { - AstFactory.BuildReturnStatement( - AstFactory.BuildFunctionCall( - backingMethod, - new List - { - AstFactory.BuildStringNode(FormulaString), - AstFactory.BuildExprList( - InPorts.Select( - x => - AstFactory.BuildStringNode(x.Name) as - AssociativeNode).ToList()), - AstFactory.BuildExprList( - inputs.Select(AstFactory.BuildIdentifier) - .Cast() - .ToList()) - })) - } - } - }; - - if (IsPartiallyApplied) - { - return new AssociativeNode[] - { - functionDef, - AstFactory.BuildAssignment( - GetAstIdentifierForOutputIndex(0), - AstFactory.BuildFunctionObject( - functionDef.Name, - InPorts.Count, - Enumerable.Range(0, InPorts.Count).Where(index=>InPorts[index].IsConnected), - inputAstNodes)) - }; + conversionFailed = true; } - else + if (!conversionFailed) { - UseLevelAndReplicationGuide(inputAstNodes); - - return new AssociativeNode[] - { - functionDef, - AstFactory.BuildAssignment( - GetAstIdentifierForOutputIndex(0), - AstFactory.BuildFunctionCall( - functionDef.Name, - inputAstNodes)) - }; + newNode.Attributes["CodeText"].Value = convertedCode; } + migrationData.AppendNode(newNode); + return migrationData; } } } diff --git a/src/Libraries/CoreNodeModelsWpf/NodeViewCustomizations/Formula.cs b/src/Libraries/CoreNodeModelsWpf/NodeViewCustomizations/Formula.cs deleted file mode 100644 index 3b67de358ee..00000000000 --- a/src/Libraries/CoreNodeModelsWpf/NodeViewCustomizations/Formula.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Media; -using CoreNodeModels; -using Dynamo.Controls; -using Dynamo.Nodes; -using Dynamo.Wpf; - -namespace CoreNodeModelsWpf.Nodes -{ - public class FormulaNodeViewCustomization : INodeViewCustomization - { - public void CustomizeView(Formula model, NodeView nodeView) - { - var tb = new DynamoTextBox(model.FormulaString) - { - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Top, - Background = new SolidColorBrush(Color.FromArgb(0x88, 0xFF, 0xFF, 0xFF)) - }; - - nodeView.inputGrid.Children.Add(tb); - Grid.SetColumn(tb, 0); - Grid.SetRow(tb, 0); - - tb.DataContext = model; - tb.BindToProperty(new Binding("FormulaString") - { - Mode = BindingMode.TwoWay, - NotifyOnValidationError = false, - Source = model, - UpdateSourceTrigger = UpdateSourceTrigger.Explicit - }); - } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/src/Libraries/CoreNodes/CoreNodes.csproj b/src/Libraries/CoreNodes/CoreNodes.csproj index 834e114cf58..99ed8ac50bd 100644 --- a/src/Libraries/CoreNodes/CoreNodes.csproj +++ b/src/Libraries/CoreNodes/CoreNodes.csproj @@ -20,10 +20,6 @@ - - - runtime - diff --git a/src/Libraries/CoreNodes/Math.cs b/src/Libraries/CoreNodes/Math.cs index eb433e8ec86..cb186df4fd1 100644 --- a/src/Libraries/CoreNodes/Math.cs +++ b/src/Libraries/CoreNodes/Math.cs @@ -1,11 +1,10 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Autodesk.DesignScript.Runtime; using DSCore.Properties; using DynamoServices; -using NCalc; using ProtoCore.Utils; using CSMath = System.Math; @@ -365,19 +364,10 @@ public static long DivRem(long dividend, long divisor) /// Variable names /// Variable bindings /// type: var[]..[] (result of the formula calculation) + [Obsolete("EvaluateFormula has been deprecated in Dynamo 3.0. If using this node in a graph, please write the corresponding DesignScript code for the formula to execute it in a Code Block node.")] public static object EvaluateFormula(string formulaString, string[] parameters, object[] arguments) { - var e = new Expression(formulaString.ToLower(), EvaluateOptions.IgnoreCase); - - e.Parameters["pi"] = 3.14159265358979; - - foreach (var arg in arguments.Select((arg, i) => new { Value = arg, Index = i })) - { - var parameter = parameters[arg.Index]; - e.Parameters[parameter] = arg.Value; - } - - return e.Evaluate(); + return null; } /// diff --git a/test/DynamoCoreTests/DSEvaluationModelTest.cs b/test/DynamoCoreTests/DSEvaluationModelTest.cs index 046660b8deb..add1d963af4 100644 --- a/test/DynamoCoreTests/DSEvaluationModelTest.cs +++ b/test/DynamoCoreTests/DSEvaluationModelTest.cs @@ -665,15 +665,6 @@ public void Defect_MAGN_2535() AssertPreviewValue("49048255-fc2c-463d-8e93-96e20f061a0d", 42); } - [Test] - public void Test_Formula_Lacing() - { - RunModel(@"core\formula\formula_lacing.dyn"); - - AssertPreviewValue("d9b9d0a9-1fec-4b20-82c4-2d1665306509", new int[] { 4, 6, 7 }); - AssertPreviewValue("c35f1c6d-b955-4638-802f-208f93112078", new object[] { new int[] { 4, 5, 6 }, new int[] { 5, 6, 7 } }); - } - [Test] public void Test_Longest_Lacing() { diff --git a/test/DynamoCoreTests/Nodes/FormulaTests.cs b/test/DynamoCoreTests/Nodes/FormulaTests.cs index 741ad97e512..c47065ce774 100644 --- a/test/DynamoCoreTests/Nodes/FormulaTests.cs +++ b/test/DynamoCoreTests/Nodes/FormulaTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using CoreNodeModels; using NUnit.Framework; @@ -20,10 +20,39 @@ public void FormulaWithIf() string path = Path.Combine(TestDirectory, "core", "formula", "formula-if.dyn"); RunModel(path); - var node = CurrentDynamoModel.CurrentWorkspace.FirstNodeFromWorkspace(); + var node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace("a9a9e7fa-abda-4f0b-8a9e-d7f8070b6b99"); Assert.AreEqual(3, node.InPorts.Count); - AssertPreviewValue(node.GUID.ToString(), 2); + AssertPreviewValue("a9a9e7fa-abda-4f0b-8a9e-d7f8070b6b99", 2); + } + + [Test] + public void FormulaMigration() + { + string path = Path.Combine(TestDirectory, "core", "formula", "formula4.dyn"); + RunModel(path); + + var trigNode = "b052363d-1713-4735-9568-5d3a3e98a740"; + var node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(trigNode); + //Assert.AreEqual(3, node.InPorts.Count); + + AssertPreviewValue(trigNode, -1.9952); + + var expNode = "cc59376e-25a1-4ac1-b0ec-f525260c645c"; + node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(expNode); + AssertPreviewValue(expNode, 22026.465794); + + var errNode = "5d2f36ea-e692-436c-9a3b-f1d15b093c0b"; + node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(errNode); + Assert.True(node.ToolTipText.Contains(Properties.Resources.FormulaDSConversionFailure)); + + var numNode = "a418958a-990b-4b9a-998a-bcfc581f4ff4"; + node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(numNode); + AssertPreviewValue(numNode, 400); + + var addNode = "98fe8b4b-c82e-4015-a978-fa632ce0c2b0"; + node = CurrentDynamoModel.CurrentWorkspace.NodeFromWorkspace(addNode); + AssertPreviewValue(addNode, 6); } } } diff --git a/test/DynamoCoreWpfTests/RecordedTests.cs b/test/DynamoCoreWpfTests/RecordedTests.cs index ee918533f51..ea41e056633 100644 --- a/test/DynamoCoreWpfTests/RecordedTests.cs +++ b/test/DynamoCoreWpfTests/RecordedTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -4817,7 +4817,6 @@ public void MAGN_7348_Math() { AssertPreviewValue("93d9bb4d-4da0-422e-add0-3b6d71cee598", 3);//minus node AssertPreviewValue("9b00f9cf-9590-468f-9579-89e76a0d1ab5", 3);//cbn node - AssertPreviewValue("013c4b13-2b50-4385-adb2-39861ca5fa1d", 3);//formula node } else if (commandTag == "SecondRun") { @@ -4825,7 +4824,6 @@ public void MAGN_7348_Math() } else if (commandTag == "ThirdRun") { - AssertPreviewValue("fc7308e1-546b-4f60-8342-d607692db435", 1);//formula node AssertPreviewValue("3507e4b6-209f-46d1-9ebd-cf9b66088c65", 1);//remainder node AssertPreviewValue("37592d1c-992e-4101-8bad-f1f4c031634c", 1);//cbn node } @@ -4837,12 +4835,10 @@ public void MAGN_7348_Math() { AssertPreviewValue("389b90e5-83ea-4f38-966a-fbce6d5cb550", false);// <= node AssertPreviewValue("fd2c046b-5b3a-46e1-972c-b4deabb7d72f", false);//cbn node - AssertPreviewValue("d9cc11a5-58a0-43c3-939b-30e5e238e37d", false);//formula node } else if (commandTag == "SixthRun") { AssertPreviewValue("194b2c6c-226d-42a0-acab-db55c5cc74ea", false); //== node - AssertPreviewValue("48c497fb-376e-473b-b31c-f7865b7c2229", false);//formula node AssertPreviewValue("23ee05b2-1e02-4537-83f0-1ac8a65bc87a", false);//cbn } else if (commandTag == "SeventhRun") diff --git a/test/DynamoCoreWpfTests/SerializationTests.cs b/test/DynamoCoreWpfTests/SerializationTests.cs index 58113ffd1b9..78e15c0313b 100644 --- a/test/DynamoCoreWpfTests/SerializationTests.cs +++ b/test/DynamoCoreWpfTests/SerializationTests.cs @@ -263,38 +263,6 @@ public void TestVariableInput() } - - [Test] - [Category("UnitTests")] - public void TestFormula() - { - var formulaNode = new Formula { FormulaString = "x+y", X = 400 }; - - //To check if base Serialization method is being called - - //Assert initial values - Assert.AreEqual(400, formulaNode.X); - Assert.AreEqual("x+y", formulaNode.FormulaString); - Assert.AreEqual(2, formulaNode.InPorts.Count); - - //Serialize node and then change values - XmlDocument xmlDoc = new XmlDocument(); - XmlElement serializedEl = formulaNode.Serialize(xmlDoc, SaveContext.Undo); - formulaNode.X = 250; - formulaNode.FormulaString = "x+y+z"; - - //Assert new changes - Assert.AreEqual(250, formulaNode.X); - Assert.AreEqual(3, formulaNode.InPorts.Count); - Assert.AreEqual("x+y+z", formulaNode.FormulaString); - - //Deserialize and aasert old values - formulaNode.Deserialize(serializedEl, SaveContext.Undo); - Assert.AreEqual(400, formulaNode.X); - Assert.AreEqual("x+y", formulaNode.FormulaString); - Assert.AreEqual(2, formulaNode.InPorts.Count); - } - [Test] public void TestFunctionNode() { diff --git a/test/Libraries/DynamoMSOfficeTests/ExcelTests.cs b/test/Libraries/DynamoMSOfficeTests/ExcelTests.cs index 8ce2559451b..ff76d3a1132 100644 --- a/test/Libraries/DynamoMSOfficeTests/ExcelTests.cs +++ b/test/Libraries/DynamoMSOfficeTests/ExcelTests.cs @@ -1,14 +1,6 @@ -using CoreNodeModels.Input; using DSOffice; -using Dynamo.Configuration; -using Dynamo.Graph.Connectors; -using Dynamo.Graph.Nodes; using NUnit.Framework; -using ProtoCore.DSASM; -using ProtoCore.Mirror; -using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; diff --git a/test/core/formula/formula4.dyn b/test/core/formula/formula4.dyn new file mode 100644 index 00000000000..f449996caef --- /dev/null +++ b/test/core/formula/formula4.dyn @@ -0,0 +1,341 @@ +{ + "Uuid": "74dc5996-40a7-405b-9cf2-7cb68341dfc1", + "IsCustomNode": false, + "Description": "", + "Name": "formula4", + "ElementResolver": { + "ResolutionMap": { + "Math": { + "Key": "DSCore.Math", + "Value": "DSCoreNodes.dll" + } + } + }, + "Inputs": [], + "Outputs": [], + "Nodes": [ + { + "ConcreteType": "CoreNodeModels.Formula, CoreNodeModels", + "Formula": "if(sin(90+0)>log10(100),45,tan(90))", + "Id": "b052363d1713473595685d3a3e98a740", + "NodeType": "FormulaNode", + "Inputs": [], + "Outputs": [ + { + "Id": "f20aa4964a784b3893e07b825032ecc7", + "Name": "", + "Description": "Result from formula", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Evaluates mathematical formulas using NCalc" + }, + { + "ConcreteType": "CoreNodeModels.Formula, CoreNodeModels", + "Formula": "exp(10)", + "Id": "cc59376e25a14ac1b0ecf525260c645c", + "NodeType": "FormulaNode", + "Inputs": [], + "Outputs": [ + { + "Id": "f828b580484241adbabe2051fb9bc545", + "Name": "", + "Description": "Result from formula", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Evaluates mathematical formulas using NCalc" + }, + { + "ConcreteType": "CoreNodeModels.Formula, CoreNodeModels", + "Formula": "if(if(x,y,z),y,z)", + "Id": "5d2f36eae692436c9a3bf1d15b093c0b", + "NodeType": "FormulaNode", + "Inputs": [ + { + "Id": "83bf3e348ff640f29b0cffbeb60b97c4", + "Name": "x", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "ae1a51881aeb4f3db71b024bef045041", + "Name": "y", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "a69be81efa064e63b93d2b13a3b32e0e", + "Name": "z", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "1827f0cfd38744a7b593236723a5f399", + "Name": "", + "Description": "Result from formula", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Evaluates mathematical formulas using NCalc" + }, + { + "ConcreteType": "CoreNodeModels.Formula, CoreNodeModels", + "Formula": "400", + "Id": "a418958a990b4b9a998abcfc581f4ff4", + "NodeType": "FormulaNode", + "Inputs": [], + "Outputs": [ + { + "Id": "931d392139904d1193c044d16dc32826", + "Name": "", + "Description": "Result from formula", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Evaluates mathematical formulas using NCalc" + }, + { + "ConcreteType": "CoreNodeModels.Formula, CoreNodeModels", + "Formula": "x+y+z", + "Id": "98fe8b4bc82e4015a978fa632ce0c2b0", + "NodeType": "FormulaNode", + "Inputs": [ + { + "Id": "d490d35ee9854b148f1045df9a0d2965", + "Name": "x", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "43d30f78408543a9ba60ac86ad553833", + "Name": "y", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "58a1eaf88e5842c3892c8dc7c382fdaa", + "Name": "z", + "Description": "variable", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Outputs": [ + { + "Id": "a0340e3d2edc4c45a9636f0243c3344a", + "Name": "", + "Description": "Result from formula", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Auto", + "Description": "Evaluates mathematical formulas using NCalc" + }, + { + "ConcreteType": "Dynamo.Graph.Nodes.CodeBlockNodeModel, DynamoCore", + "Id": "b7b015ddaa264085940bacce73887365", + "NodeType": "CodeBlockNode", + "Inputs": [], + "Outputs": [ + { + "Id": "4acc8087a0f849849213ae17844a3028", + "Name": "", + "Description": "Value of expression at line 1", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "45fd933ae0a041fe9796016487c0f08f", + "Name": "", + "Description": "Value of expression at line 2", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + }, + { + "Id": "74610c6bf1cc4a2f9c7857fa83f83a98", + "Name": "", + "Description": "Value of expression at line 3", + "UsingDefaultValue": false, + "Level": 2, + "UseLevels": false, + "KeepListStructure": false + } + ], + "Replication": "Disabled", + "Description": "Allows for DesignScript code to be authored directly", + "Code": "1;\n2;\n3;" + } + ], + "Connectors": [ + { + "Start": "4acc8087a0f849849213ae17844a3028", + "End": "d490d35ee9854b148f1045df9a0d2965", + "Id": "86daaec79dfa41989b9edc570a3cb898", + "IsHidden": "False" + }, + { + "Start": "45fd933ae0a041fe9796016487c0f08f", + "End": "43d30f78408543a9ba60ac86ad553833", + "Id": "9bf7422ff1a5435bb5aa920515fcb4d1", + "IsHidden": "False" + }, + { + "Start": "74610c6bf1cc4a2f9c7857fa83f83a98", + "End": "58a1eaf88e5842c3892c8dc7c382fdaa", + "Id": "381eb7881e6e438aafecb4ccfe495b7e", + "IsHidden": "False" + } + ], + "Dependencies": [], + "NodeLibraryDependencies": [], + "Thumbnail": "", + "GraphDocumentationURL": null, + "ExtensionWorkspaceData": [ + { + "ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670", + "Name": "Properties", + "Version": "2.19", + "Data": {} + } + ], + "Author": "", + "Linting": { + "activeLinter": "None", + "activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a", + "warningCount": 0, + "errorCount": 0 + }, + "Bindings": [], + "View": { + "Dynamo": { + "ScaleFactor": 1.0, + "HasRunWithoutCrash": true, + "IsVisibleInDynamoLibrary": true, + "Version": "2.19.0.5530", + "RunType": "Automatic", + "RunPeriod": "1000" + }, + "Camera": { + "Name": "_Background Preview", + "EyeX": -17.0, + "EyeY": 24.0, + "EyeZ": 50.0, + "LookX": 12.0, + "LookY": -13.0, + "LookZ": -58.0, + "UpX": 0.0, + "UpY": 1.0, + "UpZ": 0.0 + }, + "ConnectorPins": [], + "NodeViews": [ + { + "Id": "b052363d1713473595685d3a3e98a740", + "Name": "Formula", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 119.19999999999999, + "Y": 345.19999999999987 + }, + { + "Id": "cc59376e25a14ac1b0ecf525260c645c", + "Name": "Formula", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 606.8, + "Y": 506.40000000000003 + }, + { + "Id": "5d2f36eae692436c9a3bf1d15b093c0b", + "Name": "Formula", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 527.6, + "Y": 61.1999999999999 + }, + { + "Id": "a418958a990b4b9a998abcfc581f4ff4", + "Name": "Formula", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 188.80000000000013, + "Y": 63.600000000000009 + }, + { + "Id": "98fe8b4bc82e4015a978fa632ce0c2b0", + "Name": "Formula", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 799.59999999999991, + "Y": 314.80000000000013 + }, + { + "Id": "b7b015ddaa264085940bacce73887365", + "Name": "Code Block", + "IsSetAsInput": false, + "IsSetAsOutput": false, + "Excluded": false, + "ShowGeometry": true, + "X": 527.0, + "Y": 352.0 + } + ], + "Annotations": [], + "X": 0.0, + "Y": 0.0, + "Zoom": 1.0 + } +} \ No newline at end of file