From f1cff2024962c446422e99d992bc593f393b0aff Mon Sep 17 00:00:00 2001 From: phillvancejr Date: Mon, 24 Jan 2022 10:02:56 -0500 Subject: [PATCH 01/12] moved mac os glfw static lib to lib/darwin subdirectory --- vendor/glfw/bindings/bindings.odin | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index 84905f603..52dc10a13 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -4,7 +4,14 @@ import "core:c" import vk "vendor:vulkan" when ODIN_OS == "linux" { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux -when ODIN_OS == "darwin" { foreign import glfw "system:glfw" } +when ODIN_OS == "darwin" { + foreign import glfw { + "../lib/darwin/libglfw3.a", + "system:Cocoa.framework", + "system:IOKit.framework", + "system:OpenGL.framework", + } +} when ODIN_OS == "windows" { foreign import glfw { "../lib/glfw3_mt.lib", From f28c268d97c80f840777007262a0bd43b3086652 Mon Sep 17 00:00:00 2001 From: phillvancejr Date: Mon, 24 Jan 2022 10:03:38 -0500 Subject: [PATCH 02/12] move libgflw3.a to lib/darwin --- vendor/glfw/lib/darwin/libglfw3.a | Bin 0 -> 281384 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 vendor/glfw/lib/darwin/libglfw3.a diff --git a/vendor/glfw/lib/darwin/libglfw3.a b/vendor/glfw/lib/darwin/libglfw3.a new file mode 100644 index 0000000000000000000000000000000000000000..242197e413e1cb6f476b4c8b9b03f7d5b3c1d5f3 GIT binary patch literal 281384 zcmY$iNi0gvu;WrT)HgCvKmbECV@m@I3lnoA1qD+BLj?r|h_s=BftiVkf`X-~0aSSc zSA4u)aHOw`tD8cwe^7|43j+vnGBB9%F)#%DV`P{i$iR?rg^3{w%HIa%pNG;PptOV# zM4c0qPJ`0LP<_2n{#+=3J(Pb2O7DV-zkt#oq2iqU5O)|tX=!1IJw8zW3kC*;24@Ba z4>kq{hI&SZnT!k!9B~W`@lgI+C?Djl1XTuxBB*!=l>RTp!0>~Ig<*pf1B1s0W`+W3 z28ISR7KXD>eG8!K9z*%tpnP`@28M=(j0|GZ5dGhv@~`w=oMK$3xB z!b4_;WT-v?CWt!~ptL!Z_JPvxq5e|jWMF96$;c1`6)%9&9Z-4^l->!YPe9#w8%m#m zir<6MHc<1TpmYV4o&cqnL+Jxh`WBS_45c}^Anp-mU|;}+XEQV&?4j}UPLhG)z%yos zC@7yp3c|02@@GKlT~Jy9DsK&?uR+B>L1`WlNPLG2FfbU*VPY_Z@`IpsE|e~W%J)I} zJy8BeD18=6uZGIsgVJ205c4-dhpopxlp;T%tDy9BD18~~ziCkWWT5`p0F^%p zrC&m6R!NBYics1fO2{~ zN~rk^jF9q!7fMS(=?~ES!o&>8r*hDA-v!lg0OiX-hO8Y?dzlMhYMrin-hSCqA^nR#&cR=;c zgoevYsCWX@oLnf~0;SEM;o=6R&qMV;gwie0@R|vww?OGLQ2G&+{sE=AxFO}5ER;5f z((X_?25L_ll%5WC$2usz7V7ROsQNr8T?eHPL)A@!^4CG>2T<{^P@0bw5+7<%+7wC$ zLg{2ET??g4pzb*cHSY`5|4bZ^bTJ94ZV8m$3#D&DX%VP89Vq=4D$dCUafbqweh4-H zH9C7B>4;4pMf1$oN3w5T}0$TJTd z6nQ0%MX8BUJuazfiKRIuzKI0|nR)53XmKk_O+_;Z+XekHOH zD6!^b79`~-7NsCZHAoyBM&Q7JCJ|@=`z7Y4LacI6ErE&!mw+Q0su1i--~1GWGFU)3 zR-{6cw0kN%)F7dQDefNX=>oS1W`ajz38qREC&5&P7N-^k*Papj(vo15rZRFqf=%hq6F-~7DH5_pLVsd2(GQ&RIGX&zFv<>wY8 z7Nx?4VFrK-FHB=WqNt`q!wlIXWTEiPyp;TMXju_lkds;B6c7OM6(m>YCI%(uA_{w` z;m{&BI5{x~nljx}OQ3QnnE@&mkWpEjnVgstoLPmT9-bf&MqtDmLMlAJC_52cvO}{U z)CNRm4k*gZO)RQ}io^W^4?#>3sNP_3F_fDKQ2^s1ydMnrB1T$(T883oaP)y{#L}GX z#Jr%?;?kTFSlI}c164L*U`c5B!>c-&D9DSDk{J?D!KFoMiOGl%^vo+RNz6-5#b^<@ zrzp z*#Jq{GdVvmGYzHQgQ)jStjNp-Cp>f;pwR{mek8NNX%byE#E0l{0trTF3j<;ys7V72 zJ7`@A5r-%RJ0DrVJry$?LAJQ3mOzw2T9Xjna6znD5TYI&D+t%ZwZOfLV!D4pVsd5) zqRxSs0S*Babyy5UN$()V9+@er5d9F>LgNHk2o@X2VgdO%Ij&`?d9W%uAiuc8HMgLo z5-bQY3Yv%@+8j$tQu9D*875a;l3#>kb1+7rVq{vVQN;zR$t6LcoB=T`7+bKz1;Gg# zhf&B;f z;}-5%P>_?E3`$jbE~z=G>EL!PhANNLoPyLMhIp`quWN`SaYmr4gc$=d$H&ph)h9k6 z$Uns2+21E#CEhO>t7~wo_D{-6O$HU$U}q6)5Q;ju5%Ebm`N`SwDXGQDMVSR9`9<-@ zM)9deX7P+le!<`vQ8F}Rv^PL-EnrM%3G^5ZJAhnZlO2KMhn8Q%pN)T=NIXO_r zB77f|3NEMNR=@*0IJE>t5R}V6eaHOd{6wfJ&`g4yL7<@!mYG_PMHZ4vaY~@&O3yII zAZXS_GFC4)u_!w=B_y??1ZoftbtOfK$=R8C>5xGOaK6EzvK(BbV44PTF3eSWD9X_D zJCX~b2BE8fn1)vpW)(v`&Vm5sZ*Z%~IVTg`uY{;X$?2GCK#>Pa8Iaa1Y^VT|GN2h3 zB85J{fJF(+FF2*(&0-W4(54qwyPmOY$%wk9v4_y`#X3(^W+@?oz zJwy%Ilb{M7v+RN>fHzXG+kv%YgXqL!DsrO~#XM;13ZfCsDX_K`R!LBu0Is{x3qtgU zD~feE2V_uHfyRJ}5iNgMI~Pq6xFE&qIMBEX-UJ9z08W5tUWSV!4L`u54laio^uehm zs6N9q7UE7v;Oe6F8kpX33j8g zr#ZOOuzDO~X;5l$W>sPms8x#HXe@~mZZ1d;*3QMQ8`|JSl|*XaqDUYbwrIhCkbt*% zQ8j|=C2-*fnu5S0=aFBQT7*Lm6z-X6nK)!&nJER`O<+62GK(`2fd?*GK@Gb|Q0o9x zmw-xCP(uI`*ia)tjW&=+ur>(65=f(|D4uaoEdk3zhgDJJAa#;&X-R4Y)E-z0gUE#B zpyzmKO@d7eR0>lM$ORY%`Q#^OV>2Z^PHWcGrQA|Vd;D&*Ppk}$c`@oGt2)Sey7vv-&1{qx4eNby{6bt=> zeN&5JlQ$qApa{UNg^5C~fpDGkbMlKIvtE!soO@~sOa?q{hbHQhT2PV!RS#M&#DHsE zm8mKAbyenOrbdueSP5LopaHFl61`--e6U#{;{30-|JWHA7?~LuK+6t5Q|}B6ObiSR z3Lseq21y16h7Lvu8yoomwCDz;9HfVVfdR$`P5FW_3sh5lJb0E6$^*?~hPXzAz`1b7 zdR_<L%AVWuF>z`zBOLNPKvJ~bmg4b&uq zNTRz>LIfgy0&1Rx7{ok?C<6mG149Ok4Wd;T7#IXV4A5dH1|Dz}NiZ;g*M@A|)0W@qSyPTwmYAO{@t@N7QzpTA`%BLhQo?HPtTw&pq= zhLUI9{yeURw_8uvaWvQQFgWs0IqcFMF5udF2_zuE=-7Oj!KK?>#I^MRNI(QE&>gPP zdZ~`TJ5Iy$Rvm{6<1Niwj-8iXy6X*GTmOTU89y4NfD7Zn?sy5P0TLhsZg$7ZK>0FIz5T@Be>(c^3u-kIus$mdE&88~*+O|1$sI|Nn@n0m~ag z!+^i_2S~+lG!+bnU{CY6vj6}8|0ORtuA?1e9Ah2h9OGjTr=g|~kLEWLo}FJjI)8V& zv2?bxFflM3ZwKXVQ1q-`>5Tb%j2i|G}Biv-22?>DXM$z)+&!yc?v0p+p~4 zK!|mBgG{mR0FfmehX4Oh@L&S@>i+-9AjWH%{fwYo`0X{1N3ZEV9tH+T9*5*(k6zm= zTnr5VCue~5G+ThEUfXlXVh$j&)&u-4pw)36&AUNr82DTMGcYjhXOd@N_~nln>j#k>+R-YVqoy;Z3Zo;_2@O7%*DXq)A`<~^OHxX z?*V98267@3BLjnLH=AR3hzf_JQk-qz1Q%x<2pN>f;&0i?#K7R&`mNOOB{L%fgJYwO3djzR zUe;-xVB>d!D2VY`4Dsj&g&sq*B?Es;HpC?UmR$@C435qFK*7Mk-*N=xkk$hw;*Q;Y zpfrG<5_~$pJN};rN(zRzUz##8Fd%&D(aTx@vcA`JGKeC|6;Bx%7(BXTPk6N6E-`_n zL}y}BqT%hA+d!H@F=4?73N~0`eK`*#-fODB1ri0P&zCKX3=E}$9^I}7x)~g;T~v7Z zdxHM`|L@rRgBhAnYGgfnZSy#hQm+9hHGqtl09A?b2<2}*3l1?mX8xXKpwQ|qy|Q1f z38WE}mb+cAtY9qRI^Hb81Zk12U@DdH=(SbgWMF_LOCiVR8Wj-+kSYnNs&B4WI6!H`Y7>#H*~z59%&>x~RBk6Dh{0GY>d|X^mIG=HShn>* z30r43s4eEvYkM3f)q23EyYxhvbSu5niv>LLTwY9 z7#K<;cQ6VtGrack=r#S#1~O$omh=WLVfb66|NZ|DEjFOp2UIs5kw7Zgb}$JrGjukq zfP%c&))C>D5`C~kej_^s)R3|L19FAX4#ogxhS#h+m;ylBH6YsMIY6NVDuebjIDkr& z=4uUw5>AiK`~N2gfbur9ECf5R#N4;_TZuI+2b8#g5+C8z|5_jFqu27_+8+rCl$wLJBAW_P~LF% z=)48X9v&bU%5--jWluiC{~n!}VP*9#kIw7Sj&ZU77lHCA%$>3zZOVrK!7>X#GN5J; z8{Cy3aZn450mL{AYfpgP2WyW6cyxoCXgyFO;?w!UuUALe!}4&+wT9~d3MCg_-}LGH@A!XO0uuv6 z=i%3)9=)dfAx=ZeKj7@afs{SKiRbkTetAfGfyaku=U30p{~n#+VS(Xl_zmRFKs0x% zr@`VA;a+u2_ex=Nuj4*Y>(-_71Gqhl)D{7^XF%x#kt#}rkds3!I5|Nh0-Ey;55yiu zL@}g2gQQ=ec|W)!DiMqQzZ{fT;kqG)f$C!xc#?&PA&i5D52(KbOQ$7joxhRY1Wq!b zAQJDq5B5;({{<0D3=B|vz|ERUkPV=eVt4?e1niGAxPMX1*YLn$frJOb25?z~)NuNU zumS8Km_>&@^U6SLfEA!!eTC$rRPZdXf@6TEf<#P?VpRnUe}L6gsM+02MA)NGwWK$j{5ER7gop%gjqnQAo=#Qh@4( z8EmX)q>z}GqL7%BUzWoe_4;D=Df}C;+YDR47U+w3c6w7)TE=3 zo?imD7c7LS1IbXZ3T&Fd;R*@KOa^zKc*h{8_>|P7()9TJ(vpJG5||iDqJjw`q8=pT z8W9qYD&p-C6c3I6__UnT;tVjaC_jfGJ;ymGHL-}nIWaFUzeFK7F*{Wu8L}W=p**uB zLm^QCG>Vj8u27PZSfY@TSgeqj4+{xIMsN*=M7(U=B6qnLjo%)RUt7? zAr-WON&%X(5DFmzSd%w2tf5Xq$~C0<4Ajs-;Ps54RyHH3ib4o7FfeR@ipViBFkFma zh4K(eE`SFA7#J81vtpNDzzI=1gMooTkpa}zgYaRb1E?>_z`)SUh+Y2$&_Eso0|Tfb zgw6g09*9XM5DLS63!w7OIOIVCUm&R{@VGCg{{z51JqCt&9P-fNO9sZOAO^+?0Y(8H zc8&>*3=E)gN*M+Qh7+$rBTN7PgTfbN4}&A0KpT@YFPl>{IOKE~7#KhUtO0K!>OkR) zqRz9Ky@#!rwU4DAuD*nUfx+QDL_H|nQPlgQst37a31~d}3q(CA9#GUfH?#CHGcbVM zafX3`A>u1U9Vk9f)On$r3sV1wfq`MiH;8&r{NPg$a)%Bh1B1kOhiOrYunq3U=b^1h%wQ(O!Tw)c4;=3U}}n0Fe=U(N$I z&$b832kpfI*;4@#_f3b;wn{t<41x>{y8pNt82A|&bYF8r_#3$)<}T)jm|FxD4}+?6 zgYu=J@*Gh59v1@x9|MDK9v8%4nOtCZ_y$5~TYWBwx$;~Pb3p?jAa||h1go=c<%Gyr zazf-KI3ebI;ehaWaWH`9Omw$G`I9)H>Nz0l3ZZ<^9&08B22ow8dJU+00Vtmv%Kyp^ zG4BIA#QZ)ezZ1&WgVL((5ch#P&meQBu|fF#Y!G|f*&yyHWrLWL2c-p|>OgzxK>lQe zs(a50QTGB$A7O=w z!UD19CX{~+$_MSC1o@)?%Fkqh*c%Jwi?cx7!vm%NGDG}3ml0y#L@3<~r9pEcAoDJ`BC0|Ogqa*UCIfekd!2BHsu%S8sZ z1yC9^IRz3=fbt!nG-w(PBo4}ZAexJjfq|b9QNMup)PwjSc@QpSfXKt@my0kyv_4RW z>W9@IpgA3oepr2A4pk2;zvZEPSbgLT<3sC*{ZKxvJ^)oDAPjN~2v3Fh1H=U57&N{- zBz(YfAObX^g{*%&n)-EU{9ZIZbcPo`4GP^d2<=`#gmLXC1nnz8-+c($R0x?rMV}i- zndgSB8ive}LYA}_GsG8{6cv}CY^sCqLM$#RN(OB_DK06>gE4Ya^C0d6*$HauBW+}a zv{12ZvII}?{83=~-NyoCwUA3*cNhR_LL@U$=N+znjw!)E5j zP~{0+nR%J;$zk+)VQ_yKR1<>|Gy`N_xB_Ly6BPRh`~g~lDS-5V<|(1+4KybV!ywhf z&I^P0bc5!ZnZe~F!vuZ?22fsMz?>J(&&|!x1DOrN@$oK>A&wvx1Q$TvkzowsgGi_o zK}=9K2h%Wu&^$BDU1iWjKLy&ZgXu>PqWJiv;$oO2185!`)qOYYA(9d-5E?|{cV9|k zNg_xU1f%=+4XA)%0GFL$1w4>?8O+8;5Sj=70X44y>R$;S$h@_LFx(ClFB6&vuYiWv z52$%Fcp>J&+(u{~ToXDkULnlD0CF10a?reZgD?XFXgu_S7z0BAGq}u$&x`XhfZGJ1 zb`FCS0|SFJ%rX*a(72UjSg|w+>5wd(d7J1M-Z?H$>n;R^k8Me=ko&Q=6lvwaU5S1RC$G|4}^x9g8f+pJ_Qnns4UY-M0*8;4dLX2Oq^$n8D7KjW1XP2ZFF}&;pO*UgQ zgC=mdNJWdKAsPK%C#!-wIe21Ffb0TI7o z>raSNaq4>c^Y8!v_=Elb@BjZnEBs!bBd8PEHkV z^Z)(-zw_V!|4;t?{|}mESNi||zt{i&|11Ch|G(t_|NrMvCSoAt(7^%Vaduc@ZUwas zJ$k`28~Z@@4LC(~vx17LPH_5yrGied7+AXXKuM|xBpt)}p~xAc^+1WMN3Sht(gY@N z3YGWh1r>OZNkXvPan?Wo|NjT&8Zg(RleGbsuU@l*g$!>)rwWh<)#2mRj$y(4;RpBy zSuco!W?5}NfO1po{}K&;d5A3@-7vAz_pgOe$~Um_9^JMtAbLvQH{1RP)nj!ohPPi! zrA_eZ{0>ple3;QAnH5|hSRSrb^XO*%!OXzm(`|CYv3cJOP}VBB?Af~w)ZT{ad40&E z+ZLn>V#0COFCdc{7#NPT{(-VQx@|dNe)Txc$^u=bcAS+5$^vTz6Od2>S>(}e3o0f& zTK|_wdvvpVbb`wdup)$1=~Lw3_vi)ZerOCplp@6*IND)l0k{%?&7*+o4`@OuVS~&= zAjbiCokrt-CIME45~Jl*9w_{CLJyO1*p9P4X*AC7`Kqq$2yEN9%!70r;GRM=y9RsoRm`IA~&)fdMoj`MC8!$$gLJgFGIc+>l8U zq-h=KJPbU0fU{8S;gF0}1<>v_g`CW!qQoNb+yH3w71VCcOw7pymB}F)sYR)v(eu1~ z_&6tY2p2wskyw;onwy$e0-lmc%`44SC`bgY)B_ccuwnnQ#GKMpumXe}tR#dKkRaE9 zk3;|ua)ahqGK&>T^AgJvGjqVptuYnA#_-V;Iw}-Ecb({h7NKXRWhN`6f=)Y8$WI0j zDyJ}@ngv>boLB<#CAxi3{i!Li;b-W`Gb{*PgM$2ntQ121y#4&c{UD(U7J~;4C@>W= zGV@Ac6C9xNQ3M9%6A%V9pRtZ>f+QIj!0jsZt{q4U)ISE%pmrBFc~CzZBp=Ppz>vrY zTBHKvAuy==2k{PqHDiujg3c}i$wx5a7*~p#B|H9Vp&V?Dc5|kKuys-NV4ZaN`H4rT70o zDE?5?LC1wb>Ygw#Ff{yxr~}0#iaI2J@Gvqk?Dz#y2aQjx{xAWJw?NfF;}xqq(0N)n zpz5IUi&Y(HG0+33I%qs&Rkwzbf#C#H9Vot0{DI`(D~t>bpmsFKC$RWMA0N(xjQh!^ zLut@BAR_~VtQb3Z>{wTj9o(mpWrxtY&)66kR2dj_m$5;{QD?G&`&FV7Amf9wptB}< z7#L(5pnQKe$oQQb8`zv&eKv3&)>UEyX-6IiP$- zRt5$`1_s?PED(RZh0=#uAmOu{g@HkzfkAg0RD3-P1A{UsoFV+)1uP5R6neK2F(Y8;hq! zfnU+oPed~xJeHqa06TyOws8)+3l4d&8cYgv7aL3l*Je0p&|<4ps9B%^dZ_6rTLU3e z1fXqWpo2RQJm|y+%npzOh$Obddmyt0d6^|3GtehCptfS}%fq@^4`mtzW;?_u2opfA zK|evvCteRRH-d6v1d`WL_P2vK>q93{Kx*8fM=C51W+d^nqEyf!RY*QfFHI~;VTeyo1RYh$0EtCCOBllf#xRF5%wP;t7{eIGFoH1* z;SA82FDOsq+^1-UW1ph2rJm19r` z{z8O6a{(Y0j1Q{*Kp0wWF%UZ+^$@y{17sd(490+wk--a8AYsf$?|h{2l&%o*7>tN+UoOIH>>o9bz6t6g)45cb_M0ertvhBY6KO$a2v9)(Rm; z2GF$M4hcpE&{`2t`xLhC6O=7L7!}V zVGVoOJ3wZX38A?rky60;!gEk%AF0pXwJkb2$ zd~=mDGZnggnt!LjosLSN~L*u&uQQ1E%7qX;JjmVT?GTb>mi@c@16HL5BE*&lGpeC(HcRL5f;@A?V{|_Mk`NS_U{RJZf zLmI!{g;Jp^0TBNKgnzM=sapOMzhFB^{u94oKSgzc*%s|GlBTb2tG4tZ?aQ|2m`W>5cfdR%YINXu;mISe2 zk^<~tofe={2rLO=!6X$pz>*%IG8rrhV!WWtn&nD(hw{OV!;$o3k_Uvq zk}p6zj^NAH5?*$0nBUP3$gD8n8)e}k$V8Sz##kI+9A8N zS~VbYuOV^@sg zh+G1g*M1WsmjULnPJ_r5fO+kp&bCKyKd5Qo(b-!87UZo5EAegc=$3d=(254wWa$qD{?@I>V)PW_2s6XoyQt%m~~2ZJi7OSbbIu+gLQYdMu4KX z^PW%VCrI{Syyw|`jPWH%*6{Xz(8f1I*x?MYxjOKIh70_yx$F!Koi{uhkAN}?(oQtc zdRYda&hH+*rs?;gMRMzb(gQx7-+g**gYJVo3*Q6h!}uBI@Xq_NEoz>f$2=MD`9SiS zV;5V?0sa=y>QBSlHro6xCIA2bx6$Qq$@%~Pza!`(4~Ex*p!&zN`M7{**n)DjZ|f8O z7Eo$*>|%4=3u^b;+lr*yYCP*?G<; zu|&WoqomFziNBTc|Ns9Rm|in&V07$YQGrD z`BE2@a=Q0|5>OX=ugCs|pKQe}ED9a$9^F$xX{@UWl!_q|{7w2y3=CaOpzCMABCPyv zpsT04nm~huFcEvO8qnl4OvD{5(hAx{0kVLVzYR3V*VWX9BoYo*16tGz(-jXE0X1S_ zBI#g}P9$CVU=h%eAWTg;Sfm?CO+8qo2T7zIECO243e(jO7U@G$GaW3_k0df5ECR~B zFkQ>RBA~t1Fp>3Okx59pwu41LOP643_Jc)0Q*khn<6sfc0$!NNd9Vm*`zlQ2I#^^n zlF6Wfy{;zE@F+~pbFdoFc3qgrd$7nXBwe84ysjqD&RLk6|6nz9kko({9&|NNeCs`w4eO@|363ul$21C zPy0cr3@Ax;H6bOV_MK1}kXTm}QgUkF2$cbep(LyJl~5T_QtN6$N?z>?p)w$`t|p{p z);<#|0}|_MLP~D!6QMF7v92bhWY^val>v!$H6bOx_C}}-NUW;~DH*m`LS;Z=T}?>I zvAqx~0}|_MLQ0nHnNS&!SXUEL@@!9p%7DbWnvjxddn8l_B-Yi0lw8{bp)w$`t|p{p z+wKXK0f}`rAtm2-N2m-)tg8tr8Mj+PWk6zGO-RYP-4H4R66nvjxvyC75sB-Yi0l+mA(mi)`d9GwY5?@$ zj_yWKFQ)YXe_tIF1A}MhKcC*^;DuG)J3*ZxpUfAa&X3`3et8DZUK@Fj#^a!>-ly{! zIPIdZ-3abJnL5vhWqOvtATr5yUJ|YZh7R z7wCuwQlP~L zP=A4%zsORy2wk97EV7gmLJHJ~MV0~`WCS%3)P_Ztdc(i~3v^Hu7Fi0!hw1{gV3DP^ zA#{Nnu*g!Nln2!XYQG{&fnpUZ1!|Qdq)IZO!k}g;l5h}I7}PFB61Ij4gBr$2!YaPK zD)LY%P}3MDWq7jnfG5A}8IR5rubH6B!;sDcfS*AHYOkTBU(h*4j-BUyx>Z4APmaxd zRKWdhkIvEq9-Xx(_*+2f6C@1kUo-HxfKGw{aX~$52L2Y1A3mvKV|O#mgMf2|=BQ4G+8ol{hY)he6Zf3@aZXbj-B42T6<*!Nlp!~*s1Uvq$1psu`6<_iHv1_tk5799^(P+WO*x?XTT-l79y zgIdcz$)EOtoCRCb>D}3)1DcBUP5$qZeA~0vWmj@AIlzW`bXQBj7#d*4K2R9Ij06uV#G;&w z0@2@F`oW_&^b1(WCw?v051;r2L{sG%7(Vew9{R+u<@@Cmf8;4NW5DB~DCbBhb$;q? z`hOmDf*eb^x<@ZBXhzuswxGQ`zUH-^;ce(C70|OZUh8=DntERVpJD=8G5P|Ozg~-W z#}~X7=#DRW&D|Ye@tUoBK4^Cae5LS&&Hw-ZfB66Z|7ZXI{|9aJ{qX<)e{g;c3x;+B zn=Keh(i}UlA-gF9G*;5fyBjnD33C=`9sYihlbQLOU6~jdTr7)g_*;H~Q+aWXNAG6P z@TW)bWbo)GH0C`z@4Iw<11+Wnl}50GHw+KJMLc><%g!?}fDZ_K`44oo(*f7kZ~Rja zSUMN*w}2K>fVizLObiT$C)4=zSrz0M7+%XG>P}Gkf0g45{_dnU@?X?{``w+{6(KQ()jBx9egDKlLR&C7}EHUUSx!c zfSPhp<;9;Q()f>FVune9+HzpUOfV5p8xE%U7b{3H>$gLUrAiuj^;>Cn!){Q8!OY(x3A(^=H>lao%-;f9q0q1!)Y4|=ZvkyfY}gHITr=~x z=z*1i+SAPZEv8@&s0q!?-(myifLhJW{4LI44yd8bT*`i|8N^`dbS?qK<6%Q+lyy2+ zfcfBr*?OSF*6^Ea>o*7fsmClggA!%Q#ZEBo(Rm-F4xA!9dQB&sg~q>2=O@&ZF%cvK zIx6SoslWgKH|&1E$iTo1Ddrn?gBBSv^S4|Ftv}rT2qFVIlCohp=&EIA{uWTR*s%Kv zNCxC&5QCx9xd3GK;bY)27lsCC__Tt?&5kvL0*e6_OszNn{r`Wg85Cv=u+VC~1Qr7Y z9Ye!zNT9Wz28)3>3=O*>Vb^*DEC%8*H0*{1Ve4M77>L8rup1PB%=|5zK<5H(0ZV{9 z#{lzIt0pL>n?ZhLXn^{z6|}A4STo403@}f&N`uvbe9Qp#D}M`U!0x5c|NsB}{`~*H z<idSDA` zw-p(C^qTHGjZy9iqgu2ZG?)V~^*XOZN^o!zgUm0Wng0oHzNSa7X(XokdKd+;Oy>pu zeRIH*U(LUnOL<}QU*LW&+-gvH1S(%q?33&K)clX52xQgYQy5;sX%#3Z!>j_a8Bnc) zpYsH=541^u-Qzf@sledTdZ~on12m)n+6n@XXWhp78fFJ(hEijYVxCX@0UPq9uPa0?=om(2e-o#e4RNa9Cw>92 zTr;S40dZb@;umZNIn$&0hy>)w)q^J)7{DW(8<-%1;CP3707=ZF^FGK7P_^y*0!bV> zIYQ>Y5dAUenSqc4WaDg*S@-N_-tV|AE>Z;3JFKiUY6(cstltpa7o_VcmCu_h(DZkb+tZJ*Zzx zc=VbsI}Xo`;K~Q$b7)?MxDuA15lOv-%cHYA0FoczVFuyy%Y(Bi$Ui9gU%&%0vF_2i z9W=j=JK{lYPDuL0&<~yq@7xZe$kGp0Jv`lb}Z=FL+9=mJ5Z;t zli9m_jvc69_?pS^HoPQ*9A%6&T;Re0uJ4I(uR5lCvoPEnfyKQ}Xzm4dwPEg6b8N2T zU;sH9)B`QycJA)61NA|BSvnv-0QFw+`+!*Yryr(Lcq6-C1mtv(gCVX3b*u5a7A3qr zx@AGV#%61V5*bLUR0SRFdc#u;yMFNL{D2rd0;dGD`V6~!^r-C~(BJ_9_aNt2kL2^{8IZ%Ha|_1-76t~4 zh7olCBT9KKhs6XLkM22O6JCp8Bx0lt13UK{#XJFz?it`^KAk&26fxxwD1X7$KY&Ks zp#FoL3UC3bgy3)a#ta%?{@=w8nw=E_otfLKdguVC)doFhzSrYI!%wavMV9?Gs{HK- zK&$t+9q`x*I{gBKJ@^+Nzj|ngkmC?qA%`Qhf=)N!*K7qHdBCsP3fg|fui44~+NG}9 z`r#Mo{DfA}9xr~))(gM>|MxiFy7xC^1;Fz&9WJUwRuFNdCl+93KJ}~_2|6s*nFJPwG(We zXYz56%nu;FV6!|S>!0Auo=$>fe0o(FJsXd3|NsAg7ntAq+@p6Z$SYtyKE0~{_JQ_h zgT3L)_}&p5zpV!U{{Me%fD}v6u7VG*t`!sC|#oJ*$ZaDoD5nzg{2rlERV8wy-+FwUK9cS0g~h|+4u;y%!LC$`G(;BK_a&mFDuGY7fr1E@vh)V#+Sk`0u-dTorMl^?=Y zyk6Zc#vnI=$Cw~vS%;zZ11NkPLm+1~xC!tJvUwbL0}W?0AXR}%kSf{Gqt{e>Hv@yK z;S=z(r13HOZ@vG!5-T;0W?ho@xUqmZ4*GIeCChjnaIDd0dxi(fB1pV{8|S-^G6)~%rC&Z zmL0m53dC6g=Q#2Ux(Rr8v%fa=?CytzH`pZpZ9IYy6Apgnj{up%n$6C@@ENTBH3!s1 z`@2BP3K?*F?Gf0A_`N2A#cQDXIfU0hrog-g+WHM~7|2mzuU%q8^4du_2jo-{G_Qe7 z!s0d1o@cPvM8IAHxoCe^2Y4*^Cu4~dD6(2WYZXAz*SZTdqY4i!(8WYpOtfQz2A0H2 z(0D!~(m=Zr5IzIxhWQMXL(qKogB8hVpaU2|Y9Nsy0rHs<|F#a05jav$376w>HwjSi zg1rS|?eFRU4T*qa46nCdfg=th4WzR|y(NR@t=Ay+;LHR{iy+-FZ-J(*(YyuPQVsD5 zzW^_&q=#@o5herk7RU&E-jacP3&h&r)d8AfCg`nqAZKDG?FlSUZz-U83w-z@+*=^s zFmHVTnS`3fykG}UfwCBA`!&K_3NUYhjKJqD1-Q3Bto>abpy_ePJ)jv;kmoGHNf9)} z4^E1p!?57_w&4@VN!wT$`Qgq2Wf9iR%nS^#eGw_}Ge{ZSPasV&KY@0lAT)#XRv9x= z3e1IbKvAXg+K7J})Y20k2Vb&yc29>Ci9B422frQU2PZ!jxQ9Tj{VtskK-D_9TZUO* zLi-D#`2kK3jKO`#2n4J=28}-;sV8ba0XlvRuaPsrG324$3_A8G&4WMhKpKA%D`>}g z8h;F{7Za#EqH!XPU-ZN${)iK4{F=TGz&hYc#lcEqSmnVqvQiD#2cP)k4nl@|5#!om z?fl`OWB)Y_UJqeHXiP}nc%G=F{}&0G{SYC_#=H^eBu{i1?^E!lk_F87hPZJ1KbO zR~DCKCTHs;S|u6jBv~aH>Lev5XImv%=%f^+`)6+qcW?*iGRU$;Z(kjtV z2W%!nzbRAzY5-IoZh|>Py22{a2*RqgN;K9fE=epZu}ZSksjx~i)~U2gGSGpYfn?>I zn5^I*tPr8Y01KRC3!@ZJU>F!!LMU+17#QeSIAxZ&~Y_pebiS1IH8`R+Iz|G_a@>I0j~>kg!2ZIljgQphRN;N;HO)r4eDVxr#E(7+7hJ=Cc8H8xOyZrca>5Oi(>SLK-&3p27Vf`CGvVn>R=-{qXu4mQx3JRyQ*>!kX0wI+%!0DzI>d zW^$yI1Fl^t%k;*khDM<5U}%(>1fn6C0#RM~xd!9U7|;}@od_xtK$*izHxX2mfZb-L z4Q7`XSm`FB*QL-Lji?;avNYkGU|E}WdSg4}qM7RqBP+V96>Tgtn+We5di=hEhQvu!8;Nlh$(B_aX45-v4TtE}kn=phn zny>{fy-V1^)|)UeG=l~UQV9!7dDICUG8$qus)tOG5+Ndm5|f0C@FyW{Y?%|9c!}+; z51wFxciTxV#te+`C#KP0f(~yOL-HJigb#0oXBMUAfbOSsOi3&#Ni6~;Drk=tUW$^K zsL+dAFdsUCgWC6@QINCq`hjm$x$fq{WBWIR;IvACotU%?r4JFahLUM8qGKpPMSCHV@_ zI4g)zX_W}=W+U2CPytxKI|*I`5;-E92y+{39AXf;&A`+E((N}efuve+UNkV!aSRR( zMjj8tkxYrLm_cES9HL-8qzp9&5B|YImzW_m=uj|pT*Ly>S%w<`jV{z|49msfC^I5B zPMn$s$;6OE1Wr=m!b-=nBC{Bpaly&Rm`a1^knwT2k3hi#^H35Ir7&uUK!*?D20%v} zz=<4O#8rYO7*M)d2B07@#5aCwVhQOf8(JEefCI!3TCO?fCRXL=DfpD;B`Scfo-4}F z$-z?ZnvptU3~kFnMpJO49keN!L`ZdvTFU2U7AG5mrcc0LM;L?}W`<~UF|c9)B^kkU zzBy>Rfp9W1hlUY6%wQcqBE!rOG^R$EK2$!BF7OIXe4DlGvdN5*~|!> zz6=v#jTdM-b8>N1@b!0hREP*L)s0XH$SExbmFB1g6KLv=tN?=s5L(j*njsA#gSD^> zMNAn5&2umVpo5)o6Yv&NhQ^?vB3xg?gDQ!fpaKojk`+`&-~t;uJG*`E6j7Xbx=>Bc-Zy zz+-$PI(!TVS@@9NMnJFclAyT|dp097{a6@7noY)r&_*S=pUFI^x(gtv4-ub`l%4Qg_zgEgaxZ2u%0L+09zjM5-ue}<3-HOSxjMd=D* zdd3PtrMXEtsS40WHDw6{*7`xOp&Nx0W$%ut*D!54C#ZQ zgcf{apUBJutC&p848e&6K3@kKEI>;a3P__{CZP2g@X9>N6x7fL1Kn`2sSkX9??FBpHG{3h}?8 zu}(?>)c=N{)m|X~8yf1sk_jXsAiRl^Odzcqcramx5;PGYw4){xXn6`Z04j^p34$&iy2$yf)x}bWGA>5_{td~qu$5@>JdaPa})DYQi~Lf@y9i>!@RJX6;fLwViqIjK{)`q$$_gf#S$vGmPQlq z-oiq~6dX37@PVceT%ls3pb-#ktVwx~Wr&0eWK}&VU?5c|-f%IYTey%=VZzc2Rcc5q z=>-%v209-8L7v!hk%>Y;uraMu3#=0YX}!WcOhUB*GXR?B;3gmn9x7xpL{cIgWG16Q zW?*1o0$tYt4lmGJJ8&v8hQ^SdupzAD>rtBNm6@mz?B^PcHaq|xm4x*f4MAg) z;7K&?MELL=j%_07T?a#GV+2ve8p4Oo48h}OW}tCKyn7;H^Acu=kq$_Ck?B;LmX??U zS|pC)1Mt8QY;z=%2S9W3pgMureJ&WIsqoMTkD`O8dGQXCVsSkrBg0(}+VX0on^=)q ztYD#=R9aG!p9h{zfQ|&B`2^&6L})^~W(4|T(6u5&I@mlFG7V$^opgoN)dmJSUip=} z&iQ!?8a|pj+8}3CfHv70LD-cbwuz1|T-*Y}28$bl>T#4IC+H4SbdSJFROqNQLK+_G z;50*cJQ3~*b7-3boMMnY5kv(~pr>|7Y`{DLtroC&0-SLPd&0=X2;A3&j|0F)M7$z{ z6+okU=u2h6i<-#ZERDaL3-i?gG%3KD3~v!(1|8coG)soYH>9l4@ySomEJ;nyP;e${Y$$E4kuj|YPezCg2X5;j zGF%XNjS6T!&j>VmG|<(59b}#iQK~@)onQ?JXtNRjz%G0(54b5wLa_wPY#3<@-kyX_ zACBNc+}OeZyc5L~eV3DOVv2%uVo4Qb`T&%q0)qVMGtC4`9)q&hLj;%wto;qigg66i zgb(k*0?fh$Iw%93Jw(^Q06abl9XvoBQwCX^2VWKlIpzsb3_+$&Knc_;$q@Z` z7%anPh*R01OHlAHO8~X}v5aeh)+|CQQ1Iz$AXV_15_2sEo{jCWa4|7KTd?VySecfS zSeyZFV4P7I1MaUo#%#p-QFF>bq;aZ@9Sz(n3 zZ7Lw|03)&i02@m(hvggt=m-hiyS|C(naK)%!EisCK=)9PezY8}ktE2fOjr_v?3#f2 zG6}j$711t&1_MkvG!)?Kq5I^}5(IRt6S8lgaJvYW3Q~+9sldn#GTfU;n^JwRI}hy;Y0%b=AOI7fj~2HyEx(^SadH2ky# z*nF;UW^z$}aei8fLU3kEYIr7iZD>GFX}W@%LO@PpCAdWcTUG-dDuUKw#4ZPh`wBCo zppRRa64(_1ZHU0C7IQ=Bd?UEyXkeh@o1dNtE)|RvJUm@Mkpy)zr22)AZjo0GK->>4 z28h^F4bI3IaR}89ZMwh$2kXKH_@-Cz?i#|Af3WSrM(8`K;k&3EaqOZ7?HeMggoM_( zM(B-rl%f(kV+;2q5o@EN)dw_?4ABZo{GkMCz=5k5{0GBAH=G-x@1mwzFhRFmA=1K7 z2qrUQBk(RHb5rQ#KCJog=j!k7>aPG=C8GdZR)na6K{*b4qlDNThg_@?PVkmSkh4rp zl1v~A!;GOl6wvY%Bi(}hq7qoehT$~QyC_h%8RA`tZ)jiu+018{3JyI3Snt5kH6jGt zx*6;p1Y!$UM3RDL6@&nKoneNur2w2w@J^7!N?AigXagP||CxCusd=D7A%x{UTzEph2792$zQ#VFqg$VI;WGFoSis zO`#odLlellFC%Dmr{fpq>Eh{#+(#-iFw}z#e4;cf4MAtGlGA#Eo-%_dvQf%3v=%00 z=nJ`<32i+iv_ngLXyb{P7AAa+9FZ+d_!d&=L2(8~&_SI5mjH#Z)S}|jV#qufXtNm| zcKE}ZmPu6aF~L^A!jcK7=mBA!fXt%Ayo^MJijtz#+*DAr0(%WkY;l7+)_~eDL>p>= zBoDkv0ImHDO(O7Mf~F8WTMY@f3rvzB?ZK2p$k{RQ(HT&GvA84=v|bL!fE8LuVe>lN zsl325)>ID& zHbU+;5Rq!3MJ{?Xl!&+{I>SQS_uwfkXio&36o^meX3#@upvl2NCm`4usd@va1@Mrc zA#7_jd{`g}v>YCkU9FNpl^u9w!zu}s-a!M(Ch!9`pv4#bP&H_Pz=8*SjuV-5CHk0q=Yc_)IlJQ_x-k{G+C@0u3pA!0o2d@PVWhSokCwz>W@u6_ddx z=;;S^G!0$5dc;hQLd#QVB7&tUSSrFgsDxUT5H3q#VU%nFsT?68X8_7$qhSOsU$KM{ zET4^r5qcOUL#720)%Iv!gXJt(I!ZM|Z-54y4$krjdbp|~^wcm!V~`FdlZ7ShCXY0f z{pLDBiB+jZ3jTRji3%aEpvoVmQwyIffy^O8>i*$#z7{mQ85)S|@Eg>(k+kTN6~QX_oz96Y2Ttt3!O08-6C(o~S6r&lN_yJ7E8(z4$*NZLy9 z05XLvnKpn;MneNAF*B=F!8boCGY34pf>JDzK5GN*pbp8IN_a@Yj=F;_`Gtp6eja4J ztspT)AuYd1As`sMFmp6*!LJB}&Im$6EI75OEHMX^`%qF9sCP@w04}5li>S^a{e5UZ z1G4xP-pe3j@*Ax+09`Z$Hvu{VfPHBdc&9eu83II#g0wFU&5XgrL(ta1X!yVy1jYv7 zZ~>LxAPfzk@XVZ)QOR#l$&~rCI;R41wL8+kGx6Hh3a>jijnFc&04Qgd# zyO0I7H%@rO3&WwXkv)V%v7BImHqHlM<^&qb1-Z-$bnGwed|A*b!r*nfy3ot%kV^sZ z_!vTfROg!|K^CAH7#hHu?9diOYFU0xDR_V#G=7U^;l)TCdw~U)p)s++HBg6Z4Uz^J zY@JwIY8qN0m!F)i;GCG30$KNmXjFg?BSWb&M@Wfh3~i#Cz#H?BoEV&#SDpx7A?cr& zlbM%_tGx=D{Xre$hK}CjU9f3kXb4_451-Ko7qkWjI>D*wi3-7qC8b5+Ln**z7N~#% zH(!##=k9>ZD%71NAQhmIdPB&hGNNdLv|!*(49rFfbjTf{13Kmo*8-oIf?Q$(9x64% zcLaD6^q>TTM0l8jJ%{Wy(574P(o^VxHYiEY6gJ%e30#EJAhQpsfsIxa!%vt69|{Am zN${=}gx!{HWC*=28|+k2Jb*96^~$dVxAs5{0&trfwi+Kc@d2L+A;oQwg^YwR!Zm=L z`D%~`PLoiVffg!*D>ram7m!~BZmodR32a&ilp4V4h4fWsuqGEBn?uTCo#2whluY_x>ozF+ z%CJon7O9Xi1V|8p%Knnn#9W22%%T#|2~nV(G}x*sl3GZhIvY`uLApfXn#Brw&M&;a zg;aWYD>+yp4cTo3U10z>04fXaaDi(_aE}YxC;?ZCgohDe=K&fSKzl0STn7o7)STed zqRiA{1;5PPB$O-LpgpQ2P{@Eh4Bi9`>rf?uhxR~?6iAx{Jv3nMhlU3+0RYzm4Fc>V zCx%AE?K;8mGql##2`)*cf}f$|lsMKo!@Yu~9f9j~5V#(!-mfFh*TxnQZ^C05!ZjGC zzJ|;O8JMJ+S(>Go8JU}!8yg{AZH2|xICj*4*2aKqVbDf*_;yUt4sURtvw}>kfs(tS z0jxa>+h_=HT%nW$kZb{uR1y*bv>-uixnn&j)EItBjG+l}2?Ulc49)Qr1;Hgni6y1Q z3K2e__6oE$PqX5H+zbIN14%6qU_Lj3jm{$%2*c9nCZ^`#jACR29|{B)3p&A3zLB~C z{^71c3IWc@9XOPx*6>-95AN^a?Z}&?LFP*hO_QK=&XB57CnTe&w74WUvA86)2;A>c zaLh~0$xl}>)&n={!I=css3$qZK-DXH4GJv=pj}gVL4w)mhprk%=!dPYhBPS97f@j@ zNKkeg8G=^f5fx4bsjwkWNTUlHPQH+EN)0YgEKmR)pfo!62~J0_1aUYnwoFB!9SW^dh+L_Q#g&k9l@wP( zt5wp+cA)c%h?pdG-U7a$8tiCr_<{+Ykn+qt@Q@zzco}%9F)Z#~AFFMWX!@UXh8*&-|w^!i`;NyMZBu%*fgZtPVQl1+?ZwMV| zA4B6Ay)vY_|IIB8Ateszkgp|<8*#V=*hZeeUEr>w_XvQFA9|E|oXkcJ!Ze|JYR;8Jnn3)Pv8tAwmZ2Od2C->5ni28qwGXO(0RtXLuozbf}{ezLWgTv;m4NOp5aH9dGfErM+3}=uC->rj`qQJ8s znPoVx97j7Q2Qo$lDRjZpBj6&0l#|4u4ULxKw$cIb!bKqT=N?a;~_W&m2r z4m%MNd%+HwdnPFjfNKX zw3P}y91ArQf=Vj1_5()hB6sfrbmRh&xFEfHXr&M7FTy%=q_?=x<_eM84A4D{$fI9G z?md8|EO=OGNSWI#yE9GU^q zo9z(Alr-C^Qo0+OLymwoF);=Y(i_2sBO@{s^L;bHQ?_V(s8QOW{3MCnt#R|oh#U-h^aI>;gD-~2T;arFr z(92?x#GzIe>>0i2MAr}2%#mMAoOJ@{lOW+7juQswr&tQ z#T`O-dO&DZPYBKG1)&c>>1uBXU)%>mZ-&yRd?Eb1eh^wP07AP4Lg<1Z2t7L(LLUr) z&<{f)G-Eh~mW+VVf{_r~E($^$MMLPs7zkY(3!&G=LFfnZ5PD?-glKFQh_f=5z>cmI0xoG9k1}7KF~shR}UE5PDlKgua;vp=ahp=rer+;tGzrXE7)HbCe_jS%{J z6NG->459C}K^Ts6-&_d2Y#xL@ zHXlMiTL7WC7C~se#Sl7Z34|_N3Za)QgU|<;L+IBlAhhTz2yM0+LMN<&(393e=uPV& z^riI>`uzq7J!2z;4&MZ!+crb!?OP!9!>tfHY8!+$-43B2LFxJ(5WewF2pzr)LO1S) z&^z})=zDu1^v`_|`t5!Q{rCWczIhNrvmA!d|Dg1bBM`pwF$nE_96~ppfY7T>Lg;`~ z5Ssrqgf=__p_R`<>2nZT?>vP52BnoRLikRXAawR+2tDNrgx+%%LjS%7p|x*7=#ZNb zy7m@?UUnNoU%3OJneIVoz55V4>H&mqdI+I6J%Z2=9z$r(rw|%OLX#yUj1Qxs$&>+< zT@x9ZG2|JbBBBrtP#%N>A{C$_(Bc)!1Ia*e0#pQAoI-gJIS{!4DuT=W3k2jpK;=z9 zhB3fg3*mrB111p3z#s&npsFDp5E%fK7XWdv=ud#kLyKb!{Rg1(?o12}*uqbM6=Lu* zE(V5+5v-W{`62R~n6S$?Kpj2YQ2bz%UjUT{6{FbX4a6Ys zd%?`Wpvb_4VZMPBL|y|zVaO*y<)PIYhWr7jJgAz&X1{_o#9&bMf=zw`R321KVUuT& zf#`=;R~YseK;=Q%6`TG5S%`j6v5zhO9zf+m*%@2>ACQCS2Nl=Y&1J$!&DVRF9X4XEIerAw5P#LGe12*nIv{=S! z9;oT4096Mn*TLqwVcH97Dp^3)LF-?v<~?CxU`T+f!)GrKBLhPO5$a4B85jbf>Y%}k z)!rCJ28Il%I%qYARb2}s!hO(s8mqcBj0_AOQ1hVmHCA<37#SEEpz1*NHaPsy;zNgl zf#DA$1H%eFNPK|mZxnR_&FnpFz2LY5iG$SZFflM_NJ7+u>T{4dJUw_}s*hn}VAvrI zQ4gx$QPlgQst2Wy9+3HR5cQz?9!0%VGc$+}Qn!VPfx!W)4xT<>{zFoChlzn90;&#F z|AX|y-HW7-g_(ij08|~Q9e|?FxtXPp8Im7#m>C#mC_&r@&5u~aKZKcqVF6Sfv|WHz zT@5n>!wsl9Q2PMIUL^M|VP;?uP=?qG%0sx+ondBRh=8gCwHI)y`vP(wR2{V4fYp66 zEDQ`Upz1*F2Nd&MA@Ko97cMLe3=32s?gP~$DC*GC1t|VXSQr=>R3Yj??Ftn2Nae*G z76yhLP<3;_iWm^?L{fKzg@M694PqX&oqNNjD;_3=9E8 zsIy^ZV8|dsT?#7$Ljw`&dRQ44W)Pun3o8S|1|rnmVP#-AL4-OMHU@?VM5xnYV_^6J zRR?XaU=8OGHUyQ(3#dAb zbckf{7d8fl08NN__|(a;GcfFcs)M#~u=>}9oq^#3R2`_DgW?aQe4NA1!0-dA4p;gE z<)FfiCNFxVzQ#e+;37(5vmblsui`cQFc69xuW1_n_P zDF28t0|OHSgXn5w1_ovZ2GPY(dYUoB+&*K7IdxEVamEmP%#9)T^Fr0LLg^ny5Pgq~ zAm-hI(#MP-=Ik+o=wDz2(Lc$Efx(4=LAM<$UIG9&WMBwoV9@<+ z$iTqDz##hCkbxnDfkF2fl)n;6t3cJsL;2!RbwW`783TxZUjvAF9#Fo60mM9ODF3TI zL|vIaL|q}2pQ#T~mjdO>LFqGk5cPBPAnK<>`Tcqj^<7Z@M_q`zgSrrPd!YO+x)62i zp?m`!1_o~i2HhXpkZ^hgr7vqk;_rYqBpe&HA?hNb@}5xI7OGAQs_wNGMBPCxh2*+gB9tzH(!LrD4Dk#Mx|SLY4ABe>y5brTcME7RFhnpg z=-yFhV2EU3(A}#J@y7}%Jwcs;A&P-P*Fzngdvy)e85nFB7<4D7LCgtOgP3Eg2GOUk z2J!blRY*A9RE3D|f$}?{{7NX_9m*G1g@o@L6^On&Q2K%j#QeP~5Odm9AnIbE@;*@7 z0jf?Hs_v;WMBR2}hg;407y=j=bk(5hg`hNpEX19sWf&NO z85nd|%RtKGxlp`RkjU~pw%&`pqm*eeeeKO+s{?}E~6q#@?cl!oX_go^t^ zX-BBMCRAQZnt{QMfkF4b6vUkOQ2L=1#GI2-5ObzM#XF=J7~B~cbnB!b`qH8D0Z@4- zDFy}~1_oVosQ3*Dh&dM}Am;Cb^0!McFa(0~qXb0#8!#Hso-PEjFF*)vkFF_{mV?slQ2K)) zME)w2-UX%SL+KVMoe8D=ptLcRmVnZK1t8`;g3`yK^cpBV5lWXq>1ZhJ0Hyf_Am!pk zeu%p_@k7e}NjwY;K@1GKGF%J{2@DLnj8M9l6T<(+!N3s9z@Yn*gMlFi6dxRra=DHJ zQl6G^K;j_-sxBGIH|Btpt2!Kz_!8iNl-m#4A^L8zL-b9A@;jmYVkjL8rQM;l1(a5T z(*M~Y`X58-<4}4vlRXDF=(r8%MW8)k?(=b`i_C_NQQS3v1#C~XI&*}$V2 z47zWa!2Xa0ja7i!hgX>(>6eQM9Phs08Nsxz1H}Do7Esy%N^3xA1t={6r9tyDtPBin z98f-}Q3>MzU;*35_5n)2fYJ}3^bII|0ZN~M(g&dQ4k*0=O0R&@3!wB2C_Mp6cR=X| zC|v=i3!roclm>+}$bAt|egKsAfYJ_7+5$=&KxqvqtpKGZptJy#=77?mMk&brAIwny zLut@>4@mq0lz#(CUx3mlp!5MKy#q>bfYK|V^a3b714>VT(j8E`0ZN0?1IWGtC_e*A zCqU^4C>;Q$J)pD$l(vA<22ff9N-IEV2`DW9r8%H9sPh1__Xi}sv3-EjFQD`TD18G; zUx3mlpfqS65Tt(xl)nK=uYl4EpfqTl52S7al-~iR8=!OrlrDhM8BiKD4++v20p)|{ zEkS$_DBl4}TR>^hyeCLr1Ikx`(h^Ww07`Q}X;3E$r2YpZH2$IV3n={nO5cFepm|x4 z`V&z80Vur#N`vNgLGml0`~^^Y29ySkp@ZZ*p!^0XT>+&FpmYY52F)Xb)JH)10Z`fl zN;^Pl3n*;>r8S^5Xr3CRUjoV(fYKaL8Z>hZlK;T~^*@w;0i{9H?I3y3bUlc^02K!< z8vyY^%ML&^X!!z&1}%pG(V*oNAR4qB14M(Cb%1ElygP^nEi(bppk*o`8nny>M1z*g zfN0RN8xRdzwgaL;%YQ&LX!#I`1}#Sd(V%5bAR06-45AI7?gRDbL443O9f+2Iii5_{ zL3|Dsh&p{@(DzP${`R9DsMnEs9XWjpz;GmgUSgI4Jr>nG$`MLXi)wJ(V%<`qCxo;M1%4r zhz8|95Dm&_AR3gPKr|@dfM`(u0MVd)0HQ(Z9YllDHHZeKUl0vSryv@X9zirH-GOLO z`U26QbOfS7=>zVBiPMmp~_Irm{o$uyqCAj0_C?pz+b?Ak!EaJ~Bh(Ve1kS zLGp|Y4507>sW{C9kq4!J5Fa#G0Wu#{UV!+ZWkw)AC|p4N+fenO@&?3T4mBUP?!y>r zKB&9{$%{edLFFTe4+@!`5X?gPISU=az=@ zVe{Hsq45EmhXySl1KAIo*S3Y42b;$R)juG4*t|1ndL6`vt+UXDs)w!H=z{WL>oh?1 zDo8zS-32JWgZQv{TwSPtVe_u%q5gx-)8<0m+W?)H1}z^1>4(kp^Fifd>q;g<(;sY| zLkyG;Ti3u2H6Jz)eG3{suyqxsQ1!5N3ZP|SAp2nJKAfQPuyqd0p!@((z%Vc{?1uUu zwhrbURQ>{VUcLsJ9$@qQdQf@Tx{cjXK5U)EbtoUUEWK}0(m|2L%E1xbN1XgMeHq;@u%dBSLXP z&Hf-XK4>l++5AUn=50pfUqkbsHl$txTMZ)Q(bT_0bI*M=`$5a`knMLtGyfEt`GIKs znP~PcL*w_Nsc%8EpNj!CJX_GzzebA>UNrZmpz%MWsR#KDgh62g!mMcObI|w<@x>)Y zdC3Kp4Dq?CxnMdzJtwW)6SO|wJGGJl%yUmIL1u?!=B5_86{QxIrsgGAGQ@+`1mq-^ zq~#aox~G<4m4}!FJANvlD782>uLP+9Rwx@Rt<}V;M9_!#B#8_FL<{I*w~y@i18))r8&qh3r;S|&jE?V7ndX^ zXU8XJWXGo^W`ac^84@IftOMpChWO0lFwkBW*PPVc)Vvb6{33)Dii-mBb8^t6+=^0D z(S#gxa`KbW#K3_E_KI^(W^y*f_rc)8z&SA|2fU92Y!y5`1>_fF%48%K`R1o!kpSmn zaO`2#gdqruM+`x*`yf$)AqNRw3}KizF(jOGG7FOO6N^%UONuh{(xKsw6tx%%Ksf?b zY~a<1O+i6oQE@7?FkpyJ%gjpw$0l3^9Io+cxrr5NP-n!a!IaOa7khb)Qn(ADUM6e%bRf&{I zA%b9sBiR?6oS2uKpOOlZMYRzkmR6LCFw8r(5~c&w?I@BUqk>aQpougEVFZ#0ieuoZ z)HffbIvy#{rI#iar9eE0ntOv`d%VybL!2r|)VSp*mlmf&jfbT@&thn(GsG9ACW0~_ zLwqun2D{oh6;!N2N;uCv(CG-Nc_ofTsfiG0B89tqsHY2>^HAy)usoejpJDp2Z8HLFR$n(jm^k0BQp>urPqSf)Ggt z28Q@}(D6b=i8;^(isp60NuPbQ1hV6 zT^VFx21AsCh6|u92o)cnoS$2em|PNHnpd8gml7ZE18O=$Bth#*q2__cD?ow)0^oTk zh80qfFlPWyuYhDAI6gi#BR;JNlxx8P=1Pe2O`okbrfiT285F3QK85lrAQ6MH5 zgVvXTy}$u#(ei-Z4;ou4kY-@e2dyWSV_*P{5py$u=dZweKe2bsG2AiCG1M_6*rWN4gk$G7&(8mi{}>rq82DR2yPq5z|1p6$t2kw=`H0X#0_mWwl4?JCDx$ z9=)X}JbFXVfCd8@T)JIPxODrTInDwK0|t-I`-a~PFBzT$OL}zP_vw7*)A`Eqq^scp zuuymDh3?QR9-a5Wyw~$OFZ*lx)WOpCP_|}tkp&s4) zAf}3dw=WqUNP~IW$I^zqq`;&30EdU=q0*19wLChHdo&;CfZ5~GD{}V7|Ns9zI*&oz z(hYHoPp1Wj?Ij#Oo&Q}rzx}@eje=5;09czx^AU+?#~8<0$2iCM*ux&lCqV{-BE9+G z|4y(wJ$g;pJ(`bkcrYIK&^+YPeCP*6Cx#zqy_K*{4JnGU7&;!9N^LU8>(wJ zXv7T02946f*r1VHFq=R80KZ@}h|4e73{vgUy&E*#2A1^b-VLHbn8Bla_Xh?B1~40< z3B=_WYzC?J=-v$)(*;X{l1lRtj_BBzAfFxPmv>+QIm@GSJ7~Bo_AtLZm=8+7!2yn) z*E&CYcK+WF$`boPOJ;2{$3li)+?2%l0#G@Bn?(G5!5I3CyTIswOSwoca*j@@o7ovvqGyYoaGJ5M?`|N770@`izdVHarOn&APD zPS*>LJ3ws5Js|S661aSD?EK=|`JwZaN9PTX&e#hc&4(pCn-BiyZvpMU>~`jG(Y(-k z@cT`EpA(MFzyFu;cRTaAXx`{N_Wd5e&j-ejj?MqUf&wm@Kj4Dh%-zK-+O8+~*B{U> zJ;T5L8{;vT?qU&_&JQk{FFKEZzt8XU!?F4Af5-3FT=-qTTVCXED*gZee<`Pnx-5U)X`9l;)V z+z0b4q)>G1yyn>X%dztenukj^f=WmRuqS!DgLzyuZ*^V-`TG>qi@^den!h@)f&Bf6 z@ng4fcQA`~=?VVz-?T%|@UOqb_^G>Er1J;JgOIQRdGPyne%F64mJf?MOIckkKNU5( zSUxQ6b+P z>1OM8XW?Ieuse*!k$?RK%?qX6E}92RIlA3NwB1Bv4|kqG&J5uArG6c1Fo$H>Uf%&7#*8`FqJYl zvoRvO5u9Ix1CE25M-0#cxY>fCM6kO9RMvO$dvwnLmGrL#3~%peWME`4{06OtK=B7E zLXb^^mPf$>NG6Fk?*N&^P$K8i-2gJmqg&#&2)b#nnGA1ZGZE}QkJfJ`Y@h`UpgQSN z3EOc{fr9K>Hb?;pcOZld4}To`TThm-9S0Sb48E-gO4uDCJ9m+sj@?*9T7j3xgxn_s zasfwoJE$b?WbKJ-hdVXb@)b?A{M*pMcr?;RhV~ z1=~S<5DilA)A=9fR#4>%nm}{xo)4P$2G{GbhN@@hF>pf|)S~{(FTkqI#K7>GKhE_E z*a@zNZ_~i})urHH41)uZ`{22z6-C4D%C1tXP8 zAs(H-eR{Wpg5IMW5o5$RFhO04Z(vIeZ?_)sE~6=SRn|;O06Bh7wyO zS9p1V8k_%+LSq{wG$7t-Jy2rh)A`+_^B%|;a0}C;*A#Rn2|PI967T?li+~u185sWm zudiodXs~DaUk^Gh#U6H|PI_W)ZlXdNXfz6R91W^)QDSa^LUCqQD(LVUP_r3=*>LQ4 z2d!HHsQ~SF!nR)&wC)BZ4{j!+PPKr9;q%a-brab3!-CcYffRy<1+bY9T6YAJ2Ms-7 z(+^tr1dC8~~LEb%3$?e*#n}v8Blege21bAi@#kM85mA{hWH1X&#?L@ zhmnEd0}<+`FfuSme1Vt;&6ils+r!Af-~d$zJ!T4_4$0q7K>MPh>M+bhQpdx@z%T)- z4w|13=79qNvj5D4iGg7SR2?+mVpRv)kNg0t4tgvVR&^~*3=9%qA^yc@?;0is1_P)% zP<{qG36>s^{Bebefx!c+4w|pA+6!6>5dc*O%HO!mQ(e3%&+8ldWy zgB39#?1iQ;P`WN*W?2JtV(K1ZlOK?MJ@w9bzu1 zJU~$o-ERo8AG9A?12hQt|NnnbxqwaGL|z64DFz1JdMKUC3m(4}P2&Zp0o`C;2G9~D zT?1b5_^_=oRNYS=i1=L|1_n(A2HlHL`Y4oM#RE~_0_E56KWp8G3N>w#GUK8Aok4VVqj2UV9@P^iu-aw^gD7fFz7Ha=$b&vX<0=s(76{3 zy24O>k2xXc?Bj%(GZV@$hw>w#d>1HR9m;2h@&1V3Btf2`x<z_dB1~lISqEn#apmP;Kd}}CQA4-F|5z-6{x?dO}{&~yDz@Wvzpt~8gSdoE2 zw+|{_0~H62i-N)fv|blPgL*Q$3=F!U&Oe9`I^#l(fkAg20|RJ@oG$2iG*!^P9?)DD z1A{K;_z;k~;j*3+)DHly--NXjK@DxtdNx?Q6ttci#6JKYb75czgsx|VwM&0P*XId9 z+mWDh8KfT8?ggF60p>&XdxAQoNUbZS&J7o1*Xzl~e>>|rYq3H+h%RrWw zLvs%(-66||py>xK`$U#cN7E0I17UC-2O<#b)4-GB(5Zd!L^Nb_9Xj#N5MNlFUj$oF z23p_Z4(fI~78NB{!d78{m$;w^gO(70SMz`kgsFoqUI>P*t$;5yL#PD{ft>_XjV1>* zIxI6KH6OIz0Nrr+)DmPl@N{ocDzXsRbZ5{sFseAzl z8aeo&IzT~%st9HVrVKa$Q5AztL|xAXRe-W&3+iTEQo*U9<#D-*L5ZLRT40aET!AVD zH3uAtSQNXXm;+KAoLU04)ET~FsUW``wv2{^H8oIU0x~L#Gm{f@AnR>VoC;ry;|7{& zhbYKR&CSg(L#$1KngUt)0&*ZC*+7?g1ScovU|F^U)rhJHW#tS!?LcD|7J|qr4JzfF zk)L0TNNiY^pn#kP3wrp16Q~=)^NX?*!3$B)y^mc%a6wLHiBkY*&kCvQPs|J~OknFz z%1U#x6Z24(pJ1#%0nPS<$B2;DpMdH_P*H*nZ-DN5fbAcE@j=xG2t%4rp!Fietv@M) z)`KAPKzbhtLdQZd)}P>CF9I{?2-Lh~(E1YQ2Wa&S<1!FhFX8~}xI+uq0)BA2ogqVn zfdOhXijjoYi#YH>tOo7V0rX&z5GJ%<1auA&X#L0vsQnl;rP?p;Knpf{O^>sJ#lVVDRf1PdNc{f~8Tx(+I^)cv z*Yq_^yobFe=^9^tp`eM5q^6Ca{-DDN%|~GDWggwNC%{G>Zw93tQ0DSz zJPg{r1Di*Ax$!Uhd^L1f-lKa5B=!6+fzDjU9-h$n|G#PKkvg4Tf9~d=0_8EF^y<;e z3fk7}(JT6ofq}sznWxKx@nY=%haSDGuh|(G4mbW6HcCBGFVXm)ojdhNiA&>ucdgVT zr9K|Ltfx4@@*+m5M@mc}W|x|H^s+K?g2frkQjhSrfTq+M|Gz#v%eqtoW~N6ks})F% zM=z^B$PABORv#$e0c58~FY6sP28P2Py{zk@G-yj8h!5Hd2%?3c;&)jg>gu3$0F+jN z(kUzu`DQ4+1xg=;(x9!@AoGks_JWS>Yxw{Ff5-p-|0n$a|9{5+|Nj^K|Nno*|Ns9t z{Qv(Sv|{7H|Ns9_{Qv*I{{R2~7ykeMf8+oE{|`Wk{r~^}py5u$lr3ca3p74J^QGM2 z)i{v(X!tw_ID!oipsnA5%)$F~gGYoMo9!7&j66I4?FSWP5Dm9m50vP8Htz?e28I$< z$K&8J+1((n2Q#?P!8(tFw2%fmKMyLef&-9ka`Nm1E!II;)_S1C0lfC?o8$lK;4-H3 zut)2GQeDvE7*PfWpU!UxbHUR)7&E9yGy0HuPw@O6DE)!#2d%b)l$6cZ3?=4{o!2}& zzk7E6L2-hOM>E)a44^#p+^6%OOXnxhBpGPU7uZs0kiO>e=rxsOM=fm(55SZnEg*u- zXTjF{1$cnEgP{Bk+GfV!*j&rNP~zdydD;`Zb3B{(f|NprKuRA-aFpgBPhPOv?whxIh7&IJKi_UJ3cotIlmZL&^00?J~y=_F$XRfT$-Gm zT3pQFsF0SLmz=7QU!(xBDI*aQh?S`&3ZU*+PHIVN3WK9Ud17XX0w{PA!MAb1l);rK zWP)z{NL45gEmBkWTYzOd1i5{LS`N)0VS4XCgr3ugyiQd+}R4St7sqzg27P%nqwgDRmjQDOHVCQNGwat z%t-_}#ZjTSJh31-BQY~iAuk^$pPN{coRL}#_7Kc~0(hCBkXn(LT#{3%qmWcuqL7@J zr%+synUkZCl&Vk)+US6=6cne)8Hsu6sh~S|6pBleGZYdP$`e6B1#&&q12Ah5L8MTg zS&{*<9_Bo7jHF~17vv;Xg6#o?cp{SXQ((m+=&Bx2a26-#rYb;_49K$znYoGSsh|{< zUs?h-4iUkiRrdMipiqJZeR6(YUTQKZ36|t5Br1eu2SdspZ;v1yQ1q7MD-`GFrb6Oa zAum5q7n(9013VcVK?@!-Q@~jUWMOKN0=R$&Ww})F_BYp{ApamMg-}0lKmTw)g|JW` zZ%01`uqeDth757RqY#`9GV}8g1uCQj1Di}x6UeWbMbJovdbcDWlH5R{m7J3aD!v>8 zJQa#lOF$KYyN_FVyq|wO$U~@ItTG(y8$jnGfK)<{r3W>LL0mWnou2^WK=<2Y$b-(M z0m*|acu4CV#D!zfIS(KX=$aX9^Yfr{cR=!>^Ng{{gU$s4$%C$!!FHZGsMQaW2VD<> z?Yw_N^Y06w^U$F10ht3oPZ`VnA87s^HopuFFU0&KSTlG|jR7?O{sKA=4GlL2hCt{% zJ(4=m{5x#E6&ik6%>&K9TR`VMLE#8C0ya;HH17$Te}~PFg2EGyH2 z1!B%@7Kk~W5Wa63R6ZEOw>5>zt3$=bq2jxlA@**D(yO8LVkkWuN>7H;-B7w2N>@Ya zVkn&rrIVpF=-e!jzk{KCZz$~yrLCc~F_hMZ(#lYp9ZJ7vg1GZMl->@dLGyh4pz}?c zAmNb9#K6GIz@Q5n*B4@7&;`xw2{SP0YC+Y@FflNI_~KALCzSt?5n}#UM(|xMx@#FB z;W-Z~J{?jL=vFZ@Fz_)j=z`Au0mW-1R35Yk0OStPd>}|%1}YAk7X*oe=CwfLpfn2# z570F{ApRl9MkrC}^+CFzRlFd1&^1zm3=F!UYp6hc&^20I3=F!UYrO;*7<57Brh~*m z`JID-!4|Z94>UyyS~LfuL49Tr4O%J-q6wYD0y=-jg@J`Z9y-4SD+fP9=i|V60OVGv zJggk`g7RVI66jhk(EJmuoCA%6f%vd;4Yd6S#D|rWtx)~2aupQJAPln)wEYE{zX)wU zC>f0p+P{XZ9<=lonLi6ny)_yi)Ez=r4?2$tnGY%(kolnNjga}!@oV^qG;B291>F3F zo+<#YbfFtJp&F3J!imrV8vMr64FmNez$4!7sU<q7;`D zfj6h8wgVa32u z!3A#XfX>+k841TA_ku8d%^O^XFatb(7Zwa&{O!@*4m!@v1GIa_r}KN~z5f?lZ}YcK zVq{=2y!~1TJl^Nge3;Rr@pmjE18B&yVUHYW4-8}J3+VP$u(r-ah~2HP&p9^i16P72 z<&F*eK-CW;e+%d`MaPDHpt}|s`CC9&8#*@Z1KqgD$ln55Y3JCm5463Ek-r6WUY=va zK9B}R{ua>XdyWnJ+CVFN`CC9&;W;+!1Kr5T$lv;!0W^&HeIF=7LHlh%i_Sr{34>4P zccdM-a7VOO{|C(ud^DlrfN{A?|MVfJ%eX zIkGgwBdws*??HxxrizfIAwFvbT@nG322JiEOGCWcBKrUTe~|YM!^WrELCY#Y@x~nc z{{iw2F7WuMM|V5u7)pHdpkplY$%Brv6r789R5sK~`94>~pzr~GkuP-~9Cqq`k+ zswP4iY=4kPXSql0VaR?HaC(M~2YWQW0i8z*9l!VJX7K2Az2F1c{Os6l$H3nLYIZty zes}Er)B2yk?;qFxAQcQQrnSRghn^H2}&5EwHTQ`6i0^O}!zzmV@)&pRM#Bt{uMh9kw?p6yhUn7mb?7(OKdglm_ zssBBCw}L$8(K{972an!fQ247=O!3(41Z8Z_vbL z%SKRZAH3}xe2$)AGpL!sFW3xPeaA1@49Z3Pg3X}J2-;l^T6!kf49XLr4eFpp(#M-Y zi3C*Y@7Dm$7&C(>pTM?zSl%dQH~bG_LxXJxDC#|!L4^b0G%NVK7Y}pvl-N1 z1Doy~z%S@*z%S_Rz^}pT2GJzp0p3>&YSVahI%^zv2AvAaaJ(55gP>*A$D2VL!@*{P zCUTHAK|=flu09a6f$;JMu?JDB^H<}41_dUDdi~z6|L_0)Z~n<&?(Wem3R>R*or(Sb zu(Ln{$!tid^>+Qg4^qxu?(ETP>j;XyWS)Kx#-INmc5VQLMC{?-uK)kRO8DF7fVQ~z z+O7goFlB}(Tfgy7J=p0{6MMMv7o!0a1Aj{@BLhR@FJ=(C71TwBsp$ZPcI@HK0vQmY z03uXCga(Mv0TBiu!URNEfCw89;ShTmW`KtaNWcS0z$f-_=LS$nB8dfn#6U+ngXlHP z3=AL|6zvE#9iZq(;%S-h{s2PLA1tlv4*CPbM?wG&;@)q2IpcE8)*rV5!hmV0_KQm}c^#Mo>Pl*5b z|Nra%|Nkfc|NlSt|NsA$|NsAQ{r~^}l>h(#FaH1k|EB-{{~rWR5B~rE|Lp(&|8M^N z|3B&9|NrU#{{PSU_y2$4zyJTs{{8=7{qO((hJXM6xBmP8zw6)s|NZ~||DW>j|NjO5 z{{LV4@Bjae|Nj5q`S1V#6MrFUdO>>r|NlSr-~az}|NZ~J=HLJSyZ`|NoEv{r`_8JsX13Gm`@oLy1}AFGdjU+W3pffQg|rWIt&5&;wGU>;i2!h4>O) zB0#xwKq(nh6*vK72z&IJe&9h1Hq87MjJ*GxwL4x0b6&jj1|-KG29>YSV!PRbp@g-w zTm~cSA#8xPpTH#`NIi6+1)8T28lded64evhPmbMIczuE7A5M?vdJl#YK@2}ZLLcfM z>e%7qU33{YVvmHZ;TJx{}B?iqu{+DQX9^<@L3EDWT!wsEM z?>uM-%^ql`HUIoyBIXFvCE#dzpvKVhVvVj#=P}N66>6Q~5uNTao&E_fo$e`+0APwe z++5GWQ1YYmTIV5%>pXf*UvR-}Ipu<|2oZbG^%6+osoHt5^HcM`|0TR2`#D-K)fu&( ztkdfZ&*=2efmnqZ)?k}oc3$f|1-E$u%x0MHkoV71y5Ap%e)^qvKz#Z{R|&4gLEFQR zfbPqH_gCQgN1PwLnY~DkUypSu2LnU7C?rVH5(ji^H)w?sxW%@C5uyy5-VyaNy8TdP z@H3pq%fAToiOPQ{<&~gE=Wj?tl7<#haKAzL;6?_lsn}dC!BBD?watYu{gUcmqTG*^ zKZr6P#lHrfpL(0X?Uo$TnURhSqU zUN7yQF9M?HcFzZ0bMSg<_k7TC?5}&f=Yy_6c-`7PA2dDj5_E!0_k0#628NgUuth$Q zgw!3+@iGQoi07r}|NsBH;{{$if@zVLmZ(aQ9S&}1f}^}UUgD(y=&YIvper2b|NsAg z6|_yT_y7O@N1<(ktN;K1H-fHD1GOc-{r~^}*uVe(LD$GC{{R0UbRD80=!BpD|Nn!m z2RSA1|NsA>;fa+0|NlekL-69>W=n<=o6Zl0-&!y6Pd(Jz@fX~<}%`v3p`zxn_F|0n-A^S*P3WD$xAnU%kCYuc;g>tR6W8 zE6*|g4%#^fE{t3{54m)ngei3Cbk}j|^f%~qcYt^eIr~D-`$Ci_Y#yEE3K*3+LJPRO z!tk#GY5qmgFW}KVA3R#rxgA8|GYJ-682Z7ZNuAq46j}N~T~?3I?I4OQ{ov7}&g~$I zEdAh7&d%*1iY)!$(X!6%Ac`#gpbor8=XMZ9mVWSPTjzEVMV5ZhID$v#b`V93ep2fL z3e-!b@rR#G63pDHi#f%Kh42%h& zS_C2h8Vo?jps@pF3_ibvp}`(BeDMGO`+C@6C6Ku%*g+)~s+kOEG8vh9B?<-=ss+(tzia?W}3aXh_m`=~sM5EvL3K=+ShlQ#fOmoP9eXfuIq0gtMI z8E^vXFwha2*xbJWDi4~6#Af~lsJsfqKv33#uwW!;0}tpra|j3%NGbzFV2R%ZaMKKYS0hLTru(7t&~rI3 zDv!&20njEgJn0K`UnI!mPT+MYnD&GA=YixwvyxyZf;dQc1L(pa1_lPm zx))6SAE5F@5Iq>-TObUPz~#RMPV8q`As64Ltg9Z-+V^t6X zV}$^t01rC{=x#euc?hZ#8bBM5{{R0Esvp5tz}8tJo$mrV*jwTeq{RXCF4lFMISdR8 z0z{|-4W4rlp$>F*1_Kf5o-i;l{CG&%eV_viKMM)Snd77#K3Ta2z4^d3=9vT z>Y()(R`Wo2F#Uk4gO>AH)q(CVVt5G&7kuVTVP;^EfU1Mm>sZYLO-U(0)j{ibtm>XH zGcc@xs)N?^Sk>{cFfe?8s>A0#6VTe=R}gwT=|f$lnUfU3i1UJDBYLj+VEzVKVa z!oZLKRp$qdcli2rC?AwQKzIIjK-J+(2Y*-?7$y**4z$s822>qB_xZ3gFf4$o1GN{x zPJ-o6r2JOG%D`{~st%v~=CCp_Jb@+Z9;j*M^OOLEtS!9jN}tWnKy!1A_)s9kiW+)w~`y28ITxI(+`v!p6YR0ab_3 zUeE^L1yFUM`Wu(~SlAgDb`YUXhn<1p0uky$*cljJ5TULH)VFyD2|s-9Tf)x3AVGw> zGwciu21Ka)!p^|pL4-OP4hDt67dPpf+zD!vOUzLpQ-uSHP)WIhIlNCpPoZa(mOUD0x=`V1&P0je&DkAcC9fkD?D zDsK)I*WhDd@L*ujm4%AGuqco-OB85ne1q2gswIvpzS4b^8371!WlV2EL0 z&=rS@vqQyya5FIYFfi!8<%ZaEikpEU3VQw`$o}O}@#)+U`#ZQ97`z!6bZepFflzTL zZU%;M1_oVosJJ3jT!@>2A&!ATmmMnpfeT{JbuNf~hoStHP<|hj-^c~=XB8I%LkTRLoMo@8f2yGkA39-+M6JlN|JA`k}4zXVj%D)EPH?|N;&te0w z1J`YZ@*~+G>h0Me`nA~@7%~|cbXg(dzCT$R7@QawbU(5(Fk~?>=z{i{xic{6g6_Ar zW?=9I-K%WPz+jus%D`X=%73hobnnj!N%x?8t*sasY{jAb&v;oO_WWdlxcdVOgny3( z+?Urq#KORk&cL7xx{ub8fkF2@=uA@v23^pCEC&V#UC=74Yz7A1uS^hkKWAcK0GYp> zk%7UUfk78^<`Ia_gz`cAh(LU8C?C{U1M%N7K-Axd(lHDS40a3*y50;73~nI*LGCYQ z8@>MKCm!!2!YP=WMSA0y=NKZZcw|<3$)l2bZ#SLoS5N02jpIAkpDpPHk=SX z$loCTGpKqH8-!~>D_cRMCs6&WQ1e0I0g{K^vkV&#Uj#kJ5fm;Ud3&gOPhmMzmk_yN_u<_~bQ2)Zl z^O>RgVdI~&P(EzDG8`ITu=$5jXne!Q^P`~ZVdJBqb0$Id!N&6oq546ai$UpaJJfx! z@meNmc*4f7MWOD4jVFTc%?6nV8$Zl|rcc;>%NMBq4A227(D|ky^|1Mr*N}a}AgjT6 zA!I)?m<=L8=M96x2*d_q(1I6aejpdPJOW99F{qwEmY<3?n7tXzd@j(XjbNP+VkUTe z9Kr^X+tKvfpvfOZJJ<6Wnt4&2sO}R)^REP&Jm~ymWcP#i#v}8;p`8;t9nHSaXzqK4 z=Kd@+c|SDsdeHpiixys>gNKma!-pon0?j|5Glr1Wx1y;pL<dO4V%LNzjpxR6$WB_%u&dOemvloEqPY)E4&*qfQCO9u$$^vyXXKY-Rf{YEQV7117OP4W8IV$6(9(m< zs#L71(Ir6|khct@`4CkKq&O(GxFo*_yWwbZAmtvJDcIFwNI+6Vcw%OWE9g|FV$ik6 zpi^H^Z>z^84~{g5kDWoAra@b{Q;VS&(?i5PGC}v(gB%r*UtHpvTToI7wh7J4=#n4} zzKPkX;DcN%K=;-crGg9s@AHPGRPX_^Nu_CNsYM}0iFw5ZiAai&+y;&;h)*BjA9;G1SK5c z27#qOis9K2EP|pKzf?#L%#}fqMJ><>a0IV?fyp7c4|nQ4`XqnlAI1*d)-a@a1ShnNYA ze)w_FC}zS6G#ti)l01eKQf|d653v_qj$r78%H`*Q0v~+zGeQaWB<7ZrpI8FEoF3$G zh<;F61Uu#dtjn_)e49KpjXUS(rDdighd4wV%(Iv>Ab+5xe25U(bXYM3k79@%$UX2( z2oXY2j!h06|7ZaSvDiJe1VbF%I1B|SP5{f|a|eTw_pbab^|h+%nAg0Y_|J2{^$(TnP_cR4McjgIJ73 z4LBkovM!0BW71&fgrJ+?omv^3oS2uKp8`6i94S|)mnIgaK%ELpArJ#$=?q;K?o*f4 zPS6xg_h6G$=WzIo7L8c;Tff(}E0m|zSuFF&ss)Rka}k9Tnl zfnWZ`zyO+00V#xyC#;YF&lfOU@L*v043a>@Q1em}OA^5{=;r-^E?5Db69rOGp$suE zBLH%~IYlr0L6ZJ?2;P5ZVJkXhv80MYRfN0hN zMJfXWgP%Tx4R)jDf=omYzXi|+kAVz9GY|iH`W#UIZH0QQ1LP=>DNqa* zhVnrEOHP9<*@g(AyYB$#;v5DBh6mu)LJSNJ77+JI1cS%VA)1iL_;`3y0gIxWw*cxM z@L53&3=9f35c4=f!RMrb^&k__@GB_FFUilzEG|JeF99@Q30f}()${;rUO*@VXlNQV z?1dhFu&e>rfo@&_)I0~UECa&_sCfyYsQDNw%>Z>DIDWCYZv)gkm?I2qA^vTEx(~_e zU?ZXCfzR*E%uCBhci#c1d7!oYAPo-SlMz5HIEGmT79ezf&=rv8!XJFXR0p3~< zkp*v{gYQ2^KJW(SKJc=5kM0@Z6E0eBmx#m9x3~{+X}7dT>+RAHh6f-f9)`+;^n=bb zhwphpGQ${pbPV*Q_1E0|@(dneb4nzdcZ0J{$$O9P-Jm%TpU!WN|F6G(05%x9 z)=-ULn>|`@mw0=0gJ&x|x;ddb9e04{3w$6aet7hXzS9TA%W>4JEdGPndZ3COh8o}j zw#>8h2=rPEpKkC$qEJtOj@LmjPk8i-@*02+WqR(>c@N~q)&nIjper6=4t)ppq~rf< zpgR@1OD}kI9&-GDt>r+84Co9Eu;%|B-K8h~gV(*b9N=&H1UfFISM-WL%wUKVDCv-5 zHbg&~*`V!49=)P7u$XO!;%=z#|6fKp`~T&Z10@omeUxC`C?=OUfYY2$uWcDJ;(xIUY^%5lZJUfrSW``<-Dudn$?$i0qv-8~li?B%OJnqx^&hh^> zP+I78y#R}eZVRZf9-X&9vXJwSJbFbh=z(JYzTrvF&I=%k&ciVCJD-91Q1igi4X%Gc z8?ggD%%^Ephu^N>$3YoZ?bP$jSeaOn$`1q*19>cWnciCgcfwT-TG0NfdT3#G`ITnvVPG8#n*F)Bf;jzUI1SZ@y?@Hbh{1% z11wd5(tYQBs5xMTXbyl%dGv}N09gnsAiyaQvdPs0E%kvj4A{%Ch=7Kk=pvAddRcda z4Y?0Z$&i%f(JOicF6`6GDz1YZ7SQ6@r}H1kd7bxB!XG3AH)KA<5U7iNdRfnDqZkA? z0UUKGT3aBln~P$C3rzZiFSL?{|CtD zMS$uaaQ%9`8FbANsD%M8Kbos~7)m5DvbEtQSb2e#Ck!uvYoAz1fsS-OT39fw;BDT= z0BYdZX&Byy$a{9T{a^;A8=D(oJ3;6Dc_z1kRC!n)u6Y1Cb`JGC1<-x=jc-6F$im$Q zI%(|%#DLZVC0-uAriV2_h0Sren3-qiF^}G<4}SmuzwJ$mdgJpbBLW7pU9-u-OR9Zq)oo8pOfEdU~Xf6TQTkyy~ z=n5?$!O`mhx+;a+@pvmNmZ8=`m4nkC*ce#SKJEi9m_0jNUx1rk2l!k1K-FQlHB<|v z`b0IxqZgdRc7d+(a{PbIv$It~i~)2viU0$D3+ON-h=)Ok#evRagxy62&iByh>OAbx zYx_tG6oJPKFM-vA>ICR1V!o|UO2m9RAxDe7cJ$~q{injf@G^-N)I^zj0TjWYo#?eU9ATYQ2_Oz;cdf9pm6DIJ%J(T(K{6^ z*xL)z=LkL}4D8|Kr~v}f4~a=|1KnnJUWlN8lD8H z>)pFgmw{nd5DNptKG3)a#0NW!7>pTA7|a+vJ6mf&MaB+O23rP826K=As3>tf-Wmof z&>4amJa)J+xG{JzxP#=PK!V3xXX%1g4+b!J?C@dmVo+!B2FWde$ZgOCt!(sVa6H~R zMHjR*D77m`W_vIG{@tuyL3ToY(cCU zx}Y9`#|~Wv3kCy*SdjW2T?VkCExHU0dSKQHUCo}H}@dJw|`^cWa8z>4PSGB7ZLS)kg20nGB!V_;BX z^w^=ssLrUtr~=X`rpEyCpqw59gC?UESe1bu1A{i0rJ~2cpaW)^fUX{9bUfawp~t|W z$7l!^)X`&L&1iS1A{xr7#>htgwYc$_yCkBz^og(3=Cc%={LFz4Bm|XjQkp`pu^@tiQ@+}Zts99 zGqCDUx(p1yjIYJgVD*nj^I;~B#^0cgz$M0x{M%b%LFqKD^*{w@nq%i2*D!rhI@{h7 z8v!z_^+3hBUT?-U$Ic$G%{Tcc_7KKcwvO>^$z-z1IPxqStgkk|t1>5+QRGNe0xRM97>*l8FEr z1F~o>0|SF^>wo?h&@wU4?p}~#9<3+&TR>amJe&7|j9}nz0iDL`+0E|R*$V2ddUo%H zbYTCNC_#L9ycHw>>g{?SZv}N=!Ayv8|1WxWf~7${6Hm|Xtso=7Exf59(>*)E8bFe! zV8al^Zcv5)+QjhoYXgs7(+))jhS!py`>>Q47+wo_^qR^lK)c1>3g9DfARS|{evj_G zplS=shSzGK!z)EPZ+J8w0abTMXIFw1B2F8Do}U1!&pSWEi@N)e=EX|T2wjObyjF#^ zykSj=|JUF;jzimaoj1T$GQtALc}?K{Z%8oMa!@M(a&H)sg9#qpyCKQye~AFt1drp* zAOTR&do=F`Rg4TJmRMW~F5yA7$90cxurjD~K^@cM&0u|?y0m#WsNiQPsf1P<@VXz| zD+brZS3J5WgA~DAcd+g?xLP>i`2Pw_FQ`F@Pz`PN9tSG`TLX8(6_4Z1AS1!P=$;I! zp*>nJm54wMf~tc=gh%&o0V8Pc0fzvX@ag;xidgtnYDnW59=)t*WkH7)GJw`72Qq{+ zxH1GWL^6ah7%~JfIxspiIx#vkx-hyjx-o)obn!^dDM&4105Kg43UV@&L374=E~z=G z>4_z&41U4bMg74SMS*+(U3&u>LIz=|5SW6E%Y!*Y5TG$F(AXAid>b|{4b!>@+>&Bo zKo2K*iDhbp%tS1$<_M-P7$s5rX4p!5VPUkz}`g9d>?Jt9Y_yc?AEhSFhB zIvPr+L+J`A4dcVY6Xq_MJ7Dn+i)UE8!r~DYZ!kI@8V;~{fSCgeXBZzAF0gQe@nQCt zK+S>CpfCU@Bs2mPKA<7JPN;v{p!#6SmO{lRqKWT@iqA(AzX%maSN{Skj;@{wIspg^ zKbXC$IK-Wx;^^ii;t;QZimyd;=US*Zy1nx^D9DJb{t6IE?Or@?q+iK>0BFdr%eGL!rgb5m2S^2_s5i>ylW3w%<`Qga{; z{$eYJ;?xqyp@lSIGEerx#@0*&Nlv)HANY2j# z*#+XO;wKB!YIjlw|m(mL!7KgQ4n4fsVjH z99!(2T8SbLNwJQlCHc9DC7{c;b1K0%>}6J^dZ$*p7M5m~CFZ2&m7pfu@XVYXx6HiE z;tZd}(!69y^?(#~E}1F#q(Rz2TWe5U;*yzyAqG+ynwOE8f|_JpGE=aKf)qQYCg@n5^$*stAC3@X)*Ec$TE*g4BSw4p=3EgUBiyIhTW5Wx=IMx!@`Z zvQ!nM!!5rkH?hQuA-^akwaBd~Kd&UX1QK|TN%^HE;Hnd(w;-`7u_V6;WDzK&Kr~3W zBsjIGEHgQ^7~&L2eg={Lpo{F0k_n_)h*I$QLemO3!Wl}zg@I#E4yvXS*u|xwFw86g zIT_+fP`ZO8E~wqmW~6UsUS?uRX;EfXD!jEAm7kw$#gJH31iDz>GY{-dD~6K%^z@um zx6+&(Nba;^C^Ir~FtD<4Ff?OGMlh8P%|N0I4lo)bWo2l_;9zV7lCm;1b1*Vta4<1I z@EnYd7?PnnpoS?U%mrx z$^s!S0=c^k;v$e+jZ7GlQFwtSFz-1SnK&35C7T#9BpX?P-0WazmJIR%!XT*EUt?}Uzz?T6B^d8#8&{zoXytOglT5P;HhP+9{@8$;zwBUJa$UL+O)H`Z<*T3Z?%+X@2Oylqi(efzn=3IuT0eKCY6Ej)7CT8OR3DsOk!{bZQZg`0CgWyQxr<_6_Sfm6H8JR zkQ&wsu;x4iIC+Eipeq@gIoKN@xE2hcx-k{he=K&)OYz9hNpZ~sb-hv;jP;E5%oM=Z zDEI}t`zW}&`zZJa`=%BrVp?95T2hpmT9&Gi4ILd)$VsfsFD+5X%qu7@QGks2kf1Fz zFB8;@Qvh{Q7@XZ8BSY!AxcF@pVrv@lHwsb#`&MEW|Td!7;#7 zp|~fp9PhN1~;3fVSw%1wZx(S0Z20g_-sdpL`G%|{SHtO2{s0XixI3) z9#j)(zcMt#M&U63094+Ufq?jwKWO?FbT5Jh)Lu~hftAAC=Zkqyz#9ez290wNcY@**MLp8F z3<*$mpm;@5hjbqV=&ZF4s5(&mqNwv~X6a*QU;w!@g^__l;5@`$P&}ik!*ZX& z6i_T(gQy3^JBoU!{UCGqFfuS$K-GcbA4Q#eGg}Whq`;!!dlKF-GB8wJhnNdZ4~TGu zC}Y?z$iTqGz#zI*kbz+)1B32VK?a723=Fyx1Q{46fzIa@WMG)iz@S?%$iOfgbe^gp z_&i?OB0&ZQGX@6PKtTouSq27K(0Rt53=FcGf(#4}3=Fc8g5dLcW%&ge7|IwJY<~-Y z_1k_CU|?`$V32()08w{N0HS|4RDO#9cwf5gDgg$D5(Wm_J^==XJO&2cbSNDrz`)SS zz+memz`!tzfk9VZfPulCfk9Rjs-I5)d_Jly=p1B_{%`zXdwt*XGcdR^Fvy{0s~|3=FzG{E+YforeqxmntZ~5K71MGcfcsFz80{Gca^9 zFzANzGca^BFz9mdL)^KI4{~nqMn3Q!V9_~H{&Xn63Cgd9@^knY7(nO6ra<|=e2{Z& zJ)nF?J_d$j1_oU&-*%B`B zxw*1wToC`nb1^VXWnj?tv?tp!p|@ z24e;W*#u7T-9NG(oRD;4!O6g2$iN_L$jQK9z`!7@#R=Ln!5}Nc2}v(JoD2-Y3=FdW zIl$?`_6G+8gAfCQ>_-j;20aD_*~c7^^mH9`Mmqz8E$9q(P&!!$uArJ#6VhuAO8 z4%*AWAj`?lz#t0pHycF!2bBH@y1RgZLG}h41A`<3gX}q|_;EIf`n^#8HZ}$Zbp{66 zWo!%#(hLl;)7Tgoq!<`v`=R+u*dYFvfvOi}V_;BbV36fzgTxOD8v_HVi220|DJMYZJA=$S z!3y!uK~@F^B?boBO{@$I;tUM3tD)jcK%prERb+m%>prZAyoeq76t|x1_s$K7D%|%vOv;p0ShEN zGFc$u5y=Aamp=={Umj5Nt)b=^Ld{iY0qt;Qkd=UngU{CXF{pT1V?g5=c+R4D+yNeNgE{N;~Mo4(g1062Sz#!WPRR=mh8RTBj z`4t=t46?-#b8K@M89?U%$)-ZphcH6Q32R13eZvk_2ihP6Nf39%nkUobN;@V(%KnDYQCeuEQS|M6Xbil2ar zFW`juX96eq91pe(PVl`Kd=XG}0Z>LHr-= zP=7<|2OvQP2DS@OKB(UeN+&y@{0&g~1yKGBD8B>BZ-DX(pnTA|x*+`#P<{YZ-T}(D zfbun_12%}eLG>U==meAxI#(aW-vH&W0C5-?*k(Za z6QF$1`CB0KK=mI;C<7`FIvWhc2c3%!lJ@{{7#P?rpz;P#z5fQoPXlr<=$t4JA9Q~M zh<}0^;{F4mLXd%hZ3Q#<9u~eCQ1J;+8dU#*^nuQI2GJEz@d7BF0i_e5bOe+RfYKgN z+5t*~>Oqh>22j2RlvaS!5>Q$IN^?MI&|T6XeV{w3LGB0DlOP&&M>dEC-L(y(L3eh8 zXwbR+AR1I}f@sjW{~&q=6U5&Om>}^6sy9LAg3ifq}1qfq|i(fq@TXZY%@D+%N_PK9IQ}bs%#=>Okf; zGcfRh%mvXNpdGgi41A!mH;_8eaaSO9py5-Hd7x>$I0gnj&^Vtrs9t7ZU;wEDjmv}7 zfrhI<=75F^Ks4x{43K+4;SZu=;Sajk1jGl$1BiyjLjg2ALGb|+hs8$(R2&p9AaPi{ zfX3%Qd{F#=XjuGcK-Gid2_z1SCjqE9D84}Au=x4`jTcb7fy80)1{xm(@j>wiqG9oO z0;(Q#&KpR42b2#Q=K=9oK>46}2Ju1h1foIl1foIl1foIl1foIl1foIl528Ww1foIl z1foIl1foIl1foIl1foIl1foIl1foIl1foIl1foIl1foId1w@152}Fb92}Fb92}FbJ zsbOFMr?YBkdT3x^-~-uH3r!DA3=DiAdn!TgGzJESItB(lkUdq<^bieA59JIDpkWn; zMg|5xkUcRBklQ&b7#R32FoWBfY@qV8je&s=bpH*gNw%FsEs#9ulraz=R9=Dj zpz;dDzX0hEuz|`c5Fb=df#gB?1jGmB4-g-eFF<@yegN@7`2fTRrGF3~lTiAC#^^d{BA@@j>Yr#0RBc5FeCoL3~hp1@S@Y6vPLmPY@rJExI!c17Pll#L7ijuxfu=i<{UG(A^ayeXDE)!L50v#m;Rd2X z;RT{W;RK>V;RB*U;R2#T;Q^vS;Q*pR{s++@e}ia{e?c_Jd=Pz#lYxN`G%gDgU|?Xl z#sT4j!V@Hv0+k1u3*t|O%7g3$@nb-I4h9C;`J3-Sd`1Qakb6P$pz$L<&>cX~^E5Z| zLjwo236z0>VIdEM&jIDP2|@S*P(CX+gbzB?0%YDksCv*b6d?XHE{HtnfC>DLp0sONy{p8?emI%^9gp9C_WgMmQ;Di7Kx1S)JmXM2ITiOE2k0mgko-}o`Jhu=KzuW(|3N3EfcWW9_ks=(0rAg3-3vNF1;pP2 zH9rDsz6Vr&0+e43mCu0knW6R2H-=2bxXPoVB;fbw&o@*PmVE!4aTP`)q7{~Qbq zGoXCX_$DZQCP3$-^r7++(C{yT`cDDMpAAi~u=y(Sc?zsyxpM!w`bZ8HV zf1DjsUclz_)PeA#+P(JKPka8$r0W|Q$z`)SL3Q^x74RS35!+j`!0hG@K z<-dUPLF1($`!b;CHE)H=Z-DX-gTjZOfdO`2tqEwnmz9B`0J<*F8#Jy58q0<9qoDF0 zP<{$j9(Eq|8a4(7dENyK8PN1Li4nqwo!5H{B+s(|JShS4!Df&=&jJS6`M{v@RC&Gw z46yTfL!kF~fyPTf>We|+t&9u|u=&}g(0kcH<3Awz{ZM(>{O&rmdw9Ch`1{fB;YmZg zcgPuy51L0ns?He1(d3oT_??jc3&?3;ERJ?B5fhsFLum5f(cCu)?Vh1fH1(Ef{5fdm zgWL|nV8<|k=fpr&J&X&QGeF^k#;K9jGo!f&)P6*khqfo+=B+?;uPfTUNuY6GWc}r6 z_c%GC={H964-=YspmsB|c`9h~pk$9MFNl^NoY45M(cA-S=OgP6LyO-(X!kr7p_vD| zmkwF~B{cb$X#NA;V~DK&51M=W(c=3Lnto9K3t9g^wD<$fe;~`7qlFhkyuXu|bG);U zV{mZ1O1xh%V$C`9CIk!>pp}SFIq*tA$ofX`7Deb)D^OY39SZ0-2%*^s-fhDW@9Y*D zsFR0RP+{+Lo=V-ZGzmYc)27eONh9A)6e>J0J887Y}X z81aj|v>dt>2_DKA0qE}I77jg+3F2;;-ptgB64(k_$Y!?8{5<#`JLKSI zh)>A@ZRN!<9hB!lTbvl;8BqxyRID)pcI0KpvVTFTxYDrjX5y*v*?G&J> zfdo=MX!}<#OcX6;!-T=NoWRV2?|DSY`p{wll&p{<3ARNLp%iP{#;OCwEjY~ut3o7Q zNW#Wy9dWouArjMHdj4e%_1$7qBrh*1qLOd(|pMwmbfOgvU0X%2FA1C^S@DMl-5 z@o2(QGU8DU3r}$6hE*L({()TZ2g?6J(4!UNo!uab4OAZ`7J=>z@(XrPEeR;fPtQxt zO$Dii6g{BgqBIY@*D)YJ6SS7!Ex!o7#ULK3m;x=Y$0H5exB)Q^qY!`zLrSew(1m^R zWsnUE@$slvFoEjGct|$S%qz>!2Duts)k1R zA}BR2wJ0?&8Kf1d%t?n_k_0v^w>UjGH7^Cjp^$yMP~l)#A6MrP|DgCFS2x!nS3hUh z;CQGMxUK-#*+_CK@eI1rI8r|H{uFot3fU@ww3Rs)Y5=5OQa~Il0+Ya!43JF*?Pf;b zQ%vkHbY~)(njWHc&#_XD{W*7 zlg8;fxC*SUGcti0fL+=MzqA2fX+v{UynZu2iGXT4^2}~NN`2zF}8D45XweJh~zL9qCf04+R0F#-Ml$mIOog2d#K z_|m-c%)FHNcpq3$fpu+wng<)KSAgEc!`QXcNJi1vyuJY(~J-`oIdda}Ruj#r0u13P6^S#Eyb4p)v7oeOsdM(QC>t47%Lvzfb2Qh|_vaWnm((z#=}K-+em& zftetU96p`Tp`5oR96p`z!5r8HH6D~ZcL!eQCJ3QBHxDKOAdX*#TOS&ELWT;#HtjL?(j=#MuVnRPcg0DZxTS0dH-wLuH=GFjkod8V; z$d`<@9^mhDXJlY-HGJ|~4t^hzXY&z8SW)3=d4#`Lg%Mi%JOi5us!lo~R|R==9tI0} zSRO7t0V_b75BzWb!BoBj#_v1~V}WJ3%jbFY@?HnsJCw}Q=)rixr+Y0ZA^v~R>wKa4 zM>2nV^?y(zC6Ljtw*P` z01{imr}Mo>=RL5_m!O#P>0S%UE+DrodwKld|NpQ+^XXm+vK&^!`9MlipU&ro-@um< zesncF05%5d8$|8*9$ke;_gs)2@Js}%`_asR)}x-C$6)4wqZpcbd%?NVqjxJP<+yZy za_Ri(*a@-Sqq`TBK|DG;Kr2gqIv0QzPWyDOfaLKRpk>t_;2Q#27{IQDm6Oo&TF9gE z2&kwA!79W{5Duh5d<5Y@Dn#&2!ImA63Xutve=R#86`~M? z1E~;|ARI`AXawOvDnus;2T~yhK{${KF$uzfRER|o4x~bCf^Z-eB53iJhh+z(LR;v^gjid{6XFP~R7)B&c(MQxaUA;W8G~Rlune z)Skg93F>IzlmzvxaY}-^Y&a!B`#^C@g4_MLyaGBA38zlbaX2_7L1$3ll;i^?AzXHX z4n@JG6LNnlD80h(Z}sTi4T@55N#xPH8?ZhgBQVG!G~b);771e2q4%u1QF~PLJ0N`VHmr6H=<2_ycxs>buJ;d z${vQ_zwQ_o+-%Rl-y+Be>fZhH=-v-1ydf@cJy2(1cpGs8oM-nwkR+_`g15Vx4>Llg zAo?tC)L%gs@a*0PstO>Itq1Ci4R3?(hl=Ac51|EW9$dh)dmpGy!Db#v9EW)zDTo%R zd2j((-R#r(eIFA83j^rlJ8(`0F%BdA4@w`P780nX6dd5#`OUNQzvH)KjQlO%7#J8l zQG<@Z?;!)|ia(#;)C;de!2b2nJjLGvYVCPwp5PBZ@Y#c3>i~cFNf3SNGk?T^&-`%* zKl4Yh?qC8plb}rm@GZW`W?LTS?`=g`2=lII=TXn@{h%7yqxFA@fM<6p1FRF>dZ5JF z@PKExuYiZ;iCT8gPFDes&V!!ap%NaJ7x?>9{{R2)+370b(Rt`)#Q*>QVfRV$haY%Z zg2eaeu7%vN3pJ@`+w0wq-;Ocyx5$H1PxpR!40*I3s4F+T?bBO&;k6mOJ!p8qQQJjD z!0=Mb0si@id^-Q5`VgVp@^GyssJ{m)b)jlJJC7jwZmVaviHc9>CvbeW9w=Q3ciQVY zp56Q5F$=oDvJZ4KuHkLRy`ZuT+Jt&-&M)u4V0ge26W@sNsk(M|RbEkgGg;Lm`3GdZ2V3!dX)tyV=2c&oRak+AoFlH^YKGn%@|BbpD3b zl-;17<_nMJ<18M%rsj+c47)%DBFv|*9=+8f9=)b==n^_Uy`=|sftsY?elw(b>Cx+Z z0d%J?s9fy4@6-7S+FnGm%i8rtDW^yC5d&~y2U`P+e^7ew_T%t4egJg-kEK6Hk<1QI z-BvEz?Z*Qb<*8xgpMQXV+kx1_paO=WVLzB+K#XaE>L!pFC;~t<41>%9)p(#P5mZHi zDmai|LFzc6iomC2T46bi6LbCTJ|8L%s;fcbAPm|g1)@RNpBekPW#G92 z1_p+HR_yYib0t9fSAh}?1E{zF@enuwYT;|}x@63A;T%Bi0|o{LHAc`mEudB&Y1tI*$Q2s?hi2mh*;B$<0X9Ob*A z)IZ_}pHroKgC9H(B{~f%9?K6tw@TNCAABB_t_wf-+#OwGsJt>i_#7-LT+oFzAXx<=LR} zpV`6lR20ph+ z_YG*D5(9(o9X9YeQ@ZEbz~@xyg3k34WMI(U!v;wgpz};X_O!A=%&B4npA)5<#RfiC zOxKhR94?~!SRwp*tPp-QEBO2;T_?ynTDn%O;QS(L3>BAxiVH!-xuN2pAm>x*f=0_h zM`=A~f#lyyED&=~vVhO;(gmG|CCR{`yO;%H?o<}=`AWLYP`VIGPllYeXbU=LN}GYf z)|(j;Keo(}_%UM!pZ}(-#SAf@8!FBMIqymrv_DCSfkF2r6Zl**UC{X$<_rwB7n#84 zUg;iX0-sN&yN?N+Ph~eSfzKt=T?yHTB0HN25obf*^jQf5OfA51B31~Mugn<+V>9PgZ6!c_@KF55FgaG0r5c% zHV_}w2nX>&v#%gNs15`1LH+{m3kS`sgJ_UFAR1&ohz6MpqCw_?XplJ|8l)dYgU*3E zz{tV?8Z6~wW?+D=BX|tjm&wS$0Bb+Vf%d&JGBCi}OS?e(GC}nvbe%vGR6VRcHvW85m&gA$BMq*8WRBQAAEun)8Jc<}R@BCAFq;2C=l3Dow;fGC=-dfp`A=x}fyNh* z<=3P6|2LX>pmU0l)o(#_j|-alMrizNXzD}J!ea@V`iW?K(D`@B_6MWMgGPaol;pqbD z+`5BzQ-CicV2Cd+DauPOs06L`2H(R1+8~seQ<~~n;+dC{S^?GQnv!hw9a$&j7R>l;XE(>3oc!d(lKdj*emJON@WOc5a(0iz5~%SIcY#)!!)^hC zT3E~w4_>%al!_3@c6I|@a)8)5>782XoS2j2l$e}d%mA_+Bn|cqrZ7TR7|54M3c%~w zQQYTPky#A)U2uL;30O-pLry$&IhGz+Pe4v$3Fs2hfc%^snAh}*LAN1dC}T--Wg zX$+wja$6gM58H#}o?7Az*^R^i^E)V95s4@`6_O}GqL5J>SpI~^ zH9fTm%mtYMPP2{$1*v%{P%&grAofZ@Y(ntid#Aw45fKc^2T*rFqc%9T1mYrC82Fav zlw=m7JOIT9BCH9_k5NP>6FKtPzfNuqMVvCMfG*bMx~uOY)0Qm%%ciuY(1RYl6-q zL|z9Anp=W50MHm2(0iyr?GTU@j1L;G17Xk@DM*~yb+E49Mn3wD9`@H4ilH4bn6NdQJ(5 z4Z@INO%Mx$q3$bA%>lU%w2m0neHWnXr9u4$kd6WwNPGlng8Sp3F(@?m;a^8=0F79G zXk+98XiySlFcf3D5C1yi22jI>fq?;Zt`^7$1v!ZOHfVzTb08rU4E1kjZen^W=nhWw z_*eiv2L=`&4)Q44K^%1d;$26)0%{)UTs4qp4|$0D9JCxMx?+#n1p133YGZcdN;N$Ra=3EL-bwtLAao3-#HZU7KJ46V2M`#>#a&+b0ZfvFz7!T&pNG(TYXX#T}s%x-w;Ch9a}&A`~Tn7@U2hhR*nDv|G&=Y-fQvy z|9|kTpilQ+keEmJT!H`p|9|2aXmtS5j{JgcpbYNQy;cG2Ey#K?&|Eqr0}BJ_EOW@J zFW=68{PLio4hGNWqm13HAP;+59_4SI#m2zk+-$fn zr-BUg=D;DHVDJ}l5WTYrGo z>p^VyZG8fsANApPdEjdJ7Ad_z&FTdkWXVy&(}w!R~AD zB7e||{MG~ft#Y8;ej6G;KHcEhhs9|3R8X33z2woo6_jvG#a_o5-u6HfE%7ou@R~o3 zU*3g*!K3*Aqle|85_6Ako?{-ZCrjRS?**k5%blS0Ql$?(I%k6Nj>mBp@NS%!Z~p%O zk0=4sCcxwW6Te_9C@?1^qPu`z!vg=R+fJE=rvV^i?rS@nGK1#lF9o(v#=mf_fCapRj`;(=W~zVsU9!~ zx^zOav2`m*S*aw9zZ2BTvTg;b<8Sf*4_bWs9qbarlP^J$hUDJ;91M&M9=)cZaYyJv zf|vcMUIMK>=rx@U3noygXMjSz*L1lsXx%ZwjV%XC{5+6~7tjh(_+oI6&chzP6^#2p z4H2+oKot!{F(}+SZz0x=!vg!YIE>}dYkL*8Itr{09DC424T|TM>ffLOOb49NKJn{J z1*I(?X!!Vce(~%)=G@J)#<8;vG{@Wx&RdS1ZJ@;K**OoCbP{~^HyHWIWK$LiPr|BjtU zJCA$xnmU8Gru;HI36=##&JmB!!^c}eDH2qCg3}E+x)2E)R)g_x>jfzTuYA4?*>MB5 z*TwQdX|qe`dyigI78K)sI)8a~9*4+q2{AChYz0{eN^KwukGJythwP{DZT(*&1Ge9% z^FMOBg#|Sz-$N8Y5<5sE#2e7fMcv>u+%b@exD&5AU}``m4M;6GSG-*D@Be?_&M!XQTR|nDYwI_k?!BNQuteAJ z_G=+T`3_nDXL+wg+_T%}K4|gPJMc0x=sNk=4`5z^t>cDO9!Tq-K}|69_0MqgQQK?H zZ#+CYOHX)0_dt1e9(P1uU)Oo~lOw+XxJv%SFX(y!wn`6FUO+?2v-2n{R>2|oiC^bH z>w!|fPy7O|khM!75tq)?87`fR9ML9#H;-W*YEXEzs14XXjB@!*8#h;QsG)J>mhn z+XB3~&!f|I$8pyKAoqYvxY7-9D?p74&*o!{zLsD4TR@XfKAr!4pqrAAa;K^@2LnU% z59ZR#9^I}NKJg1QfZ8vhz&Zi*Q>W_&1ak|F3AP9nG@vY+4r=`H3%Ei&3=(}A0%|6- z-sW%F#K6Gd)17+3vw4pSX#E&Nsi`neNef51Q&+Tfdd) zfecs;F@SeI=rGCfOK<~RI=@5Xz@-yX;KL%)qxpyjQd&%dtWyhj37et~9KfFh?pnDL&SM`28`380|EOnt7MYObAmEQrMC+3CmO zc-#$q7N%pTn+VJdkM7zN9?eH25H1EU-9(g*Q1^q^*$H?wgBJ%f@VBf2uZjD8+!b`g zA1H`fTRA~BRP7tEt6C3$qTmfE1VPt^fubOnlYs$e6uf~1f=BmeP=upLf*B_`7I{G@ z?(*Y}1ds0BAOpZ|@HpNKVuO;1NAnQ@@B%$hdjwP-#9~{Q8Uk8NsNmUo-LvxxEP^~c zk9BVb#g9jCEo8d}XhR_9Cw?8*1CE_6DxiXw1H?Pw*vSsBLYt2$fC4nmF+TP%BL2bV zCt#TG(Y+Z|DSEViD^>RBHNC@$zS#~Y&EL`t3U%oIQkZ)X+DnQ&dTSRzx0dn?xE|ma z@V&q<=%XUQFUX<-4ik{$ML-4BhEM!)pxhgE;Iku07UU0Mki-s<#Enn<5D8>2CBVJJ zAAW#e)Aa(srt1NZUe^U6uAqYezaWEe>yy%juQwx74=lV9{pIF27QUUwJv+~Mc3$=9 z{0u9HJvv=icy@1t1%y1PK12%$gmg(c)RXWm531hSLD8_GlNq!XRvGG*2-g#z_#;>^ zvVmFvQIH7y%&&96vC|dg*b*EO>Cs)g0vujwdm%wS)pP}UeuGEr?b5#2llkQtKR9^J7gpklJ1-DMt(j-7lSy(|tM-M$Ar zx9>Zz_ zumGs-=X%AtwY5!n2pB&AHb_m%+D}rOl_;_lisBJJ^^`cj*;a zN$b*`dd0W(34hBZ(0w4??7rRp9KPM*0`9#wDvr&6SooXgF@UxJ-gafY@7}8;Cz(z}->%2)G_;cZZXs>8y-fJg#q6F&0`@XY_rA9><4zs|?BPLn97UK8!l zj{E{V+mJ*f9eYjWF+?N4%i}HYl}@{}Y0q@$jeKlvve^tAlsz(47jtKsdI%lxgMK>IHhUhucR{P+LA zgThCC@JNko=VQm_$A4Tpe;I;y=Ib&uFr@M4^O}OLw*&Q`9r*=B+V~?ceCCh7l*Vtt za52r1|C)${V=oU2NU9G*%CVP+3A>DwNAm#|Ps_ult9>mW^S37b`~UwXXe%iq__3#_ zuZZg7xNCQ+gmbS=3QF<;Cxk8FT?n-dzTLhYzTKe$?!7uHE}btxnIDuOd^&3nfHFLP zGpL{MYIxg~@veKXjf`I}OT2fl$vp2~mPqejo+zKr$3B|34KIPxh6ob_gCqZTn*h+p z2!5^epZViXeC8MAnT96j*lQyWD)@Q!@o%>YL{jY3Yoi5`@Boj?T`t|=)A_)syY>J$ zOLm7|c+FyX$?yQABm*UV-(Hq!E}hR{DIS)NK>ZNRb_Fy6y+lhuO7H{(8YuuJAker4 zI03Q$|Nq~+mt~oMugo)#Zr=-@y&`=cy(Yb&YTc{XWSI}+H&4rN{F4rQSRUe^bkGBo zz7F_U-r}Eh2$YIW^S2)T_y51b1^(8(pussv+5wG5zCXaP!7BjTBhl@90TH2~{8T3r zp2nYefj{~Zf80e!enF9GpB?$@L;{fnds#$45^Z3KAcRCOiy&Csqxlevr{(3+P2hy% z1WGttK%0x@9l-SkXrB~#U4OF$LkUOsd{7JHwSeL6{frEZ42IvJ!vmc+z&m?1g8G_S;|(lxI%H?=6SBr`7^G+Q4GS_EK~pOlrFTvBWW zR%6AGl3JFToa&NVoLrPyP?DLS#{f~_mS5zZTA7*>T$%)tvSKLBE6z;MOHJ|2D}l@h zrxk%tz)a51D@!dZ2}(^a3CRboddSR6w_+&EEY3{INp%A&0WH4B$*f9E0iTCilv-Sn zpO;b`k`FuT)rz4EwEO{LrxinJh?@m;o*UvZ*t`2xTa3#FT( z^aLn94@z%>()*#bUohktNytn#19VGPaY0UErE`8>UTSg)1C$G+;kz`T;?P|j zo-Qyu-4Zi%Qd1O4@)goD^HLOwQ;R_HsZfw#RHBfUU!;%%F&<_fR6jT#QuE?NgBd*i z!EuySnwFMYgvtZ0ym0q{EWGjbcXM(sEhBupYw|$3QBmO7=mEfehJvT z8~XetOnwfiWyJtqa|_W3C1LW1q4Ln}3s6}G2AKS1s61#a94-l3mk*juW?*0t22CVE z)>tA-!}Y5{<-z$KNd?S&E2uow8n_CWd@xjA6fOf{z~nQr$RigLpnIGzMzDeg10for zsztPLnG`i1NQwU0?-Is%ZObbw*Jx?hyMjY3tK^JU~$MhKl2f0^=k%8d`R6QuZLE>=tVo?uTGri&?#J!;S zM^TR@JbD-z7$QDF)PvFkA@zGe?)eN+4@w_|)W2b5VEFMBqF#qU{D8t+hKYgU2Xy}r zDE*+A58Wq}CdR0XyqSSPw?PP^&sYe2f4#1T5M&?D zKS78&FQNNyKzpVG7#MVy2}1PG6@=_-Fc)NCaARQ51zi#z0$MLGz`y{aUkZTt0qEWn zfb3tmEC5a$x*G%_`vjIk_vge5KmmSI_pc!UasLZ`h<$tb85len7<4y7 z_w7vJXJ80sV9;%c?8A`--M0h^uMB?hIcB1P{1E*g`5^jt@Ills;sdX9m+gk~oA|){ z0%WuKAmJU)2hs1z2hlGF)&H9pvi|_I?*kE}Phl=Y%X$4;J{pq^mQ2qlRh~`T;j&AI&Lli2N3)_!=lZ zmmA`~DNuebH^d%)Ziu@qp|lA%#9f-)5O>LOL)`Tna^JM>2QJ8dtP5O_^fHMH65s7y zkoeApipOy=Ft{=>=mv2?!odr)$$^1ESB?u}9}kpf=YrVxhZADoM^1=+H#i~gJIM(N zhsB%>3=Rwoy3L#n42}#8wl$oPd{Y9Yvp@rv3=F!LI3VG53Unzr1B32HD1RlCU&#U4 z|5n5SzF%B43CaiE>&(f(AnL*a+4p4#)u##7#|%~XlO3Y(DLZ(-h3-an@B$gpSx|Zs zJ7nKnBRgbYP7OOG9i~F%W7#484PuA*&y5}84@q_g1{Vef-REo!3|xGB8*$ zFzB|hLc%G96%sE2tdQ`rXN80hXx|eD1A{0pE5zTdtPBi63=F;>SRgcLpA#rvu0r`s zSs?q7*rEJ$%#eM6yO|;GSk4UAXWPxpz!1p5pc?`amvv(Xho>y`eqh-rOb~U~Aou9X zE@gt4GlPkNL4$!ow}^>>!GnQ87j(a+E(3!uXg$9b1B0$069a=U1A{H-9wbmud}Rce z%d*cI!TC`ZwC5k!O5{efuEdO{El+CKxL zLG4ly4Qft-Xwcjdhz6MtqCtIV4p1|X5#0IY1D&A&;)C|<*n{pTWdMgC8))ASh!2{y z0m*~*?|}HA{YW4_X#NSr2kjFA@j>hIKzxw9L41&VL41%qL41(=Kzxw9KzxvUKz!&u zQf#1m9vK-J*g&%>AR5%i2GJmQfoPC>Ks3l5AR1&phz8jUqCxh7XplW18e~3*ehaz> zjh%r3wtlb^bk7_+1H%naz%wu~%mLlI#?HVX017w;28JV0dDyv~22eie+)a>~*P-e) zpz1-V-SM$9Fu>MN`a#t{fSNB1<-dUPcR}@kfby3?<$pl=*-$py_*B?j?f?eSeu z^I`34H8utYkUS_XKp1piJBSbKUsyxsVf__tsD4=c8?>(tl2t&u85q*Q?QsYjL~5h$ zKiP*SkA6?sbTsv6(Dt8npz%MW@m0|Hw;=f$e<8a+8*Tp*`u;A^{kzEO zLG5K^eju9p!D#-Ojpn{aGi<85kHqZF^)s=>BUoLN!{(hZe_==01=%SY_)U;y3bhIh{wc%K8v6i?8dRVDdF zeyJ5D4DrtH?x`jIc{!PRsZis6GK)dtko_T`-7?_esCZ{Lgl(|BFP>=ukPE#SKwGpN zG4_YS{R7(k;htLJk(!yFQ3Ac#3VQVoXtx^p7P|DDv~sW!V9$ehr@*#R!FC_Hrmq9}F231UUh; zDJe5A9V&uspHqHmUJA?@@WwN!d!gG@U>*T&l0uaM`y4I=3JY-1C+8=^1;H^0HWa#} z3?96pd6^~9Vb^%LAY{}NLl_hYIWSSMk)RkzDJ_6T3%0A=z{+554^Axs$52ore6Jcz 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�?`gobqY`#)Mx^UKj47shti<& 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 +|G%kT#4dAWR0- xrho=Gt`I(!KeMH<0G7J?08!o Date: Fri, 4 Feb 2022 13:03:20 -0500 Subject: [PATCH 03/12] stb_image --- Makefile | 2 +- vendor/stb/image/stb_image.odin | 1 + vendor/stb/image/stb_image_resize.odin | 3 ++- vendor/stb/image/stb_image_write.odin | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d3d3c6a2d..df5fe0605 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ ifeq ($(OS), Darwin) LLVM_VERSIONS = "13.%.%" else # allow for x86 / amd64 all llvm versions begining from 11 - LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0" + LLVM_VERSIONS = "13.%.%" "12.0.1" "11.0.0" endif LLVM_VERSION_PATTERN_SEPERATOR = )|( diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index 9e72760ab..12f7aea9f 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -6,6 +6,7 @@ import c "core:c/libc" when ODIN_OS == "windows" { foreign import stbi "../lib/stb_image.lib" } when ODIN_OS == "linux" { foreign import stbi "../lib/stb_image.a" } +when ODIN_OS == "darwin" { foreign import stbi "../lib/darwin/stb_image.a" } #assert(size_of(b32) == size_of(c.int)) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index bee29a15e..c75a95fc9 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -4,6 +4,7 @@ import c "core:c/libc" when ODIN_OS == "windows" { foreign import lib "../lib/stb_image_resize.lib" } when ODIN_OS == "linux" { foreign import lib "../lib/stb_image_resize.a" } +when ODIN_OS == "darwin" { foreign import lib "../lib/darwin/stb_image_resize.a" } ////////////////////////////////////////////////////////////////////////////// // @@ -184,4 +185,4 @@ foreign lib { space: colorspace, alloc_context: rawptr, s0, t0, s1, t1: f32) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin index 1f0cfce85..2a2ec240c 100644 --- a/vendor/stb/image/stb_image_write.odin +++ b/vendor/stb/image/stb_image_write.odin @@ -4,6 +4,7 @@ import c "core:c/libc" when ODIN_OS == "windows" { foreign import stbiw "../lib/stb_image_write.lib" } when ODIN_OS == "linux" { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == "darwin" { foreign import stbiw "../lib/darwin/stb_image_write.a" } write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int) From 42364f2fcee1f0f588b006bf2b7e9bc6f88acb93 Mon Sep 17 00:00:00 2001 From: phillvancejr Date: Fri, 4 Feb 2022 13:15:43 -0500 Subject: [PATCH 04/12] sync with main --- core/bindgen/c-parser-evaluate.odin | 266 +++++++ core/bindgen/c-parser-helpers.odin | 267 +++++++ core/bindgen/c-parser-nodes.odin | 132 ++++ core/bindgen/c-parser.odin | 840 +++++++++++++++++++++++ core/bindgen/errors.odin | 44 ++ core/bindgen/generator-clean.odin | 284 ++++++++ core/bindgen/generator-export.odin | 166 +++++ core/bindgen/generator-helpers.odin | 392 +++++++++++ core/bindgen/generator.odin | 205 ++++++ vendor/stb/lib/darwin/libstb_image.a | Bin 0 -> 55744 bytes vendor/stb/lib/darwin/stb_image.a | Bin 0 -> 97544 bytes vendor/stb/lib/darwin/stb_image_resize.a | Bin 0 -> 36824 bytes vendor/stb/lib/darwin/stb_image_write.a | Bin 0 -> 32896 bytes vendor/stb/lib/darwin/stb_rect_pack.a | Bin 0 -> 5064 bytes vendor/stb/lib/darwin/stb_truetype.a | Bin 0 -> 67008 bytes wasm-ld | 1 + 16 files changed, 2597 insertions(+) create mode 100644 core/bindgen/c-parser-evaluate.odin create mode 100644 core/bindgen/c-parser-helpers.odin create mode 100644 core/bindgen/c-parser-nodes.odin create mode 100644 core/bindgen/c-parser.odin create mode 100644 core/bindgen/errors.odin create mode 100644 core/bindgen/generator-clean.odin create mode 100644 core/bindgen/generator-export.odin create mode 100644 core/bindgen/generator-helpers.odin create mode 100644 core/bindgen/generator.odin create mode 100644 vendor/stb/lib/darwin/libstb_image.a create mode 100644 vendor/stb/lib/darwin/stb_image.a create mode 100644 vendor/stb/lib/darwin/stb_image_resize.a create mode 100644 vendor/stb/lib/darwin/stb_image_write.a create mode 100644 vendor/stb/lib/darwin/stb_rect_pack.a create mode 100644 vendor/stb/lib/darwin/stb_truetype.a create mode 120000 wasm-ld diff --git a/core/bindgen/c-parser-evaluate.odin b/core/bindgen/c-parser-evaluate.odin new file mode 100644 index 000000000..13cb5042c --- /dev/null +++ b/core/bindgen/c-parser-evaluate.odin @@ -0,0 +1,266 @@ +package bindgen + +import "core:fmt" +import "core:strconv" + +// Evaluates an expression to a i64, without checking. +evaluate_i64 :: proc(data : ^ParserData) -> i64 { + ok : bool; + value : LiteralValue; + + value, ok = evaluate(data); + return value.(i64); +} + +// Evaluate an expression, returns whether it succeeded. +evaluate :: proc(data : ^ParserData) -> (LiteralValue, bool) { + return evaluate_level_5(data); +} + +// @note Evaluate levels numbers are based on +// https://en.cppreference.com/w/c/language/operator_precedence. + +// Bitwise shift level. +evaluate_level_5 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + value, ok = evaluate_level_4(data); + if !ok do return; + + invalid_value : LiteralValue; + token := peek_token(data); + + if token == "<<" { + v : LiteralValue; + eat_token(data); + + v, ok = evaluate_level_5(data); + if is_i64(v) do value = value.(i64) << cast(u64) v.(i64); + else do invalid_value = v; + } else if token == ">>" { + v : LiteralValue; + eat_token(data); + + v, ok = evaluate_level_5(data); + if is_i64(v) do value = value.(i64) >> cast(u64) v.(i64); + else do invalid_value = v; + } + + if invalid_value != nil { + print_warning("Invalid operand for bitwise shift ", invalid_value); + } + + return; +} + +// Additive level. +evaluate_level_4 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + value, ok = evaluate_level_3(data); + if !ok do return; + + token := peek_token(data); + if token == "+" { + v : LiteralValue; + eat_token(data); + v, ok = evaluate_level_4(data); + if is_i64(v) do value = value.(i64) + v.(i64); + else if is_f64(v) do value = value.(f64) + v.(f64); + } + else if token == "-" { + v : LiteralValue; + eat_token(data); + v, ok = evaluate_level_4(data); + if is_i64(v) do value = value.(i64) - v.(i64); + else if is_f64(v) do value = value.(f64) - v.(f64); + } + + return; +} + +// Multiplicative level. +evaluate_level_3 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + value, ok = evaluate_level_2(data); + if !ok do return; + + token := peek_token(data); + if token == "*" { + v : LiteralValue; + eat_token(data); + v, ok = evaluate_level_3(data); + if is_i64(v) do value = value.(i64) * v.(i64); + else if is_f64(v) do value = value.(f64) * v.(f64); + } + else if token == "/" { + v : LiteralValue; + eat_token(data); + v, ok = evaluate_level_3(data); + if is_i64(v) do value = value.(i64) / v.(i64); + else if is_f64(v) do value = value.(f64) / v.(f64); + } + + return; +} + +// Prefix level. +evaluate_level_2 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + token := peek_token(data); + + // Bitwise not + if token == "~" { + check_and_eat_token(data, "~"); + value, ok = evaluate_level_2(data); + value = ~value.(i64); + } + else { + // @note Should call evaluate_level_1, but we don't have that because we do not dereferenciation. + value, ok = evaluate_level_0(data); + } + + return; +} + +// Does not try to compose with arithmetics, it just evaluates one single expression. +evaluate_level_0 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + ok = true; + value = 0; + token := peek_token(data); + + // Parentheses + if token == "(" { + value, ok = evaluate_parentheses(data); + } // Number literal + else if (token[0] == '-') || (token[0] >= '0' && token[0] <= '9') { + value, ok = evaluate_number_literal(data); + } // String literal + else if token[0] == '"' { + value = evaluate_string_literal(data); + } // Function-like + else if token == "sizeof" { + value = evaluate_sizeof(data); + } // Knowned literal + else if token in data.knownedLiterals { + value = evaluate_knowned_literal(data); + } // Custom expression + else if token in data.options.customExpressionHandlers { + value = data.options.customExpressionHandlers[token](data); + } + else { + print_warning("Unknown token ", token, " for expression evaluation."); + ok = false; + } + + return; +} + +evaluate_sizeof :: proc(data : ^ParserData) -> LiteralValue { + print_warning("Using 'sizeof()'. Currently not able to precompute that. Please check generated code."); + + check_and_eat_token(data, "sizeof"); + check_and_eat_token(data, "("); + for data.bytes[data.offset] != ')' { + data.offset += 1; + } + check_and_eat_token(data, ")"); + return 1; +} + +evaluate_parentheses :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { + check_and_eat_token(data, "("); + + // Cast to int (via "(int)" syntax) + token := peek_token(data); + if token == "int" { + check_and_eat_token(data, "int"); + check_and_eat_token(data, ")"); + value, ok = evaluate(data); + return; + } // Cast to enum value (via "(enum XXX)" syntax) + else if token == "enum" { + check_and_eat_token(data, "enum"); + eat_token(data); + check_and_eat_token(data, ")"); + value, ok = evaluate(data); + return; + } + + value, ok = evaluate(data); + check_and_eat_token(data, ")"); + return; +} + +evaluate_number_literal :: proc(data : ^ParserData, loc := #caller_location) -> (value : LiteralValue, ok : bool) { + token := parse_any(data); + + // Unary - before numbers + numberLitteral := token; + for token == "-" { + token = parse_any(data); + numberLitteral = tcat(numberLitteral, token); + } + token = numberLitteral; + + // Check if any point or scientific notation in number + foundPointOrExp := false; + for c in token { + if c == '.' || c == 'e' || c == 'E' { + foundPointOrExp = true; + break; + } + } + + isHexadecimal := len(token) >= 2 && token[:2] == "0x"; + + // Computing postfix + tokenLength := len(token); + l := tokenLength - 1; + for l > 0 { + c := token[l]; + if c >= '0' && c <= '9' { break; } + if isHexadecimal && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { break; } + l -= 1; + } + + postfix : string; + if l != tokenLength - 1 { + postfix = token[l+1:]; + token = token[:l+1]; + } + + if postfix != "" && (postfix[0] == 'u' || postfix[0] == 'U') { + print_warning("Found number litteral '", token, "' with unsigned postfix, we cast it to an int64 internally."); + } + + // Floating point + if !isHexadecimal && (foundPointOrExp || postfix == "f") { + value, ok = strconv.parse_f64(token); + } // Integer + else { + value, ok = strconv.parse_i64(token); + } + + if !ok { + print_error(data, loc, "Expected number litteral but got '", token, "'."); + } + + return value, ok; +} + +evaluate_string_literal :: proc(data : ^ParserData) -> string { + token := parse_any(data); + return token; +} + +evaluate_knowned_literal :: proc(data : ^ParserData) -> LiteralValue { + token := parse_any(data); + return data.knownedLiterals[token]; +} + +is_i64 :: proc(value : LiteralValue) -> (ok : bool) { + v : i64; + v, ok = value.(i64); + return ok; +} + +is_f64 :: proc(value : LiteralValue) -> (ok : bool) { + v : f64; + v, ok = value.(f64); + return ok; +} diff --git a/core/bindgen/c-parser-helpers.odin b/core/bindgen/c-parser-helpers.odin new file mode 100644 index 000000000..a99d83dd2 --- /dev/null +++ b/core/bindgen/c-parser-helpers.odin @@ -0,0 +1,267 @@ +package bindgen + +import "core:os" +import "core:fmt" +import "core:strings" +import "core:strconv" + +// Extract from start (included) to end (excluded) offsets +extract_string :: proc(data : ^ParserData, startOffset : u32, endOffset : u32) -> string { + return strings.string_from_ptr(&data.bytes[startOffset], cast(int) (endOffset - startOffset)); +} + +// Peek the end offset of the next token +peek_token_end :: proc(data : ^ParserData) -> u32 { + offset : u32; + + for true { + eat_whitespaces_and_comments(data); + if data.offset >= data.bytesLength { + return data.bytesLength; + } + offset = data.offset; + + // Identifier + if (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') || + (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') || + (data.bytes[offset] == '_') { + offset += 1; + for (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') || + (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') || + (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || + (data.bytes[offset] == '_') { + offset += 1; + } + } + if offset != data.offset { + // Nothing to do: we found an identifier + } // Number literal + else if (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') { + offset += 1; + // Hexademical literal + if data.bytes[offset - 1] == '0' && data.bytes[offset] == 'x' { + offset += 1; + for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || + (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'f') || + (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'F') { + offset += 1; + } + } // Basic number literal + else { + for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || + data.bytes[offset] == '.' { + offset += 1; + } + + if (data.bytes[offset] == 'e' || data.bytes[offset] == 'E') { + offset += 1; + if data.bytes[offset] == '-' { + offset += 1; + } + } + + for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') { + offset += 1; + } + } + + // Number suffix? + for (data.bytes[offset] == 'u' || data.bytes[offset] == 'U') || + (data.bytes[offset] == 'l' || data.bytes[offset] == 'L') || + (data.bytes[offset] == 'f') { + offset += 1; + } + } // String literal + else if data.bytes[offset] == '"' { + offset += 1; + for data.bytes[offset-1] == '\\' || data.bytes[offset] != '"' { + offset += 1; + } + offset += 1; + } // Possible shifts + else if data.bytes[offset] == '<' || data.bytes[offset] == '>' { + offset += 1; + if data.bytes[offset] == data.bytes[offset-1] { + offset += 1; + } + } // Single character + else { + offset += 1; + } + + token := extract_string(data, data.offset, offset); + + // Ignore __attribute__ + if token == "__attribute__" { + print_warning("__attribute__ is ignored."); + + for data.bytes[offset] != '(' { + offset += 1; + } + + parenthesesCount := 1; + for true { + offset += 1; + if data.bytes[offset] == '(' do parenthesesCount += 1; + else if data.bytes[offset] == ')' do parenthesesCount -= 1; + if parenthesesCount == 0 do break; + } + offset += 1; + + data.offset = offset; + } // Ignore certain keywords + else if (token == "inline" || token == "__inline" || token == "static" + || token == "restrict" || token == "__restrict" + || token == "volatile" + || token == "__extension__") { + data.offset = offset; + } // Ignore ignored tokens ;) + else { + for ignoredToken in data.options.ignoredTokens { + if token == ignoredToken { + data.offset = offset; + break; + } + } + } + + if data.offset != offset { + break; + } + } + + return offset; +} + +// Peek the next token (just eating whitespaces and comment) +peek_token :: proc(data : ^ParserData) -> string { + tokenEnd := peek_token_end(data); + if tokenEnd == data.bytesLength { + return "EOF"; + } + return extract_string(data, data.offset, tokenEnd); +} + +// Find the end of the define directive (understanding endline backslashes) +// @note Tricky cases like comments hiding a backslash effect are not handled. +peek_define_end :: proc(data : ^ParserData) -> u32 { + defineEndOffset := data.offset; + for data.bytes[defineEndOffset-1] == '\\' || data.bytes[defineEndOffset] != '\n' { + defineEndOffset += 1; + } + return defineEndOffset; +} + +eat_comment :: proc(data : ^ParserData) { + if data.offset >= data.bytesLength || data.bytes[data.offset] != '/' { + return; + } + + // Line comment + if data.bytes[data.offset + 1] == '/' { + eat_line(data); + } // Range comment + else if data.bytes[data.offset + 1] == '*' { + data.offset += 2; + for data.bytes[data.offset] != '*' || data.bytes[data.offset + 1] != '/' { + data.offset += 1; + } + data.offset += 2; + } +} + +// Eat whitespaces +eat_whitespaces :: proc(data : ^ParserData) { + // Effective whitespace + for data.offset < data.bytesLength && + (data.bytes[data.offset] == ' ' || data.bytes[data.offset] == '\t' || + data.bytes[data.offset] == '\r' || data.bytes[data.offset] == '\n') { + if data.bytes[data.offset] == '\n' && data.bytes[data.offset] != '\\' { + data.foundFullReturn = true; + } + data.offset += 1; + } +} + +// Removes whitespaces and comments +eat_whitespaces_and_comments :: proc(data : ^ParserData) { + startOffset : u32 = 0xFFFFFFFF; + for startOffset != data.offset { + startOffset = data.offset; + eat_whitespaces(data); + eat_comment(data); + } +} + +// Eat full line +eat_line :: proc(data : ^ParserData) { + for ; data.bytes[data.offset] != '\n'; data.offset += 1 { + } +} + +// Eat a line, and repeat if it ends with a backslash +eat_define_lines :: proc(data : ^ParserData) { + for data.bytes[data.offset-1] == '\\' || data.bytes[data.offset] != '\n' { + data.offset += 1; + } +} + +// Eat next token +eat_token :: proc(data : ^ParserData) { + data.offset = peek_token_end(data); +} + +// Eat next token +check_and_eat_token :: proc(data : ^ParserData, expectedToken : string, loc := #caller_location) { + token := peek_token(data); + if token != expectedToken { + print_error(data, loc, "Expected ", expectedToken, " but found ", token, "."); + } + data.offset += cast(u32) len(token); +} + +// Check whether the next token is outside #define range +is_define_end :: proc(data : ^ParserData) -> bool { + defineEnd := peek_define_end(data); + tokenEnd := peek_token_end(data); + + return (defineEnd < tokenEnd); +} + +// Check if the current #define is a macro definition +is_define_macro :: proc(data : ^ParserData) -> bool { + startOffset := data.offset; + defer data.offset = startOffset; + + token := parse_any(data); + if token != "(" do return false; + + // Find the other parenthesis + parenthesesCount := 1; + for parenthesesCount != 0 { + token = parse_any(data); + if token == "(" do parenthesesCount += 1; + else if token == ")" do parenthesesCount -= 1; + } + + // Its a macro if after the parentheses, it's not the end + return !is_define_end(data); +} + +// @note Very slow function to get line number, +// use only for errors. +// @todo Well, this does not seem to work properly, UTF-8 problem? +get_line_column :: proc(data : ^ParserData) -> (u32, u32) { + line : u32 = 1; + column : u32 = 0; + for i : u32 = 0; i < data.offset; i += 1 { + if data.bytes[i] == '\n' { + column = 0; + line += 1; + } + else { + column += 1; + } + } + return line, column; +} diff --git a/core/bindgen/c-parser-nodes.odin b/core/bindgen/c-parser-nodes.odin new file mode 100644 index 000000000..0620e0187 --- /dev/null +++ b/core/bindgen/c-parser-nodes.odin @@ -0,0 +1,132 @@ +package bindgen + +DefineNode :: struct { + name : string, + value : LiteralValue, +} + +StructDefinitionNode :: struct { + name : string, + members : [dynamic]StructOrUnionMember, + forwardDeclared : bool, +} + +UnionDefinitionNode :: struct { + name : string, + members : [dynamic]StructOrUnionMember, +} + +EnumDefinitionNode :: struct { + name : string, + members : [dynamic]EnumMember, +} + +FunctionDeclarationNode :: struct { + name : string, + returnType : Type, + parameters : [dynamic]FunctionParameter, +} + +TypedefNode :: struct { + name : string, + type : Type, +} + +Nodes :: struct { + defines : [dynamic]DefineNode, + enumDefinitions : [dynamic]EnumDefinitionNode, + unionDefinitions : [dynamic]UnionDefinitionNode, + structDefinitions : [dynamic]StructDefinitionNode, + functionDeclarations : [dynamic]FunctionDeclarationNode, + typedefs : [dynamic]TypedefNode, +} + +LiteralValue :: union { + i64, + f64, + string, +} + +// Type, might be an array +Type :: struct { + base : BaseType, + dimensions : [dynamic]u64, // Array dimensions +} + +BaseType :: union { + BuiltinType, + PointerType, + IdentifierType, + FunctionType, + FunctionPointerType, +} + +BuiltinType :: enum { + Unknown, + Void, + Int, + UInt, + LongInt, + ULongInt, + LongLongInt, + ULongLongInt, + ShortInt, + UShortInt, + Char, + SChar, + UChar, + Float, + Double, + LongDouble, + + // Not defined by C language but in + Int8, + Int16, + Int32, + Int64, + UInt8, + UInt16, + UInt32, + UInt64, + Size, + SSize, + PtrDiff, + UIntPtr, + IntPtr, +} + +PointerType :: struct { + type : ^Type, // Pointer is there to prevent definition cycle. Null means void. +} + +IdentifierType :: struct { + name : string, + anonymous : bool, // An anonymous identifier can be hard-given a name in some contexts. +} + +FunctionType :: struct { + returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void. + parameters : [dynamic]FunctionParameter, +} + +FunctionPointerType :: struct { + name : string, + returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void. + parameters : [dynamic]FunctionParameter, +} + +EnumMember :: struct { + name : string, + value : i64, + hasValue : bool, +} + +StructOrUnionMember :: struct { + name : string, + type : Type, +} + +FunctionParameter :: struct { + name : string, + type : Type, +} diff --git a/core/bindgen/c-parser.odin b/core/bindgen/c-parser.odin new file mode 100644 index 000000000..c3ef4937f --- /dev/null +++ b/core/bindgen/c-parser.odin @@ -0,0 +1,840 @@ +package bindgen + +import "core:os" +import "core:fmt" +import "core:strings" +import "core:strconv" + +// Global counters +anonymousStructCount := 0; +anonymousUnionCount := 0; +anonymousEnumCount := 0; + +knownTypeAliases : map[string]Type; + +CustomHandler :: proc(data : ^ParserData); +CustomExpressionHandler :: proc(data : ^ParserData) -> LiteralValue; + +ParserOptions :: struct { + ignoredTokens : []string, + + // Handlers + customHandlers : map[string]CustomHandler, + customExpressionHandlers : map[string]CustomExpressionHandler, +} + +ParserData :: struct { + bytes : []u8, + bytesLength : u32, + offset : u32, + + // References + nodes : Nodes, + options : ^ParserOptions, + + // Knowned values + knownedLiterals : map[string]LiteralValue, + + // Whether we have eaten a '\n' character that has no backslash just before + foundFullReturn : bool, +} + +is_identifier :: proc(token : string) -> bool { + return (token[0] >= 'a' && token[0] <= 'z') || + (token[0] >= 'A' && token[0] <= 'Z') || + (token[0] == '_'); +} + +parse :: proc(bytes : []u8, options : ParserOptions, loc := #caller_location) -> Nodes { + options := options; + + data : ParserData; + data.bytes = bytes; + data.bytesLength = cast(u32) len(bytes); + data.options = &options; + + for data.offset = 0; data.offset < data.bytesLength; { + token := peek_token(&data); + if data.offset == data.bytesLength do break; + + if token in options.customHandlers { + options.customHandlers[token](&data); + } + else if token == "{" || token == "}" || token == ";" { + eat_token(&data); + } + else if token == "extern" { + check_and_eat_token(&data, "extern"); + } + else if token == "\"C\"" { + check_and_eat_token(&data, "\"C\""); + } + else if token == "#" { + parse_directive(&data); + } + else if token == "typedef" { + parse_typedef(&data); + } + else if is_identifier(token) { + parse_variable_or_function_declaration(&data); + } + else { + print_error(&data, loc, "Unexpected token: ", token, "."); + return data.nodes; + } + } + + return data.nodes; +} + +parse_any :: proc(data : ^ParserData) -> string { + offset := peek_token_end(data); + identifier := extract_string(data, data.offset, offset); + data.offset = offset; + return identifier; +} + +parse_identifier :: proc(data : ^ParserData, loc := #caller_location) -> string { + identifier := parse_any(data); + + if (identifier[0] < 'a' || identifier[0] > 'z') && + (identifier[0] < 'A' || identifier[0] > 'Z') && + (identifier[0] != '_') { + print_error(data, loc, "Expected identifier but found ", identifier, "."); + } + + return identifier; +} + +parse_type_dimensions :: proc(data : ^ParserData, type : ^Type) { + token := peek_token(data); + for token == "[" { + eat_token(data); + token = peek_token(data); + if token == "]" { + pointerType : PointerType; + pointerType.type = new(Type); + pointerType.type^ = type^; // Copy + type.base = pointerType; + delete(type.dimensions); + } else { + dimension := evaluate_i64(data); + append(&type.dimensions, cast(u64) dimension); + } + check_and_eat_token(data, "]"); + token = peek_token(data); + } +} + +// This will parse anything that look like a type: +// Builtin: char/int/float/... +// Struct-like: struct A/struct { ... }/enum E +// Function pointer: void (*f)(...) +// +// Definition permitted: If a struct-like definition is found, it will generate +// the according Node and return a corresponding type. +parse_type :: proc(data : ^ParserData, definitionPermitted := false) -> Type { + type : Type; + + // Eat qualifiers + token := peek_token(data); + if token == "const" { + eat_token(data); + token = peek_token(data); + } + + // Parse main type + if token == "struct" { + type.base = parse_struct_type(data, definitionPermitted); + } + else if token == "union" { + type.base = parse_union_type(data); + } + else if token == "enum" { + type.base = parse_enum_type(data); + } + else { + // Test builtin type + type.base = parse_builtin_type(data); + if type.base.(BuiltinType) == BuiltinType.Unknown { + // Basic identifier type + identifierType : IdentifierType; + identifierType.name = parse_identifier(data); + type.base = identifierType; + } + } + + // Eat qualifiers + token = peek_token(data); + if token == "const" { + eat_token(data); + token = peek_token(data); + } + + // Check if pointer + for token == "*" { + check_and_eat_token(data, "*"); + token = peek_token(data); + + pointerType : PointerType; + pointerType.type = new(Type); + pointerType.type^ = type; // Copy + + type.base = pointerType; + + // Eat qualifiers + if token == "const" { + eat_token(data); + token = peek_token(data); + } + } + + // Parse array dimensions if any. + parse_type_dimensions(data, &type); + + // ----- Function pointer type + + if token == "(" { + check_and_eat_token(data, "("); + check_and_eat_token(data, "*"); + + functionPointerType : FunctionPointerType; + functionPointerType.returnType = new(Type); + functionPointerType.returnType^ = type; + functionPointerType.name = parse_identifier(data); + + check_and_eat_token(data, ")"); + parse_function_parameters(data, &functionPointerType.parameters); + + type.base = functionPointerType; + } + + return type; +} + +parse_builtin_type :: proc(data : ^ParserData) -> BuiltinType { + previousBuiltinType := BuiltinType.Unknown; + intFound := false; + shortFound := false; + signedFound := false; + unsignedFound := false; + longCount := 0; + + for true { + token := peek_token(data); + + // Attribute + attributeFound := true; + if token == "long" do longCount += 1; + else if token == "short" do shortFound = true; + else if token == "unsigned" do unsignedFound = true; + else if token == "signed" do signedFound = true; + else do attributeFound = false; + if attributeFound { eat_token(data); continue; } + + // Known type alias + if token in knownTypeAliases { + builtinType, ok := knownTypeAliases[token].base.(BuiltinType); + if ok { + eat_token(data); + previousBuiltinType = builtinType; + } + break; + } + + // Classic type and standard types + if token == "void" { eat_token(data); return BuiltinType.Void; } + else if token == "int" { + eat_token(data); + intFound = true; + } + else if token == "float" { eat_token(data); return BuiltinType.Float; } + else if token == "double" { + eat_token(data); + if longCount == 0 do return BuiltinType.Double; + else do return BuiltinType.LongDouble; + } + else if token == "char" { + eat_token(data); + if signedFound do return BuiltinType.SChar; + else if unsignedFound do return BuiltinType.UChar; + else do return BuiltinType.Char; + } + else if token == "__int8" { + // @note :MicrosoftDumminess __intX are Microsoft's fixed-size integers + // https://docs.microsoft.com/fr-fr/cpp/cpp/int8-int16-int32-int64 + // and for unsigned version, they prefixed it with "unsigned"... + eat_token(data); + if unsignedFound do return BuiltinType.UInt8; + else do return BuiltinType.Int8; + } + else if token == "__int16" { + eat_token(data); + if unsignedFound do return BuiltinType.UInt16; + else do return BuiltinType.Int16; + } + else if token == "__int32" { + eat_token(data); + if unsignedFound do return BuiltinType.UInt32; + else do return BuiltinType.Int32; + } + else if token == "__int64" { + eat_token(data); + if unsignedFound do return BuiltinType.UInt64; + else do return BuiltinType.Int64; + } + else if token == "int8_t" { eat_token(data); return BuiltinType.Int8; } + else if token == "int16_t" { eat_token(data); return BuiltinType.Int16; } + else if token == "int32_t" { eat_token(data); return BuiltinType.Int32; } + else if token == "int64_t" { eat_token(data); return BuiltinType.Int64; } + else if token == "uint8_t" { eat_token(data); return BuiltinType.UInt8; } + else if token == "uint16_t" { eat_token(data); return BuiltinType.UInt16; } + else if token == "uint32_t" { eat_token(data); return BuiltinType.UInt32; } + else if token == "uint64_t" { eat_token(data); return BuiltinType.UInt64; } + else if token == "size_t" { eat_token(data); return BuiltinType.Size; } + else if token == "ssize_t" { eat_token(data); return BuiltinType.SSize; } + else if token == "ptrdiff_t" { eat_token(data); return BuiltinType.PtrDiff; } + else if token == "uintptr_t" { eat_token(data); return BuiltinType.UIntPtr; } + else if token == "intptr_t" { eat_token(data); return BuiltinType.IntPtr; } + + break; + } + + // Adapt previous builtin type + if previousBuiltinType == BuiltinType.ShortInt { + shortFound = true; + } + else if previousBuiltinType == BuiltinType.Int { + intFound = true; + } + else if previousBuiltinType == BuiltinType.LongInt { + longCount += 1; + } + else if previousBuiltinType == BuiltinType.LongLongInt { + longCount += 2; + } + else if previousBuiltinType == BuiltinType.UShortInt { + unsignedFound = true; + shortFound = true; + } + else if previousBuiltinType == BuiltinType.UInt { + unsignedFound = true; + } + else if previousBuiltinType == BuiltinType.ULongInt { + unsignedFound = true; + longCount += 1; + } + else if previousBuiltinType == BuiltinType.ULongLongInt { + unsignedFound = true; + longCount += 2; + } + else if (previousBuiltinType != BuiltinType.Unknown) { + return previousBuiltinType; // float, void, etc. + } + + // Implicit and explicit int + if intFound || shortFound || unsignedFound || signedFound || longCount > 0 { + if unsignedFound { + if shortFound do return BuiltinType.UShortInt; + if longCount == 0 do return BuiltinType.UInt; + if longCount == 1 do return BuiltinType.ULongInt; + if longCount == 2 do return BuiltinType.ULongLongInt; + } else { + if shortFound do return BuiltinType.ShortInt; + if longCount == 0 do return BuiltinType.Int; + if longCount == 1 do return BuiltinType.LongInt; + if longCount == 2 do return BuiltinType.LongLongInt; + } + } + + return BuiltinType.Unknown; +} + +parse_struct_type :: proc(data : ^ParserData, definitionPermitted : bool) -> IdentifierType { + check_and_eat_token(data, "struct"); + + type : IdentifierType; + token := peek_token(data); + + if !definitionPermitted || token != "{" { + type.name = parse_identifier(data); + token = peek_token(data); + } else { + type.name = tcat("AnonymousStruct", anonymousStructCount); + type.anonymous = true; + anonymousStructCount += 1; + } + + if token == "{" { + node := parse_struct_definition(data); + node.name = type.name; + } else if definitionPermitted { + // @note Whatever happens, we create a definition of the struct, + // as it might be used to forward declare it and then use it only with a pointer. + // This for instance the pattern for xcb_connection_t which definition + // is never known from user API. + node : StructDefinitionNode; + node.forwardDeclared = false; + node.name = type.name; + append(&data.nodes.structDefinitions, node); + } + + return type; +} + +parse_union_type :: proc(data : ^ParserData) -> IdentifierType { + check_and_eat_token(data, "union"); + + type : IdentifierType; + token := peek_token(data); + + if token != "{" { + type.name = parse_identifier(data); + token = peek_token(data); + } else { + type.name = tcat("AnonymousUnion", anonymousUnionCount); + type.anonymous = true; + anonymousUnionCount += 1; + } + + if token == "{" { + node := parse_union_definition(data); + node.name = type.name; + } + + return type; +} + +parse_enum_type :: proc(data : ^ParserData) -> IdentifierType { + check_and_eat_token(data, "enum"); + + type : IdentifierType; + token := peek_token(data); + + if token != "{" { + type.name = parse_identifier(data); + token = peek_token(data); + } else { + type.name = tcat("AnonymousEnum", anonymousEnumCount); + type.anonymous = true; + anonymousEnumCount += 1; + } + + if token == "{" { + node := parse_enum_definition(data); + node.name = type.name; + } + + return type; +} + +/** + * We only care about defines of some value + */ +parse_directive :: proc(data : ^ParserData) { + check_and_eat_token(data, "#"); + + token := peek_token(data); + if token == "define" { + parse_define(data); + } // We ignore all other directives + else { + eat_line(data); + } +} + +parse_define :: proc(data : ^ParserData) { + check_and_eat_token(data, "define"); + data.foundFullReturn = false; + + node : DefineNode; + node.name = parse_identifier(data); + + // Does it look like end? It might be a #define with no expression + if is_define_end(data) { + node.value = 1; + append(&data.nodes.defines, node); + data.knownedLiterals[node.name] = node.value; + } // Macros are ignored + else if is_define_macro(data) { + print_warning("Ignoring define macro for ", node.name, "."); + } + else { + literalValue, ok := evaluate(data); + if ok { + node.value = literalValue; + append(&data.nodes.defines, node); + data.knownedLiterals[node.name] = node.value; + } + else { + print_warning("Ignoring define expression for ", node.name, "."); + } + } + + // Evaluating the expression, we might have already eaten a full return, + // if so, do nothing. + if !data.foundFullReturn { + eat_define_lines(data); + } +} + +// @fixme Move +change_anonymous_node_name :: proc (data : ^ParserData, oldName : string, newName : string) -> bool { + for i := 0; i < len(data.nodes.structDefinitions); i += 1 { + if data.nodes.structDefinitions[i].name == oldName { + data.nodes.structDefinitions[i].name = newName; + return true; + } + } + + for i := 0; i < len(data.nodes.enumDefinitions); i += 1 { + if data.nodes.enumDefinitions[i].name == oldName { + data.nodes.enumDefinitions[i].name = newName; + return true; + } + } + + for i := 0; i < len(data.nodes.unionDefinitions); i += 1 { + if data.nodes.unionDefinitions[i].name == oldName { + data.nodes.unionDefinitions[i].name = newName; + return true; + } + } + + return false; +} + +/** + * Type aliasing. + * typedef ; + */ +parse_typedef :: proc(data : ^ParserData) { + check_and_eat_token(data, "typedef"); + + // @note Struct-like definitions (and such) + // are generated within type parsing. + // + // So that typedef struct { int foo; }* Ap; is valid. + + // Parsing type + node : TypedefNode; + node.type = parse_type(data, true); + + if sourceType, ok := node.type.base.(FunctionPointerType); ok { + node.name = sourceType.name; + } else { + node.name = parse_identifier(data); + } + + // Checking if function type + token := peek_token(data); + if token == "(" { + functionType : FunctionType; + functionType.returnType = new(Type); + functionType.returnType^ = node.type; + + parse_function_parameters(data, &functionType.parameters); + + node.type.base = functionType; + } + + // Checking if array + parse_type_dimensions(data, &node.type); + + // If the underlying type is anonymous, + // we just affect it the name. + addTypedefNode := true; + if identifierType, ok := node.type.base.(IdentifierType); ok { + if identifierType.anonymous { + addTypedefNode = !change_anonymous_node_name(data, identifierType.name, node.name); + } + } + + if addTypedefNode { + knownTypeAliases[node.name] = node.type; + append(&data.nodes.typedefs, node); + } + + check_and_eat_token(data, ";"); + + // @note Commented tool for debug + // fmt.println("Typedef: ", node.type, node.name); +} + +parse_struct_definition :: proc(data : ^ParserData) -> ^StructDefinitionNode { + node : StructDefinitionNode; + node.forwardDeclared = false; + parse_struct_or_union_members(data, &node.members); + + append(&data.nodes.structDefinitions, node); + return &data.nodes.structDefinitions[len(data.nodes.structDefinitions) - 1]; +} + +parse_union_definition :: proc(data : ^ParserData) -> ^UnionDefinitionNode { + node : UnionDefinitionNode; + parse_struct_or_union_members(data, &node.members); + + append(&data.nodes.unionDefinitions, node); + return &data.nodes.unionDefinitions[len(data.nodes.unionDefinitions) - 1]; +} + +parse_enum_definition :: proc(data : ^ParserData) -> ^EnumDefinitionNode { + node : EnumDefinitionNode; + parse_enum_members(data, &node.members); + + append(&data.nodes.enumDefinitions, node); + return &data.nodes.enumDefinitions[len(data.nodes.enumDefinitions) - 1]; +} + +/** + * { + * = , + * , + * } + */ +parse_enum_members :: proc(data : ^ParserData, members : ^[dynamic]EnumMember) { + check_and_eat_token(data, "{"); + + nextMemberValue : i64 = 0; + token := peek_token(data); + for token != "}" { + member : EnumMember; + member.name = parse_identifier(data); + member.hasValue = false; + + token = peek_token(data); + if token == "=" { + check_and_eat_token(data, "="); + + member.hasValue = true; + member.value = evaluate_i64(data); + nextMemberValue = member.value; + token = peek_token(data); + } else { + member.value = nextMemberValue; + } + + data.knownedLiterals[member.name] = member.value; + nextMemberValue += 1; + + // Eat until end, as this might be a complex expression that we couldn't understand + if token != "," && token != "}" { + print_warning("Parser cannot understand fully the expression of enum member ", member.name, "."); + for token != "," && token != "}" { + eat_token(data); + token = peek_token(data); + } + } + if token == "," { + check_and_eat_token(data, ","); + token = peek_token(data); + } + + append(members, member); + } + + check_and_eat_token(data, "}"); +} + +/** + * { + * ; + * , ; + * []; + * } + */ +parse_struct_or_union_members :: proc(data : ^ParserData, structOrUnionMembers : ^[dynamic]StructOrUnionMember) { + check_and_eat_token(data, "{"); + + // To ensure unique id + unamedCount := 0; + + token := peek_token(data); + for token != "}" { + member : StructOrUnionMember; + member.type = parse_type(data, true); + + for true { + // In the case of function pointer types, the name has been parsed + // during type inspection. + if type, ok := member.type.base.(FunctionPointerType); ok { + member.name = type.name; + } + else { + // Unamed (struct or union) + token = peek_token(data); + if !is_identifier(token) { + member.name = tcat("unamed", unamedCount); + unamedCount += 1; + } + else { + member.name = parse_identifier(data); + } + } + + parse_type_dimensions(data, &member.type); + + token = peek_token(data); + if token == ":" { + check_and_eat_token(data, ":"); + print_warning("Found bitfield in struct, which is not handled correctly."); + evaluate_i64(data); + token = peek_token(data); + } + + append(structOrUnionMembers, member); + + // Multiple declarations on one line + if token == "," { + check_and_eat_token(data, ","); + continue; + } + + break; + } + + check_and_eat_token(data, ";"); + token = peek_token(data); + } + + check_and_eat_token(data, "}"); +} + +parse_variable_or_function_declaration :: proc(data : ^ParserData) { + type := parse_type(data, true); + + // If it's just a type, it might be a struct definition + token := peek_token(data); + if token == ";" { + check_and_eat_token(data, ";"); + return; + } + + // Eat array declaration if any + // @fixme The return type of a function declaration will be wrong! + for data.bytes[data.offset] == '[' { + for data.bytes[data.offset] != ']' { + data.offset += 1; + } + data.offset += 1; + } + + name := parse_identifier(data); + + token = peek_token(data); + if token == "(" { + functionDeclarationNode := parse_function_declaration(data); + functionDeclarationNode.returnType = type; + functionDeclarationNode.name = name; + return; + } else if token == "[" { + // Eat whole array declaration + for data.bytes[data.offset] == '[' { + for data.bytes[data.offset] != ']' { + data.offset += 1; + } + data.offset += 1; + } + } + + // Global variable declaration (with possible multiple declarations) + token = peek_token(data); + + for true { + if token == "," { + print_warning("Found global variable declaration '", name, "', we won't generated any binding for it."); + check_and_eat_token(data, ","); + + name = parse_identifier(data); + token = peek_token(data); + continue; + } + else if token == ";" { + if name != "" { + print_warning("Found global variable declaration '", name, "', we won't generated any binding for it."); + } + check_and_eat_token(data, ";"); + break; + } + + // Global variable assignment, considered as constant define. + node : DefineNode; + + check_and_eat_token(data, "="); + literalValue, ok := evaluate(data); + if ok { + node.name = name; + node.value = literalValue; + append(&data.nodes.defines, node); + } + else { + print_warning("Ignoring global variable expression for '", name, "'."); + } + + name = ""; + token = peek_token(data); + } +} + +parse_function_declaration :: proc(data : ^ParserData) -> ^FunctionDeclarationNode { + node : FunctionDeclarationNode; + + parse_function_parameters(data, &node.parameters); + + // Function definition? Ignore it. + token := peek_token(data); + if token == "{" { + bracesCount := 1; + for true { + data.offset += 1; + if data.bytes[data.offset] == '{' do bracesCount += 1; + else if data.bytes[data.offset] == '}' do bracesCount -= 1; + if bracesCount == 0 do break; + } + data.offset += 1; + } // Function declaration + else { + check_and_eat_token(data, ";"); + } + + append(&data.nodes.functionDeclarations, node); + return &data.nodes.functionDeclarations[len(data.nodes.functionDeclarations) - 1]; +} + +parse_function_parameters :: proc(data : ^ParserData, parameters : ^[dynamic]FunctionParameter) { + check_and_eat_token(data, "("); + + token := peek_token(data); + for token != ")" { + parameter : FunctionParameter; + + token = peek_token(data); + if token == "." { + print_warning("A function accepts variadic arguments, this is currently not handled within generated code."); + + check_and_eat_token(data, "."); + check_and_eat_token(data, "."); + check_and_eat_token(data, "."); + break; + } else { + parameter.type = parse_type(data); + } + + // Check if named parameter + token = peek_token(data); + if token != ")" && token != "," { + parameter.name = parse_identifier(data); + parse_type_dimensions(data, ¶meter.type); + token = peek_token(data); + } + + if token == "," { + eat_token(data); + token = peek_token(data); + } + + append(parameters, parameter); + } + + check_and_eat_token(data, ")"); +} diff --git a/core/bindgen/errors.odin b/core/bindgen/errors.odin new file mode 100644 index 000000000..9564c5244 --- /dev/null +++ b/core/bindgen/errors.odin @@ -0,0 +1,44 @@ +package bindgen + +import "core:fmt" +import "core:os" + +seenWarnings : map[string]bool; + +print_warning :: proc(args : ..any) { + message := tcat(..args); + + if !seenWarnings[message] { + fmt.eprint("[bindgen] Warning: ", message, "\n"); + seenWarnings[message] = true; + } +} + +print_error :: proc(data : ^ParserData, loc := #caller_location, args : ..any) { + message := tcat(..args); + + min : u32 = 0; + for i := data.offset - 1; i > 0; i -= 1 { + if data.bytes[i] == '\n' { + min = i + 1; + break; + } + } + + max := min + 200; + for i := min + 1; i < max; i += 1 { + if data.bytes[i] == '\n' { + max = i; + break; + } + } + + line, _ := get_line_column(data); + + fmt.eprint("[bindgen] Error: ", message, "\n"); + fmt.eprint("[bindgen] ... from ", loc.procedure, "\n"); + fmt.eprint("[bindgen] ... at line ", line, " within this context:\n"); + fmt.eprint("> ", extract_string(data, min, max), "\n"); + + os.exit(1); +} diff --git a/core/bindgen/generator-clean.odin b/core/bindgen/generator-clean.odin new file mode 100644 index 000000000..8dd837b10 --- /dev/null +++ b/core/bindgen/generator-clean.odin @@ -0,0 +1,284 @@ +package bindgen + +import "core:fmt" + +// Prevent keywords clashes and other tricky cases +clean_identifier :: proc(name : string) -> string { + name := name; + + if name == "" { + return name; + } + + // Starting with _? Try removing that. + for true { + if name[0] == '_' { + name = name[1:]; + } + else { + break; + } + } + + // Number + if name[0] >= '0' && name[0] <= '9' { + return tcat("_", name); + } // Keywords clash + else if name == "map" || name == "proc" || name == "opaque" || name == "in" { + return tcat("_", name); + } // Jai keywords clash + else if name == "context" || + name == "float32" || name == "float64" || + name == "s8" || name == "s16" || name == "s32" || name == "s64" || + name == "u8" || name == "u16" || name == "u32" || name == "u64" { + return tcat("_", name); + } + + return name; +} + +clean_variable_name :: proc(name : string, options : ^GeneratorOptions) -> string { + name := name; + name = change_case(name, options.variableCase); + return clean_identifier(name); +} + +clean_pseudo_type_name :: proc(structName : string, options : ^GeneratorOptions) -> string { + structName := structName; + structName = remove_postfixes(structName, options.pseudoTypePostfixes, options.pseudoTypeTransparentPostfixes); + structName = remove_prefixes(structName, options.pseudoTypePrefixes, options.pseudoTypeTransparentPrefixes); + structName = change_case(structName, options.pseudoTypeCase); + return structName; +} + +// Clean up the enum name so that it can be used to remove the prefix from enum values. +clean_enum_name_for_prefix_removal :: proc(enumName : string, options : ^GeneratorOptions) -> (string, [dynamic]string) { + enumName := enumName; + + if !options.enumValueNameRemove { + return enumName, nil; + } + + // Remove postfix and use same case convention as the enum values + removedPostfixes : [dynamic]string; + enumName, removedPostfixes = remove_postfixes_with_removed(enumName, options.enumValueNameRemovePostfixes); + enumName = change_case(enumName, options.enumValueCase); + return enumName, removedPostfixes; +} + +clean_enum_value_name :: proc(valueName : string, enumName : string, postfixes : []string, options : ^GeneratorOptions) -> string { + valueName := valueName; + + valueName = remove_prefixes(valueName, options.enumValuePrefixes, options.enumValueTransparentPrefixes); + valueName = remove_postfixes(valueName, postfixes, options.enumValueTransparentPostfixes); + + if options.enumValueNameRemove { + valueName = remove_prefixes(valueName, []string{enumName}); + } + + valueName = change_case(valueName, options.enumValueCase); + + return clean_identifier(valueName); +} + +clean_function_name :: proc(functionName : string, options : ^GeneratorOptions) -> string { + functionName := functionName; + functionName = remove_prefixes(functionName, options.functionPrefixes, options.functionTransparentPrefixes); + functionName = remove_postfixes(functionName, options.definePostfixes, options.defineTransparentPostfixes); + functionName = change_case(functionName, options.functionCase); + return functionName; +} + +clean_define_name :: proc(defineName : string, options : ^GeneratorOptions) -> string { + defineName := defineName; + defineName = remove_prefixes(defineName, options.definePrefixes, options.defineTransparentPrefixes); + defineName = remove_postfixes(defineName, options.definePostfixes, options.defineTransparentPostfixes); + defineName = change_case(defineName, options.defineCase); + return defineName; +} + +// Convert to Odin's types +clean_type :: proc(data : ^GeneratorData, type : Type, baseTab : string = "", explicitSharpType := true) -> string { + output := ""; + + for dimension in type.dimensions { + output = tcat(output, "[", dimension, "]"); + } + output = tcat(output, clean_base_type(data, type.base, baseTab, explicitSharpType)); + + return output; +} + +clean_base_type :: proc(data : ^GeneratorData, baseType : BaseType, baseTab : string = "", explicitSharpType := true) -> string { + options := data.options; + + if _type, ok := baseType.(BuiltinType); ok { + if _type == BuiltinType.Void do return options.mode == "jai" ? "void" : ""; + else if _type == BuiltinType.Int do return options.mode == "jai" ? "s64" : "_c.int"; + else if _type == BuiltinType.UInt do return options.mode == "jai" ? "u64" :"_c.uint"; + else if _type == BuiltinType.LongInt do return options.mode == "jai" ? "s64" :"_c.long"; + else if _type == BuiltinType.ULongInt do return options.mode == "jai" ? "u64" :"_c.ulong"; + else if _type == BuiltinType.LongLongInt do return options.mode == "jai" ? "s64" :"_c.longlong"; + else if _type == BuiltinType.ULongLongInt do return options.mode == "jai" ? "u64" :"_c.ulonglong"; + else if _type == BuiltinType.ShortInt do return options.mode == "jai" ? "s16" :"_c.short"; + else if _type == BuiltinType.UShortInt do return options.mode == "jai" ? "u16" :"_c.ushort"; + else if _type == BuiltinType.Char do return options.mode == "jai" ? "u8" :"_c.char"; + else if _type == BuiltinType.SChar do return options.mode == "jai" ? "s8" :"_c.schar"; + else if _type == BuiltinType.UChar do return options.mode == "jai" ? "u8" :"_c.uchar"; + else if _type == BuiltinType.Float do return options.mode == "jai" ? "float32" :"_c.float"; + else if _type == BuiltinType.Double do return options.mode == "jai" ? "float64" :"_c.double"; + else if _type == BuiltinType.LongDouble { + print_warning("Found long double which is currently not supported. Fallback to double in generated code."); + return options.mode == "jai" ? "double" :"_c.double"; + } + else if _type == BuiltinType.Int8 do return options.mode == "jai" ? "s8" :"i8"; + else if _type == BuiltinType.Int16 do return options.mode == "jai" ? "s16" :"i16"; + else if _type == BuiltinType.Int32 do return options.mode == "jai" ? "s32" :"i32"; + else if _type == BuiltinType.Int64 do return options.mode == "jai" ? "s64" :"i64"; + else if _type == BuiltinType.UInt8 do return options.mode == "jai" ? "u8" :"u8"; + else if _type == BuiltinType.UInt16 do return options.mode == "jai" ? "u16" :"u16"; + else if _type == BuiltinType.UInt32 do return options.mode == "jai" ? "u32" :"u32"; + else if _type == BuiltinType.UInt64 do return options.mode == "jai" ? "u64" :"u64"; + else if _type == BuiltinType.Size do return options.mode == "jai" ? "u64" :"_c.size_t"; + else if _type == BuiltinType.SSize do return options.mode == "jai" ? "u64" :"_c.ssize_t"; + else if _type == BuiltinType.PtrDiff do return options.mode == "jai" ? "s64" :"_c.ptrdiff_t"; + else if _type == BuiltinType.UIntPtr do return options.mode == "jai" ? "u64" :"_c.uintptr_t"; + else if _type == BuiltinType.IntPtr do return options.mode == "jai" ? "s64" :"_c.intptr_t"; + } + else if _type, ok := baseType.(PointerType); ok { + if options.mode == "jai" { + // Hide pointers to types that were not declared. + if !is_known_base_type(data, _type.type.base) { + print_warning("*", _type.type.base.(IdentifierType).name, " replaced by *void as the pointed type is unknown."); + return "*void"; + } + } else { + if __type, ok := _type.type.base.(BuiltinType); ok { + if __type == BuiltinType.Void do return "rawptr"; + else if __type == BuiltinType.Char do return "cstring"; + } + } + name := clean_type(data, _type.type^, baseTab); + return tcat(options.mode == "jai" ? "*" :"^", name); + } + else if _type, ok := baseType.(IdentifierType); ok { + return clean_pseudo_type_name(_type.name, options); + } + else if _type, ok := baseType.(FunctionType); ok { + output : string; + if explicitSharpType { + output = "#type "; + } + output = tcat(output, options.mode == "jai" ? "(" :"proc("); + parameters := clean_function_parameters(data, _type.parameters, baseTab); + output = tcat(output, parameters, ")"); + + returnType := clean_type(data, _type.returnType^); + if len(returnType) > 0 && returnType != "void" { + output = tcat(output, " -> ", returnType); + } + return output; + } + else if _type, ok := baseType.(FunctionPointerType); ok { + output : string; + if explicitSharpType { + output = "#type "; + } + output = tcat(output, options.mode == "jai" ? "(" :"proc("); + parameters := clean_function_parameters(data, _type.parameters, baseTab); + output = tcat(output, parameters, ")"); + + returnType := clean_type(data, _type.returnType^); + if len(returnType) > 0 && returnType != "void" { + output = tcat(output, " -> ", returnType); + } + + if options.mode == "jai" { + output = tcat(output, " #foreign"); + } + return output; + } + + return ""; +} + +clean_function_parameters :: proc(data : ^GeneratorData, parameters : [dynamic]FunctionParameter, baseTab : string) -> string { + output := ""; + options := data.options; + + // Special case: function(void) does not really have a parameter + if len(parameters) == 1 { + if _type, ok := parameters[0].type.base.(BuiltinType); ok { + if _type == BuiltinType.Void { + return ""; + } + } + } + + tab := ""; + if options.mode == "jai" { // @note :OdinCodingStyle Odin forces a coding style, now. Ugh. + if (len(parameters) > 1) { + output = tcat(output, "\n"); + tab = tcat(baseTab, " "); + } + } + + unamedParametersCount := 0; + for parameter, i in parameters { + type := clean_type(data, parameter.type); + + name : string; + if len(parameter.name) != 0 { + name = clean_variable_name(parameter.name, options); + } else { + name = tcat("unamed", unamedParametersCount); + unamedParametersCount += 1; + } + + output = tcat(output, tab, name, " : ", type); + + if i != len(parameters) - 1 { + if options.mode == "jai" { // @note :OdinCodingStyle + output = tcat(output, ",\n"); + } else { + output = tcat(output, ", "); + } + } + } + + if (len(parameters) > 1) { + if options.mode == "jai" { // @note :OdinCodingStyle + output = tcat(output, "\n", baseTab); + } + } + + return output; +} + +is_known_base_type :: proc(data : ^GeneratorData, baseType : BaseType) -> bool { + if _type, ok := baseType.(IdentifierType); ok { + for it in data.nodes.typedefs { + if _type.name == it.name { + return true; + } + } + for it in data.nodes.structDefinitions { + if _type.name == it.name { + return true; + } + } + for it in data.nodes.enumDefinitions { + if _type.name == it.name { + return true; + } + } + for it in data.nodes.unionDefinitions { + if _type.name == it.name { + return true; + } + } + return false; + } + + return true; +} diff --git a/core/bindgen/generator-export.odin b/core/bindgen/generator-export.odin new file mode 100644 index 000000000..a04113ed9 --- /dev/null +++ b/core/bindgen/generator-export.odin @@ -0,0 +1,166 @@ +package bindgen + +import "core:os" +import "core:fmt" + +export_defines :: proc(data : ^GeneratorData) { + for node in data.nodes.defines { + defineName := clean_define_name(node.name, data.options); + + // @fixme fprint of float numbers are pretty badly handled, + // just has a 10^-3 precision. + fcat(data.handle, defineName, " :: ", node.value, ";\n"); + } + fcat(data.handle, "\n"); +} + +export_typedefs :: proc(data : ^GeneratorData) { + for node in data.nodes.typedefs { + name := clean_pseudo_type_name(node.name, data.options); + type := clean_type(data, node.type, "", true); + if name == type do continue; + fcat(data.handle, name, " :: ", type, ";\n"); + } + fcat(data.handle, "\n"); +} + +export_enums :: proc(data : ^GeneratorData) { + for node in data.nodes.enumDefinitions { + enumName := clean_pseudo_type_name(node.name, data.options); + + if data.options.mode == "jai" { + consideredFlags := false; + for postfix in data.options.enumConsideredFlagsPostfixes { + if ends_with(node.name, postfix) { + consideredFlags = true; + break; + } + } + + if consideredFlags { + fcat(data.handle, enumName, " :: enum_flags u32 {"); + } else { + fcat(data.handle, enumName, " :: enum s32 {"); + } + } else { + fcat(data.handle, enumName, " :: enum i32 {"); + } + + postfixes : [dynamic]string; + enumName, postfixes = clean_enum_name_for_prefix_removal(enumName, data.options); + + // Changing the case of postfixes to the enum value one, + // so that they can be removed. + enumValueCase := find_case(node.members[0].name); + for postfix, i in postfixes { + postfixes[i] = change_case(postfix, enumValueCase); + } + + // And changing the case of enumName to the enum value one + enumName = change_case(enumName, enumValueCase); + + // Merging enum value postfixes with postfixes that have been removed from the enum name. + for postfix in data.options.enumValuePostfixes { + append(&postfixes, postfix); + } + + export_enum_members(data, node.members, enumName, postfixes[:]); + fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); + fcat(data.handle, "\n"); + } +} + +export_structs :: proc(data : ^GeneratorData) { + for node in data.nodes.structDefinitions { + structName := clean_pseudo_type_name(node.name, data.options); + fcat(data.handle, structName, " :: struct {"); + export_struct_or_union_members(data, node.members); + fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); + fcat(data.handle, "\n"); + } +} + +export_unions :: proc(data : ^GeneratorData) { + for node in data.nodes.unionDefinitions { + unionName := clean_pseudo_type_name(node.name, data.options); + fcat(data.handle, unionName, data.options.mode == "jai" ? " :: union {" : " :: struct #raw_union {"); + export_struct_or_union_members(data, node.members); + fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); + fcat(data.handle, "\n"); + } +} + +export_functions :: proc(data : ^GeneratorData) { + for node in data.nodes.functionDeclarations { + functionName := clean_function_name(node.name, data.options); + if data.options.mode == "jai" { + fcat(data.handle, functionName, " :: ("); + } else { + fcat(data.handle, " @(link_name=\"", node.name, "\")\n"); + fcat(data.handle, " ", functionName, " :: proc("); + } + parameters := clean_function_parameters(data, node.parameters, data.options.mode == "jai" ? "" : " "); + fcat(data.handle, parameters, ")"); + returnType := clean_type(data, node.returnType); + if len(returnType) > 0 { + fcat(data.handle, " -> ", returnType); + } + if data.options.mode == "jai" { + fcat(data.handle, " #foreign ", data.foreignLibrary, " \"", node.name ,"\";\n"); + } else { + fcat(data.handle, " ---;\n"); + } + fcat(data.handle, "\n"); + } +} + +export_enum_members :: proc(data : ^GeneratorData, members : [dynamic]EnumMember, enumName : string, postfixes : []string) { + if (len(members) > 0) { + fcat(data.handle, "\n"); + } + + cleanedMembers : [dynamic]EnumMember; + for member in members { + cleanedMember : EnumMember; + cleanedMember.hasValue = member.hasValue; + cleanedMember.value = member.value; + cleanedMember.name = clean_enum_value_name(member.name, enumName, postfixes, data.options); + + if len(cleanedMember.name) == 0 { + // print_warning("Enum member ", member.name, " resolves to an empty name. Ignoring it."); + continue; + } + + // Ensuring that we don't collide with an other enum member. + foundCopy := false; + for existingCleanedMember in cleanedMembers { + if cleanedMember.name == existingCleanedMember.name && + cleanedMember.hasValue == existingCleanedMember.hasValue && + cleanedMember.value == existingCleanedMember.value { + print_warning("Enum member ", member.name, " is duplicated once cleaned. Keeping only one copy."); + foundCopy = true; + break; + } + } + if foundCopy do continue; + + fcat(data.handle, " ", cleanedMember.name); + if member.hasValue { + fcat(data.handle, data.options.mode == "jai" ? " :: " : " = ", member.value); + } + fcat(data.handle, data.options.mode == "jai" ? ";\n" : ",\n"); + + append(&cleanedMembers, cleanedMember); + } +} + +export_struct_or_union_members :: proc(data : ^GeneratorData, members : [dynamic]StructOrUnionMember) { + if (len(members) > 0) { + fcat(data.handle, "\n"); + } + for member in members { + type := clean_type(data, member.type, " "); + name := clean_variable_name(member.name, data.options); + fcat(data.handle, " ", name, " : ", type, data.options.mode == "jai" ? ";\n" : ",\n"); + } +} diff --git a/core/bindgen/generator-helpers.odin b/core/bindgen/generator-helpers.odin new file mode 100644 index 000000000..a3b37f4f6 --- /dev/null +++ b/core/bindgen/generator-helpers.odin @@ -0,0 +1,392 @@ +package bindgen + +import "core:fmt" +import "core:os" +import "core:io" +import "core:strings" +import "core:unicode/utf8" + +Case :: enum { + Unknown, + Camel, + Constant, + Kebab, + Pascal, + Snake, +} + +WordCase :: enum { + Unknown, + Up, + Low, + FirstUp, + // When first upping, numbers are followed always by a capital + FirstUpNumberReset, +} + +// Change a character to a capital. +to_uppercase :: proc(c : rune) -> rune { + c := c; + if c >= 'a' && c <= 'z' { + c = c - 'a' + 'A'; + } + return c; +} + +// Change a character to lowercase. +to_lowercase :: proc(c : rune) -> rune { + c := c; + if c >= 'A' && c <= 'Z' { + c = c - 'A' + 'a'; + } + return c; +} + +// @note Stolen tprint and fprint from fmt package, because it was confusing due to args: ..any and sep default parameter. +tcat :: proc(args: ..any) -> string { + return fmt.tprint(args=args, sep=""); +} + +fcat :: proc(fd: os.Handle, args: ..any) -> int { + return fmt.fprint(fd=fd, args=args, sep=""); +} + +// Change the case convention of a word. +change_word_case :: proc(str : string, targetCase : WordCase) -> string { + newStr : string; + if targetCase == WordCase.Up { + for c in str { + newStr = tcat(newStr, to_uppercase(c)); + } + } + else if targetCase == WordCase.Low { + for c in str { + newStr = tcat(newStr, to_lowercase(c)); + } + } + else if targetCase == WordCase.FirstUp { + for c, i in str { + if i == 0 { + newStr = tcat(newStr, to_uppercase(c)); + } else { + newStr = tcat(newStr, to_lowercase(c)); + } + } + } + else if targetCase == WordCase.FirstUpNumberReset { + for c, i in str { + if i == 0 || (str[i - 1] >= '0' && str[i - 1] <= '9') { + newStr = tcat(newStr, to_uppercase(c)); + } else { + newStr = tcat(newStr, to_lowercase(c)); + } + } + } + return newStr; +} + +// Change the case convention of a string by detecting original convention, +// then splitting it into words. +change_case :: proc(str : string, targetCase : Case) -> string { + if targetCase == Case.Unknown { + return str; + } + + // Split + parts := autosplit_string(str); + + // Join + newStr : string; + if targetCase == Case.Pascal { + for part, i in parts { + newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset)); + } + } + else if targetCase == Case.Snake { + for part, i in parts { + newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "_" : ""); + } + } + else if targetCase == Case.Kebab { + for part, i in parts { + newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "-" : ""); + } + } + else if targetCase == Case.Camel { + for part, i in parts { + if i == 0 { + newStr = tcat(newStr, change_word_case(part, WordCase.Low)); + } else { + newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset)); + } + } + } + else if targetCase == Case.Constant { + for part, i in parts { + newStr = tcat(newStr, change_word_case(part, WordCase.Up), (i != len(parts) - 1) ? "_" : ""); + } + } + + return newStr; +} + +// Identify the case of the provided string. +// Full lowercase with no separator is identified as camelCase. +find_case :: proc(str : string) -> Case { + refuted : bool; + + // CONSTANT_CASE + refuted = false; + for c in str { + if (c != '_') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') { + refuted = true; + break; + } + } + if !refuted do return Case.Constant; + + for c in str { + // snake_case + if c == '_' { + return Case.Snake; + } // kebab-case + else if c == '-' { + return Case.Kebab; + } + } + + // PascalCase + if str[0] >= 'A' && str[0] <= 'Z' { + return Case.Pascal; + } + + // camelCase + return Case.Camel; +} + +// Splits the string according to detected case. +// HeyBuddy -> {"Hey", "Buddy"} +// hey-buddy -> {"hey", "buddy"} +// _hey_buddy -> {"", "hey", "buddy"} +// and such... +autosplit_string :: proc(str : string) -> [dynamic]string { + lowCount := 0; + upCount := 0; + for c in str { + // If any '_', split according to that (CONSTANT_CASE or snake_case) + if c == '_' { + return split_from_separator(str, '_'); + } // If any '-', split according to that (kebab-case) + else if c == '-' { + return split_from_separator(str, '-'); + } + else if c >= 'a' && c <= 'z' { + lowCount += 1; + } + else if c >= 'A' && c <= 'Z' { + upCount += 1; + } + } + + // If it seems to be only one word + if lowCount == 0 || upCount == 0 { + parts : [dynamic]string; + append(&parts, str); + return parts; + } + + // Split at each uppercase letter (PascalCase or camelCase) + return split_from_capital(str); +} + +split_from_separator :: proc(str : string, sep : rune) -> [dynamic]string { + parts : [dynamic]string; + + lastI := 0; + + // Empty strings for starting separators in string + for c in str { + if c == sep { + append(&parts, ""); + lastI += 1; + } else { + break; + } + } + + // Ignore non letter prefix + if lastI == 0 { + for c in str { + if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') { + lastI += 1; + } + else { + break; + } + } + } + + for c, i in str { + if i > lastI + 1 && c == sep { + append(&parts, str[lastI:i]); + lastI = i + 1; + } + } + + append(&parts, str[lastI:]); + + return parts; +} + +split_from_capital :: proc(str : string) -> [dynamic]string { + parts : [dynamic]string; + + // Ignore non letter prefix + lastI := 0; + for c in str { + if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') { + lastI += 1; + } + else { + break; + } + } + + // We want to handle: + // myBrainIsCRAZY -> my Brain Is Crazy + // myCRAZYBrain -> my CRAZY Brain + // SOLO -> SOLO + + // Do split + for i := 1; i < len(str); i += 1 { + if str[i] >= 'A' && str[i] <= 'Z' { + // Do not split too much if it seems to be a capitalized word + if (lastI == i - 1) && (str[lastI] >= 'A' && str[lastI] <= 'Z') { + for ; i + 1 < len(str); i += 1 { + if str[i + 1] < 'A' || str[i + 1] > 'Z' { + break; + } + } + if (i + 1 == len(str)) && (str[i] >= 'A' && str[i] <= 'Z') { + i += 1; + } + } + + append(&parts, str[lastI:i]); + lastI = i; + } + } + + if lastI != len(str) { + append(&parts, str[lastI:]); + } + + return parts; +} + +// Check if str if prefixed with any of the provided strings, +// even combinaisons of those, and remove them. +remove_prefixes :: proc(str : string, prefixes : []string, transparentPrefixes : []string = nil) -> string { + str := str; + transparentStr := ""; + + found := true; + for found { + found = false; + + // Remove effective prefixes + for prefix in prefixes { + if len(str) >= len(prefix) && + str[:len(prefix)] == prefix { + str = str[len(prefix):]; + if len(str) != 0 && (str[0] == '_' || str[0] == '-') { + str = str[1:]; + } + found = true; + break; + } + } + + if found do continue; + + // Remove transparent ones, only one by one, + // as we want effective ones to be fully removed. + for prefix in transparentPrefixes { + if len(str) >= len(prefix) && + str[:len(prefix)] == prefix { + str = str[len(prefix):]; + transparentStr = tcat(transparentStr, prefix); + if len(str) != 0 && (str[0] == '_' || str[0] == '-') { + str = str[1:]; + transparentStr = tcat(transparentStr, '_'); + } + found = true; + break; + } + } + } + + return tcat(transparentStr, str); +} + +// Check if str if postfixes with any of the provided strings, +// even combinaisons of those, and remove them. +remove_postfixes_with_removed :: proc( + str : string, + postfixes : []string, + transparentPostfixes : []string = nil) -> (string, [dynamic]string) { + str := str; + removedPostfixes : [dynamic]string; + transparentStr := ""; + + found := true; + for found { + found = false; + + // Remove effective postfixes + for postfix in postfixes { + if ends_with(str, postfix) { + str = str[:len(str) - len(postfix)]; + if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') { + str = str[:len(str)-1]; + } + append(&removedPostfixes, postfix); + found = true; + break; + } + } + + if found do continue; + + // Remove transparent ones, only one by one, + // as we want effective ones to be fully removed. + for postfix in transparentPostfixes { + if ends_with(str, postfix) { + str = str[:len(str) - len(postfix)]; + transparentStr = tcat(postfix, transparentStr); + if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') { + str = str[:len(str)-1]; + transparentStr = tcat('_', transparentStr); + } + found = true; + break; + } + } + } + + return tcat(str, transparentStr), removedPostfixes; +} + +remove_postfixes :: proc( + str : string, + postfixes : []string, + transparentPostfixes : []string = nil) -> string { + str := str; + removedPostfixes : [dynamic]string; + str, removedPostfixes = remove_postfixes_with_removed(str, postfixes, transparentPostfixes); + return str; +} + +ends_with :: proc(str : string, postfix : string) -> bool { + return len(str) >= len(postfix) && str[len(str) - len(postfix):] == postfix; +} diff --git a/core/bindgen/generator.odin b/core/bindgen/generator.odin new file mode 100644 index 000000000..3ef3d69c0 --- /dev/null +++ b/core/bindgen/generator.odin @@ -0,0 +1,205 @@ +/** + * Odin binding generator from C header data. + */ + +package bindgen + +import "core:os" +import "core:fmt" +import "core:runtime" + +GeneratorOptions :: struct { + mode : string, // "odin" or "jai" + + // Variable + variableCase : Case, + + // Defines + definePrefixes : []string, + defineTransparentPrefixes : []string, + definePostfixes : []string, + defineTransparentPostfixes : []string, + defineCase : Case, + + // Pseudo-types + pseudoTypePrefixes : []string, + pseudoTypeTransparentPrefixes : []string, + pseudoTypePostfixes : []string, + pseudoTypeTransparentPostfixes : []string, + pseudoTypeCase : Case, + + // Enums + enumConsideredFlagsPostfixes : []string, + + // Functions + functionPrefixes : []string, + functionTransparentPrefixes : []string, + functionPostfixes : []string, + functionTransparentPostfixes : []string, + functionCase : Case, + + // Enum values + enumValuePrefixes : []string, + enumValueTransparentPrefixes : []string, + enumValuePostfixes : []string, + enumValueTransparentPostfixes : []string, + enumValueCase : Case, + enumValueNameRemove : bool, + enumValueNameRemovePostfixes : []string, + + parserOptions : ParserOptions, +} + +GeneratorData :: struct { + handle : os.Handle, + nodes : Nodes, + + // References + foreignLibrary : string, + options : ^GeneratorOptions, +} + +generate :: proc( + packageName : string, + foreignLibrary : string, + outputFile : string, + headerFiles : []string, + options : GeneratorOptions, +) { + options := options; + data : GeneratorData; + data.options = &options; + data.foreignLibrary = foreignLibrary; + + if options.mode == "" { + options.mode = "odin"; + } + + // Outputing odin file + errno : os.Errno; + + // chmod 664 when creating file + mode: int = 0; + when os.OS == "linux" || os.OS == "darwin" { + mode = os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IWGRP | os.S_IROTH; + } + + data.handle, errno = os.open(outputFile, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, mode); + if errno != 0 { + fmt.eprint("[bindgen] Unable to write to output file ", outputFile, " (", errno ,")\n"); + return; + } + defer os.close(data.handle); + + if options.mode == "jai" { + fcat(data.handle, foreignLibrary, " :: #foreign_library \"", foreignLibrary, "\";\n"); + fcat(data.handle, "\n"); + } else { + fcat(data.handle, "package ", packageName, "\n"); + fcat(data.handle, "\n"); + fcat(data.handle, "foreign import \"", foreignLibrary, "\"\n"); + fcat(data.handle, "\n"); + fcat(data.handle, "import _c \"core:c\"\n"); + fcat(data.handle, "\n"); + } + + // Parsing header files + anonymousStructCount = 0; + anonymousUnionCount = 0; + anonymousEnumCount = 0; + + for headerFile in headerFiles { + bytes, ok := os.read_entire_file(headerFile); + if !ok { + fmt.eprint("[bindgen] Unable to read file ", headerFile, "\n"); + return; + } + + // We fuse the SOAs + headerNodes := parse(bytes, options.parserOptions); + merge_generic_nodes(&data.nodes.defines, &headerNodes.defines); + merge_generic_nodes(&data.nodes.enumDefinitions, &headerNodes.enumDefinitions); + merge_generic_nodes(&data.nodes.unionDefinitions, &headerNodes.unionDefinitions); + merge_forward_declared_nodes(&data.nodes.structDefinitions, &headerNodes.structDefinitions); + merge_generic_nodes(&data.nodes.functionDeclarations, &headerNodes.functionDeclarations); + merge_generic_nodes(&data.nodes.typedefs, &headerNodes.typedefs); + } + + // Exporting + export_defines(&data); + export_typedefs(&data); + export_enums(&data); + export_structs(&data); + export_unions(&data); + + // Foreign block for functions + if options.mode != "jai" { + foreignLibrarySimple := simplify_library_name(foreignLibrary); + fcat(data.handle, "@(default_calling_convention=\"c\")\n"); + fcat(data.handle, "foreign ", foreignLibrarySimple, " {\n"); + fcat(data.handle, "\n"); + } + + export_functions(&data); + + if options.mode != "jai" { + fcat(data.handle, "}\n"); + } +} + +// system:foo.lib -> foo +simplify_library_name :: proc(libraryName : string) -> string { + startOffset := 0; + endOffset := len(libraryName); + + for c, i in libraryName { + if startOffset == 0 && c == ':' { + startOffset = i + 1; + } + else if c == '.' { + endOffset = i; + break; + } + } + + return libraryName[startOffset:endOffset]; +} + +merge_generic_nodes :: proc(nodes : ^$T, headerNodes : ^T) { + for headerNode in headerNodes { + // Check that there are no duplicated nodes (due to forward declaration or such) + duplicatedIndex := -1; + for i := 0; i < len(nodes); i += 1 { + node := nodes[i]; + if node.name == headerNode.name { + duplicatedIndex = i; + break; + } + } + + if duplicatedIndex < 0 { + append(nodes, headerNode); + } + } +} + +merge_forward_declared_nodes :: proc(nodes : ^$T, headerNodes : ^T) { + for headerNode in headerNodes { + // Check that there are no duplicated nodes (due to forward declaration or such) + duplicatedIndex := -1; + for i := 0; i < len(nodes); i += 1 { + node := nodes[i]; + if node.name == headerNode.name { + duplicatedIndex = i; + break; + } + } + + if duplicatedIndex < 0 { + append(nodes, headerNode); + } + else if !headerNode.forwardDeclared && len(headerNode.members) > 0 { + nodes[duplicatedIndex] = headerNode; + } + } +} diff --git a/vendor/stb/lib/darwin/libstb_image.a b/vendor/stb/lib/darwin/libstb_image.a new file mode 100644 index 0000000000000000000000000000000000000000..06ce4432192e21268b40c487d33f54d0d4ec0007 GIT binary patch literal 55744 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 $IC322Z*dg? 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 M)se7pG-O}^0H7`N-T(jq literal 0 HcmV?d00001 diff --git a/vendor/stb/lib/darwin/stb_image_resize.a b/vendor/stb/lib/darwin/stb_image_resize.a new file mode 100644 index 0000000000000000000000000000000000000000..f39c507a6c92d777f16c781d44a9dd3b623c42f9 GIT binary patch literal 36824 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 JtOgr00063`#B2Zn literal 0 HcmV?d00001 diff --git a/vendor/stb/lib/darwin/stb_truetype.a b/vendor/stb/lib/darwin/stb_truetype.a new file mode 100644 index 0000000000000000000000000000000000000000..c4a895b54b69c674e69c31dc2464951a929cc3a4 GIT binary patch literal 67008 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 Date: Fri, 4 Feb 2022 13:45:36 -0500 Subject: [PATCH 05/12] Reverted experimental changes that were meant for a branch, in sync with master --- Makefile | 2 +- core/bindgen/c-parser-evaluate.odin | 266 --------- core/bindgen/c-parser-helpers.odin | 267 --------- core/bindgen/c-parser-nodes.odin | 132 ----- core/bindgen/c-parser.odin | 840 ---------------------------- core/bindgen/errors.odin | 44 -- core/bindgen/generator-clean.odin | 284 ---------- core/bindgen/generator-export.odin | 166 ------ core/bindgen/generator-helpers.odin | 392 ------------- core/bindgen/generator.odin | 205 ------- wasm-ld | 1 - 11 files changed, 1 insertion(+), 2598 deletions(-) delete mode 100644 core/bindgen/c-parser-evaluate.odin delete mode 100644 core/bindgen/c-parser-helpers.odin delete mode 100644 core/bindgen/c-parser-nodes.odin delete mode 100644 core/bindgen/c-parser.odin delete mode 100644 core/bindgen/errors.odin delete mode 100644 core/bindgen/generator-clean.odin delete mode 100644 core/bindgen/generator-export.odin delete mode 100644 core/bindgen/generator-helpers.odin delete mode 100644 core/bindgen/generator.odin delete mode 120000 wasm-ld diff --git a/Makefile b/Makefile index df5fe0605..d3d3c6a2d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ ifeq ($(OS), Darwin) LLVM_VERSIONS = "13.%.%" else # allow for x86 / amd64 all llvm versions begining from 11 - LLVM_VERSIONS = "13.%.%" "12.0.1" "11.0.0" + LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0" endif LLVM_VERSION_PATTERN_SEPERATOR = )|( diff --git a/core/bindgen/c-parser-evaluate.odin b/core/bindgen/c-parser-evaluate.odin deleted file mode 100644 index 13cb5042c..000000000 --- a/core/bindgen/c-parser-evaluate.odin +++ /dev/null @@ -1,266 +0,0 @@ -package bindgen - -import "core:fmt" -import "core:strconv" - -// Evaluates an expression to a i64, without checking. -evaluate_i64 :: proc(data : ^ParserData) -> i64 { - ok : bool; - value : LiteralValue; - - value, ok = evaluate(data); - return value.(i64); -} - -// Evaluate an expression, returns whether it succeeded. -evaluate :: proc(data : ^ParserData) -> (LiteralValue, bool) { - return evaluate_level_5(data); -} - -// @note Evaluate levels numbers are based on -// https://en.cppreference.com/w/c/language/operator_precedence. - -// Bitwise shift level. -evaluate_level_5 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - value, ok = evaluate_level_4(data); - if !ok do return; - - invalid_value : LiteralValue; - token := peek_token(data); - - if token == "<<" { - v : LiteralValue; - eat_token(data); - - v, ok = evaluate_level_5(data); - if is_i64(v) do value = value.(i64) << cast(u64) v.(i64); - else do invalid_value = v; - } else if token == ">>" { - v : LiteralValue; - eat_token(data); - - v, ok = evaluate_level_5(data); - if is_i64(v) do value = value.(i64) >> cast(u64) v.(i64); - else do invalid_value = v; - } - - if invalid_value != nil { - print_warning("Invalid operand for bitwise shift ", invalid_value); - } - - return; -} - -// Additive level. -evaluate_level_4 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - value, ok = evaluate_level_3(data); - if !ok do return; - - token := peek_token(data); - if token == "+" { - v : LiteralValue; - eat_token(data); - v, ok = evaluate_level_4(data); - if is_i64(v) do value = value.(i64) + v.(i64); - else if is_f64(v) do value = value.(f64) + v.(f64); - } - else if token == "-" { - v : LiteralValue; - eat_token(data); - v, ok = evaluate_level_4(data); - if is_i64(v) do value = value.(i64) - v.(i64); - else if is_f64(v) do value = value.(f64) - v.(f64); - } - - return; -} - -// Multiplicative level. -evaluate_level_3 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - value, ok = evaluate_level_2(data); - if !ok do return; - - token := peek_token(data); - if token == "*" { - v : LiteralValue; - eat_token(data); - v, ok = evaluate_level_3(data); - if is_i64(v) do value = value.(i64) * v.(i64); - else if is_f64(v) do value = value.(f64) * v.(f64); - } - else if token == "/" { - v : LiteralValue; - eat_token(data); - v, ok = evaluate_level_3(data); - if is_i64(v) do value = value.(i64) / v.(i64); - else if is_f64(v) do value = value.(f64) / v.(f64); - } - - return; -} - -// Prefix level. -evaluate_level_2 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - token := peek_token(data); - - // Bitwise not - if token == "~" { - check_and_eat_token(data, "~"); - value, ok = evaluate_level_2(data); - value = ~value.(i64); - } - else { - // @note Should call evaluate_level_1, but we don't have that because we do not dereferenciation. - value, ok = evaluate_level_0(data); - } - - return; -} - -// Does not try to compose with arithmetics, it just evaluates one single expression. -evaluate_level_0 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - ok = true; - value = 0; - token := peek_token(data); - - // Parentheses - if token == "(" { - value, ok = evaluate_parentheses(data); - } // Number literal - else if (token[0] == '-') || (token[0] >= '0' && token[0] <= '9') { - value, ok = evaluate_number_literal(data); - } // String literal - else if token[0] == '"' { - value = evaluate_string_literal(data); - } // Function-like - else if token == "sizeof" { - value = evaluate_sizeof(data); - } // Knowned literal - else if token in data.knownedLiterals { - value = evaluate_knowned_literal(data); - } // Custom expression - else if token in data.options.customExpressionHandlers { - value = data.options.customExpressionHandlers[token](data); - } - else { - print_warning("Unknown token ", token, " for expression evaluation."); - ok = false; - } - - return; -} - -evaluate_sizeof :: proc(data : ^ParserData) -> LiteralValue { - print_warning("Using 'sizeof()'. Currently not able to precompute that. Please check generated code."); - - check_and_eat_token(data, "sizeof"); - check_and_eat_token(data, "("); - for data.bytes[data.offset] != ')' { - data.offset += 1; - } - check_and_eat_token(data, ")"); - return 1; -} - -evaluate_parentheses :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) { - check_and_eat_token(data, "("); - - // Cast to int (via "(int)" syntax) - token := peek_token(data); - if token == "int" { - check_and_eat_token(data, "int"); - check_and_eat_token(data, ")"); - value, ok = evaluate(data); - return; - } // Cast to enum value (via "(enum XXX)" syntax) - else if token == "enum" { - check_and_eat_token(data, "enum"); - eat_token(data); - check_and_eat_token(data, ")"); - value, ok = evaluate(data); - return; - } - - value, ok = evaluate(data); - check_and_eat_token(data, ")"); - return; -} - -evaluate_number_literal :: proc(data : ^ParserData, loc := #caller_location) -> (value : LiteralValue, ok : bool) { - token := parse_any(data); - - // Unary - before numbers - numberLitteral := token; - for token == "-" { - token = parse_any(data); - numberLitteral = tcat(numberLitteral, token); - } - token = numberLitteral; - - // Check if any point or scientific notation in number - foundPointOrExp := false; - for c in token { - if c == '.' || c == 'e' || c == 'E' { - foundPointOrExp = true; - break; - } - } - - isHexadecimal := len(token) >= 2 && token[:2] == "0x"; - - // Computing postfix - tokenLength := len(token); - l := tokenLength - 1; - for l > 0 { - c := token[l]; - if c >= '0' && c <= '9' { break; } - if isHexadecimal && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { break; } - l -= 1; - } - - postfix : string; - if l != tokenLength - 1 { - postfix = token[l+1:]; - token = token[:l+1]; - } - - if postfix != "" && (postfix[0] == 'u' || postfix[0] == 'U') { - print_warning("Found number litteral '", token, "' with unsigned postfix, we cast it to an int64 internally."); - } - - // Floating point - if !isHexadecimal && (foundPointOrExp || postfix == "f") { - value, ok = strconv.parse_f64(token); - } // Integer - else { - value, ok = strconv.parse_i64(token); - } - - if !ok { - print_error(data, loc, "Expected number litteral but got '", token, "'."); - } - - return value, ok; -} - -evaluate_string_literal :: proc(data : ^ParserData) -> string { - token := parse_any(data); - return token; -} - -evaluate_knowned_literal :: proc(data : ^ParserData) -> LiteralValue { - token := parse_any(data); - return data.knownedLiterals[token]; -} - -is_i64 :: proc(value : LiteralValue) -> (ok : bool) { - v : i64; - v, ok = value.(i64); - return ok; -} - -is_f64 :: proc(value : LiteralValue) -> (ok : bool) { - v : f64; - v, ok = value.(f64); - return ok; -} diff --git a/core/bindgen/c-parser-helpers.odin b/core/bindgen/c-parser-helpers.odin deleted file mode 100644 index a99d83dd2..000000000 --- a/core/bindgen/c-parser-helpers.odin +++ /dev/null @@ -1,267 +0,0 @@ -package bindgen - -import "core:os" -import "core:fmt" -import "core:strings" -import "core:strconv" - -// Extract from start (included) to end (excluded) offsets -extract_string :: proc(data : ^ParserData, startOffset : u32, endOffset : u32) -> string { - return strings.string_from_ptr(&data.bytes[startOffset], cast(int) (endOffset - startOffset)); -} - -// Peek the end offset of the next token -peek_token_end :: proc(data : ^ParserData) -> u32 { - offset : u32; - - for true { - eat_whitespaces_and_comments(data); - if data.offset >= data.bytesLength { - return data.bytesLength; - } - offset = data.offset; - - // Identifier - if (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') || - (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') || - (data.bytes[offset] == '_') { - offset += 1; - for (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') || - (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') || - (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || - (data.bytes[offset] == '_') { - offset += 1; - } - } - if offset != data.offset { - // Nothing to do: we found an identifier - } // Number literal - else if (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') { - offset += 1; - // Hexademical literal - if data.bytes[offset - 1] == '0' && data.bytes[offset] == 'x' { - offset += 1; - for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || - (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'f') || - (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'F') { - offset += 1; - } - } // Basic number literal - else { - for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') || - data.bytes[offset] == '.' { - offset += 1; - } - - if (data.bytes[offset] == 'e' || data.bytes[offset] == 'E') { - offset += 1; - if data.bytes[offset] == '-' { - offset += 1; - } - } - - for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') { - offset += 1; - } - } - - // Number suffix? - for (data.bytes[offset] == 'u' || data.bytes[offset] == 'U') || - (data.bytes[offset] == 'l' || data.bytes[offset] == 'L') || - (data.bytes[offset] == 'f') { - offset += 1; - } - } // String literal - else if data.bytes[offset] == '"' { - offset += 1; - for data.bytes[offset-1] == '\\' || data.bytes[offset] != '"' { - offset += 1; - } - offset += 1; - } // Possible shifts - else if data.bytes[offset] == '<' || data.bytes[offset] == '>' { - offset += 1; - if data.bytes[offset] == data.bytes[offset-1] { - offset += 1; - } - } // Single character - else { - offset += 1; - } - - token := extract_string(data, data.offset, offset); - - // Ignore __attribute__ - if token == "__attribute__" { - print_warning("__attribute__ is ignored."); - - for data.bytes[offset] != '(' { - offset += 1; - } - - parenthesesCount := 1; - for true { - offset += 1; - if data.bytes[offset] == '(' do parenthesesCount += 1; - else if data.bytes[offset] == ')' do parenthesesCount -= 1; - if parenthesesCount == 0 do break; - } - offset += 1; - - data.offset = offset; - } // Ignore certain keywords - else if (token == "inline" || token == "__inline" || token == "static" - || token == "restrict" || token == "__restrict" - || token == "volatile" - || token == "__extension__") { - data.offset = offset; - } // Ignore ignored tokens ;) - else { - for ignoredToken in data.options.ignoredTokens { - if token == ignoredToken { - data.offset = offset; - break; - } - } - } - - if data.offset != offset { - break; - } - } - - return offset; -} - -// Peek the next token (just eating whitespaces and comment) -peek_token :: proc(data : ^ParserData) -> string { - tokenEnd := peek_token_end(data); - if tokenEnd == data.bytesLength { - return "EOF"; - } - return extract_string(data, data.offset, tokenEnd); -} - -// Find the end of the define directive (understanding endline backslashes) -// @note Tricky cases like comments hiding a backslash effect are not handled. -peek_define_end :: proc(data : ^ParserData) -> u32 { - defineEndOffset := data.offset; - for data.bytes[defineEndOffset-1] == '\\' || data.bytes[defineEndOffset] != '\n' { - defineEndOffset += 1; - } - return defineEndOffset; -} - -eat_comment :: proc(data : ^ParserData) { - if data.offset >= data.bytesLength || data.bytes[data.offset] != '/' { - return; - } - - // Line comment - if data.bytes[data.offset + 1] == '/' { - eat_line(data); - } // Range comment - else if data.bytes[data.offset + 1] == '*' { - data.offset += 2; - for data.bytes[data.offset] != '*' || data.bytes[data.offset + 1] != '/' { - data.offset += 1; - } - data.offset += 2; - } -} - -// Eat whitespaces -eat_whitespaces :: proc(data : ^ParserData) { - // Effective whitespace - for data.offset < data.bytesLength && - (data.bytes[data.offset] == ' ' || data.bytes[data.offset] == '\t' || - data.bytes[data.offset] == '\r' || data.bytes[data.offset] == '\n') { - if data.bytes[data.offset] == '\n' && data.bytes[data.offset] != '\\' { - data.foundFullReturn = true; - } - data.offset += 1; - } -} - -// Removes whitespaces and comments -eat_whitespaces_and_comments :: proc(data : ^ParserData) { - startOffset : u32 = 0xFFFFFFFF; - for startOffset != data.offset { - startOffset = data.offset; - eat_whitespaces(data); - eat_comment(data); - } -} - -// Eat full line -eat_line :: proc(data : ^ParserData) { - for ; data.bytes[data.offset] != '\n'; data.offset += 1 { - } -} - -// Eat a line, and repeat if it ends with a backslash -eat_define_lines :: proc(data : ^ParserData) { - for data.bytes[data.offset-1] == '\\' || data.bytes[data.offset] != '\n' { - data.offset += 1; - } -} - -// Eat next token -eat_token :: proc(data : ^ParserData) { - data.offset = peek_token_end(data); -} - -// Eat next token -check_and_eat_token :: proc(data : ^ParserData, expectedToken : string, loc := #caller_location) { - token := peek_token(data); - if token != expectedToken { - print_error(data, loc, "Expected ", expectedToken, " but found ", token, "."); - } - data.offset += cast(u32) len(token); -} - -// Check whether the next token is outside #define range -is_define_end :: proc(data : ^ParserData) -> bool { - defineEnd := peek_define_end(data); - tokenEnd := peek_token_end(data); - - return (defineEnd < tokenEnd); -} - -// Check if the current #define is a macro definition -is_define_macro :: proc(data : ^ParserData) -> bool { - startOffset := data.offset; - defer data.offset = startOffset; - - token := parse_any(data); - if token != "(" do return false; - - // Find the other parenthesis - parenthesesCount := 1; - for parenthesesCount != 0 { - token = parse_any(data); - if token == "(" do parenthesesCount += 1; - else if token == ")" do parenthesesCount -= 1; - } - - // Its a macro if after the parentheses, it's not the end - return !is_define_end(data); -} - -// @note Very slow function to get line number, -// use only for errors. -// @todo Well, this does not seem to work properly, UTF-8 problem? -get_line_column :: proc(data : ^ParserData) -> (u32, u32) { - line : u32 = 1; - column : u32 = 0; - for i : u32 = 0; i < data.offset; i += 1 { - if data.bytes[i] == '\n' { - column = 0; - line += 1; - } - else { - column += 1; - } - } - return line, column; -} diff --git a/core/bindgen/c-parser-nodes.odin b/core/bindgen/c-parser-nodes.odin deleted file mode 100644 index 0620e0187..000000000 --- a/core/bindgen/c-parser-nodes.odin +++ /dev/null @@ -1,132 +0,0 @@ -package bindgen - -DefineNode :: struct { - name : string, - value : LiteralValue, -} - -StructDefinitionNode :: struct { - name : string, - members : [dynamic]StructOrUnionMember, - forwardDeclared : bool, -} - -UnionDefinitionNode :: struct { - name : string, - members : [dynamic]StructOrUnionMember, -} - -EnumDefinitionNode :: struct { - name : string, - members : [dynamic]EnumMember, -} - -FunctionDeclarationNode :: struct { - name : string, - returnType : Type, - parameters : [dynamic]FunctionParameter, -} - -TypedefNode :: struct { - name : string, - type : Type, -} - -Nodes :: struct { - defines : [dynamic]DefineNode, - enumDefinitions : [dynamic]EnumDefinitionNode, - unionDefinitions : [dynamic]UnionDefinitionNode, - structDefinitions : [dynamic]StructDefinitionNode, - functionDeclarations : [dynamic]FunctionDeclarationNode, - typedefs : [dynamic]TypedefNode, -} - -LiteralValue :: union { - i64, - f64, - string, -} - -// Type, might be an array -Type :: struct { - base : BaseType, - dimensions : [dynamic]u64, // Array dimensions -} - -BaseType :: union { - BuiltinType, - PointerType, - IdentifierType, - FunctionType, - FunctionPointerType, -} - -BuiltinType :: enum { - Unknown, - Void, - Int, - UInt, - LongInt, - ULongInt, - LongLongInt, - ULongLongInt, - ShortInt, - UShortInt, - Char, - SChar, - UChar, - Float, - Double, - LongDouble, - - // Not defined by C language but in - Int8, - Int16, - Int32, - Int64, - UInt8, - UInt16, - UInt32, - UInt64, - Size, - SSize, - PtrDiff, - UIntPtr, - IntPtr, -} - -PointerType :: struct { - type : ^Type, // Pointer is there to prevent definition cycle. Null means void. -} - -IdentifierType :: struct { - name : string, - anonymous : bool, // An anonymous identifier can be hard-given a name in some contexts. -} - -FunctionType :: struct { - returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void. - parameters : [dynamic]FunctionParameter, -} - -FunctionPointerType :: struct { - name : string, - returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void. - parameters : [dynamic]FunctionParameter, -} - -EnumMember :: struct { - name : string, - value : i64, - hasValue : bool, -} - -StructOrUnionMember :: struct { - name : string, - type : Type, -} - -FunctionParameter :: struct { - name : string, - type : Type, -} diff --git a/core/bindgen/c-parser.odin b/core/bindgen/c-parser.odin deleted file mode 100644 index c3ef4937f..000000000 --- a/core/bindgen/c-parser.odin +++ /dev/null @@ -1,840 +0,0 @@ -package bindgen - -import "core:os" -import "core:fmt" -import "core:strings" -import "core:strconv" - -// Global counters -anonymousStructCount := 0; -anonymousUnionCount := 0; -anonymousEnumCount := 0; - -knownTypeAliases : map[string]Type; - -CustomHandler :: proc(data : ^ParserData); -CustomExpressionHandler :: proc(data : ^ParserData) -> LiteralValue; - -ParserOptions :: struct { - ignoredTokens : []string, - - // Handlers - customHandlers : map[string]CustomHandler, - customExpressionHandlers : map[string]CustomExpressionHandler, -} - -ParserData :: struct { - bytes : []u8, - bytesLength : u32, - offset : u32, - - // References - nodes : Nodes, - options : ^ParserOptions, - - // Knowned values - knownedLiterals : map[string]LiteralValue, - - // Whether we have eaten a '\n' character that has no backslash just before - foundFullReturn : bool, -} - -is_identifier :: proc(token : string) -> bool { - return (token[0] >= 'a' && token[0] <= 'z') || - (token[0] >= 'A' && token[0] <= 'Z') || - (token[0] == '_'); -} - -parse :: proc(bytes : []u8, options : ParserOptions, loc := #caller_location) -> Nodes { - options := options; - - data : ParserData; - data.bytes = bytes; - data.bytesLength = cast(u32) len(bytes); - data.options = &options; - - for data.offset = 0; data.offset < data.bytesLength; { - token := peek_token(&data); - if data.offset == data.bytesLength do break; - - if token in options.customHandlers { - options.customHandlers[token](&data); - } - else if token == "{" || token == "}" || token == ";" { - eat_token(&data); - } - else if token == "extern" { - check_and_eat_token(&data, "extern"); - } - else if token == "\"C\"" { - check_and_eat_token(&data, "\"C\""); - } - else if token == "#" { - parse_directive(&data); - } - else if token == "typedef" { - parse_typedef(&data); - } - else if is_identifier(token) { - parse_variable_or_function_declaration(&data); - } - else { - print_error(&data, loc, "Unexpected token: ", token, "."); - return data.nodes; - } - } - - return data.nodes; -} - -parse_any :: proc(data : ^ParserData) -> string { - offset := peek_token_end(data); - identifier := extract_string(data, data.offset, offset); - data.offset = offset; - return identifier; -} - -parse_identifier :: proc(data : ^ParserData, loc := #caller_location) -> string { - identifier := parse_any(data); - - if (identifier[0] < 'a' || identifier[0] > 'z') && - (identifier[0] < 'A' || identifier[0] > 'Z') && - (identifier[0] != '_') { - print_error(data, loc, "Expected identifier but found ", identifier, "."); - } - - return identifier; -} - -parse_type_dimensions :: proc(data : ^ParserData, type : ^Type) { - token := peek_token(data); - for token == "[" { - eat_token(data); - token = peek_token(data); - if token == "]" { - pointerType : PointerType; - pointerType.type = new(Type); - pointerType.type^ = type^; // Copy - type.base = pointerType; - delete(type.dimensions); - } else { - dimension := evaluate_i64(data); - append(&type.dimensions, cast(u64) dimension); - } - check_and_eat_token(data, "]"); - token = peek_token(data); - } -} - -// This will parse anything that look like a type: -// Builtin: char/int/float/... -// Struct-like: struct A/struct { ... }/enum E -// Function pointer: void (*f)(...) -// -// Definition permitted: If a struct-like definition is found, it will generate -// the according Node and return a corresponding type. -parse_type :: proc(data : ^ParserData, definitionPermitted := false) -> Type { - type : Type; - - // Eat qualifiers - token := peek_token(data); - if token == "const" { - eat_token(data); - token = peek_token(data); - } - - // Parse main type - if token == "struct" { - type.base = parse_struct_type(data, definitionPermitted); - } - else if token == "union" { - type.base = parse_union_type(data); - } - else if token == "enum" { - type.base = parse_enum_type(data); - } - else { - // Test builtin type - type.base = parse_builtin_type(data); - if type.base.(BuiltinType) == BuiltinType.Unknown { - // Basic identifier type - identifierType : IdentifierType; - identifierType.name = parse_identifier(data); - type.base = identifierType; - } - } - - // Eat qualifiers - token = peek_token(data); - if token == "const" { - eat_token(data); - token = peek_token(data); - } - - // Check if pointer - for token == "*" { - check_and_eat_token(data, "*"); - token = peek_token(data); - - pointerType : PointerType; - pointerType.type = new(Type); - pointerType.type^ = type; // Copy - - type.base = pointerType; - - // Eat qualifiers - if token == "const" { - eat_token(data); - token = peek_token(data); - } - } - - // Parse array dimensions if any. - parse_type_dimensions(data, &type); - - // ----- Function pointer type - - if token == "(" { - check_and_eat_token(data, "("); - check_and_eat_token(data, "*"); - - functionPointerType : FunctionPointerType; - functionPointerType.returnType = new(Type); - functionPointerType.returnType^ = type; - functionPointerType.name = parse_identifier(data); - - check_and_eat_token(data, ")"); - parse_function_parameters(data, &functionPointerType.parameters); - - type.base = functionPointerType; - } - - return type; -} - -parse_builtin_type :: proc(data : ^ParserData) -> BuiltinType { - previousBuiltinType := BuiltinType.Unknown; - intFound := false; - shortFound := false; - signedFound := false; - unsignedFound := false; - longCount := 0; - - for true { - token := peek_token(data); - - // Attribute - attributeFound := true; - if token == "long" do longCount += 1; - else if token == "short" do shortFound = true; - else if token == "unsigned" do unsignedFound = true; - else if token == "signed" do signedFound = true; - else do attributeFound = false; - if attributeFound { eat_token(data); continue; } - - // Known type alias - if token in knownTypeAliases { - builtinType, ok := knownTypeAliases[token].base.(BuiltinType); - if ok { - eat_token(data); - previousBuiltinType = builtinType; - } - break; - } - - // Classic type and standard types - if token == "void" { eat_token(data); return BuiltinType.Void; } - else if token == "int" { - eat_token(data); - intFound = true; - } - else if token == "float" { eat_token(data); return BuiltinType.Float; } - else if token == "double" { - eat_token(data); - if longCount == 0 do return BuiltinType.Double; - else do return BuiltinType.LongDouble; - } - else if token == "char" { - eat_token(data); - if signedFound do return BuiltinType.SChar; - else if unsignedFound do return BuiltinType.UChar; - else do return BuiltinType.Char; - } - else if token == "__int8" { - // @note :MicrosoftDumminess __intX are Microsoft's fixed-size integers - // https://docs.microsoft.com/fr-fr/cpp/cpp/int8-int16-int32-int64 - // and for unsigned version, they prefixed it with "unsigned"... - eat_token(data); - if unsignedFound do return BuiltinType.UInt8; - else do return BuiltinType.Int8; - } - else if token == "__int16" { - eat_token(data); - if unsignedFound do return BuiltinType.UInt16; - else do return BuiltinType.Int16; - } - else if token == "__int32" { - eat_token(data); - if unsignedFound do return BuiltinType.UInt32; - else do return BuiltinType.Int32; - } - else if token == "__int64" { - eat_token(data); - if unsignedFound do return BuiltinType.UInt64; - else do return BuiltinType.Int64; - } - else if token == "int8_t" { eat_token(data); return BuiltinType.Int8; } - else if token == "int16_t" { eat_token(data); return BuiltinType.Int16; } - else if token == "int32_t" { eat_token(data); return BuiltinType.Int32; } - else if token == "int64_t" { eat_token(data); return BuiltinType.Int64; } - else if token == "uint8_t" { eat_token(data); return BuiltinType.UInt8; } - else if token == "uint16_t" { eat_token(data); return BuiltinType.UInt16; } - else if token == "uint32_t" { eat_token(data); return BuiltinType.UInt32; } - else if token == "uint64_t" { eat_token(data); return BuiltinType.UInt64; } - else if token == "size_t" { eat_token(data); return BuiltinType.Size; } - else if token == "ssize_t" { eat_token(data); return BuiltinType.SSize; } - else if token == "ptrdiff_t" { eat_token(data); return BuiltinType.PtrDiff; } - else if token == "uintptr_t" { eat_token(data); return BuiltinType.UIntPtr; } - else if token == "intptr_t" { eat_token(data); return BuiltinType.IntPtr; } - - break; - } - - // Adapt previous builtin type - if previousBuiltinType == BuiltinType.ShortInt { - shortFound = true; - } - else if previousBuiltinType == BuiltinType.Int { - intFound = true; - } - else if previousBuiltinType == BuiltinType.LongInt { - longCount += 1; - } - else if previousBuiltinType == BuiltinType.LongLongInt { - longCount += 2; - } - else if previousBuiltinType == BuiltinType.UShortInt { - unsignedFound = true; - shortFound = true; - } - else if previousBuiltinType == BuiltinType.UInt { - unsignedFound = true; - } - else if previousBuiltinType == BuiltinType.ULongInt { - unsignedFound = true; - longCount += 1; - } - else if previousBuiltinType == BuiltinType.ULongLongInt { - unsignedFound = true; - longCount += 2; - } - else if (previousBuiltinType != BuiltinType.Unknown) { - return previousBuiltinType; // float, void, etc. - } - - // Implicit and explicit int - if intFound || shortFound || unsignedFound || signedFound || longCount > 0 { - if unsignedFound { - if shortFound do return BuiltinType.UShortInt; - if longCount == 0 do return BuiltinType.UInt; - if longCount == 1 do return BuiltinType.ULongInt; - if longCount == 2 do return BuiltinType.ULongLongInt; - } else { - if shortFound do return BuiltinType.ShortInt; - if longCount == 0 do return BuiltinType.Int; - if longCount == 1 do return BuiltinType.LongInt; - if longCount == 2 do return BuiltinType.LongLongInt; - } - } - - return BuiltinType.Unknown; -} - -parse_struct_type :: proc(data : ^ParserData, definitionPermitted : bool) -> IdentifierType { - check_and_eat_token(data, "struct"); - - type : IdentifierType; - token := peek_token(data); - - if !definitionPermitted || token != "{" { - type.name = parse_identifier(data); - token = peek_token(data); - } else { - type.name = tcat("AnonymousStruct", anonymousStructCount); - type.anonymous = true; - anonymousStructCount += 1; - } - - if token == "{" { - node := parse_struct_definition(data); - node.name = type.name; - } else if definitionPermitted { - // @note Whatever happens, we create a definition of the struct, - // as it might be used to forward declare it and then use it only with a pointer. - // This for instance the pattern for xcb_connection_t which definition - // is never known from user API. - node : StructDefinitionNode; - node.forwardDeclared = false; - node.name = type.name; - append(&data.nodes.structDefinitions, node); - } - - return type; -} - -parse_union_type :: proc(data : ^ParserData) -> IdentifierType { - check_and_eat_token(data, "union"); - - type : IdentifierType; - token := peek_token(data); - - if token != "{" { - type.name = parse_identifier(data); - token = peek_token(data); - } else { - type.name = tcat("AnonymousUnion", anonymousUnionCount); - type.anonymous = true; - anonymousUnionCount += 1; - } - - if token == "{" { - node := parse_union_definition(data); - node.name = type.name; - } - - return type; -} - -parse_enum_type :: proc(data : ^ParserData) -> IdentifierType { - check_and_eat_token(data, "enum"); - - type : IdentifierType; - token := peek_token(data); - - if token != "{" { - type.name = parse_identifier(data); - token = peek_token(data); - } else { - type.name = tcat("AnonymousEnum", anonymousEnumCount); - type.anonymous = true; - anonymousEnumCount += 1; - } - - if token == "{" { - node := parse_enum_definition(data); - node.name = type.name; - } - - return type; -} - -/** - * We only care about defines of some value - */ -parse_directive :: proc(data : ^ParserData) { - check_and_eat_token(data, "#"); - - token := peek_token(data); - if token == "define" { - parse_define(data); - } // We ignore all other directives - else { - eat_line(data); - } -} - -parse_define :: proc(data : ^ParserData) { - check_and_eat_token(data, "define"); - data.foundFullReturn = false; - - node : DefineNode; - node.name = parse_identifier(data); - - // Does it look like end? It might be a #define with no expression - if is_define_end(data) { - node.value = 1; - append(&data.nodes.defines, node); - data.knownedLiterals[node.name] = node.value; - } // Macros are ignored - else if is_define_macro(data) { - print_warning("Ignoring define macro for ", node.name, "."); - } - else { - literalValue, ok := evaluate(data); - if ok { - node.value = literalValue; - append(&data.nodes.defines, node); - data.knownedLiterals[node.name] = node.value; - } - else { - print_warning("Ignoring define expression for ", node.name, "."); - } - } - - // Evaluating the expression, we might have already eaten a full return, - // if so, do nothing. - if !data.foundFullReturn { - eat_define_lines(data); - } -} - -// @fixme Move -change_anonymous_node_name :: proc (data : ^ParserData, oldName : string, newName : string) -> bool { - for i := 0; i < len(data.nodes.structDefinitions); i += 1 { - if data.nodes.structDefinitions[i].name == oldName { - data.nodes.structDefinitions[i].name = newName; - return true; - } - } - - for i := 0; i < len(data.nodes.enumDefinitions); i += 1 { - if data.nodes.enumDefinitions[i].name == oldName { - data.nodes.enumDefinitions[i].name = newName; - return true; - } - } - - for i := 0; i < len(data.nodes.unionDefinitions); i += 1 { - if data.nodes.unionDefinitions[i].name == oldName { - data.nodes.unionDefinitions[i].name = newName; - return true; - } - } - - return false; -} - -/** - * Type aliasing. - * typedef ; - */ -parse_typedef :: proc(data : ^ParserData) { - check_and_eat_token(data, "typedef"); - - // @note Struct-like definitions (and such) - // are generated within type parsing. - // - // So that typedef struct { int foo; }* Ap; is valid. - - // Parsing type - node : TypedefNode; - node.type = parse_type(data, true); - - if sourceType, ok := node.type.base.(FunctionPointerType); ok { - node.name = sourceType.name; - } else { - node.name = parse_identifier(data); - } - - // Checking if function type - token := peek_token(data); - if token == "(" { - functionType : FunctionType; - functionType.returnType = new(Type); - functionType.returnType^ = node.type; - - parse_function_parameters(data, &functionType.parameters); - - node.type.base = functionType; - } - - // Checking if array - parse_type_dimensions(data, &node.type); - - // If the underlying type is anonymous, - // we just affect it the name. - addTypedefNode := true; - if identifierType, ok := node.type.base.(IdentifierType); ok { - if identifierType.anonymous { - addTypedefNode = !change_anonymous_node_name(data, identifierType.name, node.name); - } - } - - if addTypedefNode { - knownTypeAliases[node.name] = node.type; - append(&data.nodes.typedefs, node); - } - - check_and_eat_token(data, ";"); - - // @note Commented tool for debug - // fmt.println("Typedef: ", node.type, node.name); -} - -parse_struct_definition :: proc(data : ^ParserData) -> ^StructDefinitionNode { - node : StructDefinitionNode; - node.forwardDeclared = false; - parse_struct_or_union_members(data, &node.members); - - append(&data.nodes.structDefinitions, node); - return &data.nodes.structDefinitions[len(data.nodes.structDefinitions) - 1]; -} - -parse_union_definition :: proc(data : ^ParserData) -> ^UnionDefinitionNode { - node : UnionDefinitionNode; - parse_struct_or_union_members(data, &node.members); - - append(&data.nodes.unionDefinitions, node); - return &data.nodes.unionDefinitions[len(data.nodes.unionDefinitions) - 1]; -} - -parse_enum_definition :: proc(data : ^ParserData) -> ^EnumDefinitionNode { - node : EnumDefinitionNode; - parse_enum_members(data, &node.members); - - append(&data.nodes.enumDefinitions, node); - return &data.nodes.enumDefinitions[len(data.nodes.enumDefinitions) - 1]; -} - -/** - * { - * = , - * , - * } - */ -parse_enum_members :: proc(data : ^ParserData, members : ^[dynamic]EnumMember) { - check_and_eat_token(data, "{"); - - nextMemberValue : i64 = 0; - token := peek_token(data); - for token != "}" { - member : EnumMember; - member.name = parse_identifier(data); - member.hasValue = false; - - token = peek_token(data); - if token == "=" { - check_and_eat_token(data, "="); - - member.hasValue = true; - member.value = evaluate_i64(data); - nextMemberValue = member.value; - token = peek_token(data); - } else { - member.value = nextMemberValue; - } - - data.knownedLiterals[member.name] = member.value; - nextMemberValue += 1; - - // Eat until end, as this might be a complex expression that we couldn't understand - if token != "," && token != "}" { - print_warning("Parser cannot understand fully the expression of enum member ", member.name, "."); - for token != "," && token != "}" { - eat_token(data); - token = peek_token(data); - } - } - if token == "," { - check_and_eat_token(data, ","); - token = peek_token(data); - } - - append(members, member); - } - - check_and_eat_token(data, "}"); -} - -/** - * { - * ; - * , ; - * []; - * } - */ -parse_struct_or_union_members :: proc(data : ^ParserData, structOrUnionMembers : ^[dynamic]StructOrUnionMember) { - check_and_eat_token(data, "{"); - - // To ensure unique id - unamedCount := 0; - - token := peek_token(data); - for token != "}" { - member : StructOrUnionMember; - member.type = parse_type(data, true); - - for true { - // In the case of function pointer types, the name has been parsed - // during type inspection. - if type, ok := member.type.base.(FunctionPointerType); ok { - member.name = type.name; - } - else { - // Unamed (struct or union) - token = peek_token(data); - if !is_identifier(token) { - member.name = tcat("unamed", unamedCount); - unamedCount += 1; - } - else { - member.name = parse_identifier(data); - } - } - - parse_type_dimensions(data, &member.type); - - token = peek_token(data); - if token == ":" { - check_and_eat_token(data, ":"); - print_warning("Found bitfield in struct, which is not handled correctly."); - evaluate_i64(data); - token = peek_token(data); - } - - append(structOrUnionMembers, member); - - // Multiple declarations on one line - if token == "," { - check_and_eat_token(data, ","); - continue; - } - - break; - } - - check_and_eat_token(data, ";"); - token = peek_token(data); - } - - check_and_eat_token(data, "}"); -} - -parse_variable_or_function_declaration :: proc(data : ^ParserData) { - type := parse_type(data, true); - - // If it's just a type, it might be a struct definition - token := peek_token(data); - if token == ";" { - check_and_eat_token(data, ";"); - return; - } - - // Eat array declaration if any - // @fixme The return type of a function declaration will be wrong! - for data.bytes[data.offset] == '[' { - for data.bytes[data.offset] != ']' { - data.offset += 1; - } - data.offset += 1; - } - - name := parse_identifier(data); - - token = peek_token(data); - if token == "(" { - functionDeclarationNode := parse_function_declaration(data); - functionDeclarationNode.returnType = type; - functionDeclarationNode.name = name; - return; - } else if token == "[" { - // Eat whole array declaration - for data.bytes[data.offset] == '[' { - for data.bytes[data.offset] != ']' { - data.offset += 1; - } - data.offset += 1; - } - } - - // Global variable declaration (with possible multiple declarations) - token = peek_token(data); - - for true { - if token == "," { - print_warning("Found global variable declaration '", name, "', we won't generated any binding for it."); - check_and_eat_token(data, ","); - - name = parse_identifier(data); - token = peek_token(data); - continue; - } - else if token == ";" { - if name != "" { - print_warning("Found global variable declaration '", name, "', we won't generated any binding for it."); - } - check_and_eat_token(data, ";"); - break; - } - - // Global variable assignment, considered as constant define. - node : DefineNode; - - check_and_eat_token(data, "="); - literalValue, ok := evaluate(data); - if ok { - node.name = name; - node.value = literalValue; - append(&data.nodes.defines, node); - } - else { - print_warning("Ignoring global variable expression for '", name, "'."); - } - - name = ""; - token = peek_token(data); - } -} - -parse_function_declaration :: proc(data : ^ParserData) -> ^FunctionDeclarationNode { - node : FunctionDeclarationNode; - - parse_function_parameters(data, &node.parameters); - - // Function definition? Ignore it. - token := peek_token(data); - if token == "{" { - bracesCount := 1; - for true { - data.offset += 1; - if data.bytes[data.offset] == '{' do bracesCount += 1; - else if data.bytes[data.offset] == '}' do bracesCount -= 1; - if bracesCount == 0 do break; - } - data.offset += 1; - } // Function declaration - else { - check_and_eat_token(data, ";"); - } - - append(&data.nodes.functionDeclarations, node); - return &data.nodes.functionDeclarations[len(data.nodes.functionDeclarations) - 1]; -} - -parse_function_parameters :: proc(data : ^ParserData, parameters : ^[dynamic]FunctionParameter) { - check_and_eat_token(data, "("); - - token := peek_token(data); - for token != ")" { - parameter : FunctionParameter; - - token = peek_token(data); - if token == "." { - print_warning("A function accepts variadic arguments, this is currently not handled within generated code."); - - check_and_eat_token(data, "."); - check_and_eat_token(data, "."); - check_and_eat_token(data, "."); - break; - } else { - parameter.type = parse_type(data); - } - - // Check if named parameter - token = peek_token(data); - if token != ")" && token != "," { - parameter.name = parse_identifier(data); - parse_type_dimensions(data, ¶meter.type); - token = peek_token(data); - } - - if token == "," { - eat_token(data); - token = peek_token(data); - } - - append(parameters, parameter); - } - - check_and_eat_token(data, ")"); -} diff --git a/core/bindgen/errors.odin b/core/bindgen/errors.odin deleted file mode 100644 index 9564c5244..000000000 --- a/core/bindgen/errors.odin +++ /dev/null @@ -1,44 +0,0 @@ -package bindgen - -import "core:fmt" -import "core:os" - -seenWarnings : map[string]bool; - -print_warning :: proc(args : ..any) { - message := tcat(..args); - - if !seenWarnings[message] { - fmt.eprint("[bindgen] Warning: ", message, "\n"); - seenWarnings[message] = true; - } -} - -print_error :: proc(data : ^ParserData, loc := #caller_location, args : ..any) { - message := tcat(..args); - - min : u32 = 0; - for i := data.offset - 1; i > 0; i -= 1 { - if data.bytes[i] == '\n' { - min = i + 1; - break; - } - } - - max := min + 200; - for i := min + 1; i < max; i += 1 { - if data.bytes[i] == '\n' { - max = i; - break; - } - } - - line, _ := get_line_column(data); - - fmt.eprint("[bindgen] Error: ", message, "\n"); - fmt.eprint("[bindgen] ... from ", loc.procedure, "\n"); - fmt.eprint("[bindgen] ... at line ", line, " within this context:\n"); - fmt.eprint("> ", extract_string(data, min, max), "\n"); - - os.exit(1); -} diff --git a/core/bindgen/generator-clean.odin b/core/bindgen/generator-clean.odin deleted file mode 100644 index 8dd837b10..000000000 --- a/core/bindgen/generator-clean.odin +++ /dev/null @@ -1,284 +0,0 @@ -package bindgen - -import "core:fmt" - -// Prevent keywords clashes and other tricky cases -clean_identifier :: proc(name : string) -> string { - name := name; - - if name == "" { - return name; - } - - // Starting with _? Try removing that. - for true { - if name[0] == '_' { - name = name[1:]; - } - else { - break; - } - } - - // Number - if name[0] >= '0' && name[0] <= '9' { - return tcat("_", name); - } // Keywords clash - else if name == "map" || name == "proc" || name == "opaque" || name == "in" { - return tcat("_", name); - } // Jai keywords clash - else if name == "context" || - name == "float32" || name == "float64" || - name == "s8" || name == "s16" || name == "s32" || name == "s64" || - name == "u8" || name == "u16" || name == "u32" || name == "u64" { - return tcat("_", name); - } - - return name; -} - -clean_variable_name :: proc(name : string, options : ^GeneratorOptions) -> string { - name := name; - name = change_case(name, options.variableCase); - return clean_identifier(name); -} - -clean_pseudo_type_name :: proc(structName : string, options : ^GeneratorOptions) -> string { - structName := structName; - structName = remove_postfixes(structName, options.pseudoTypePostfixes, options.pseudoTypeTransparentPostfixes); - structName = remove_prefixes(structName, options.pseudoTypePrefixes, options.pseudoTypeTransparentPrefixes); - structName = change_case(structName, options.pseudoTypeCase); - return structName; -} - -// Clean up the enum name so that it can be used to remove the prefix from enum values. -clean_enum_name_for_prefix_removal :: proc(enumName : string, options : ^GeneratorOptions) -> (string, [dynamic]string) { - enumName := enumName; - - if !options.enumValueNameRemove { - return enumName, nil; - } - - // Remove postfix and use same case convention as the enum values - removedPostfixes : [dynamic]string; - enumName, removedPostfixes = remove_postfixes_with_removed(enumName, options.enumValueNameRemovePostfixes); - enumName = change_case(enumName, options.enumValueCase); - return enumName, removedPostfixes; -} - -clean_enum_value_name :: proc(valueName : string, enumName : string, postfixes : []string, options : ^GeneratorOptions) -> string { - valueName := valueName; - - valueName = remove_prefixes(valueName, options.enumValuePrefixes, options.enumValueTransparentPrefixes); - valueName = remove_postfixes(valueName, postfixes, options.enumValueTransparentPostfixes); - - if options.enumValueNameRemove { - valueName = remove_prefixes(valueName, []string{enumName}); - } - - valueName = change_case(valueName, options.enumValueCase); - - return clean_identifier(valueName); -} - -clean_function_name :: proc(functionName : string, options : ^GeneratorOptions) -> string { - functionName := functionName; - functionName = remove_prefixes(functionName, options.functionPrefixes, options.functionTransparentPrefixes); - functionName = remove_postfixes(functionName, options.definePostfixes, options.defineTransparentPostfixes); - functionName = change_case(functionName, options.functionCase); - return functionName; -} - -clean_define_name :: proc(defineName : string, options : ^GeneratorOptions) -> string { - defineName := defineName; - defineName = remove_prefixes(defineName, options.definePrefixes, options.defineTransparentPrefixes); - defineName = remove_postfixes(defineName, options.definePostfixes, options.defineTransparentPostfixes); - defineName = change_case(defineName, options.defineCase); - return defineName; -} - -// Convert to Odin's types -clean_type :: proc(data : ^GeneratorData, type : Type, baseTab : string = "", explicitSharpType := true) -> string { - output := ""; - - for dimension in type.dimensions { - output = tcat(output, "[", dimension, "]"); - } - output = tcat(output, clean_base_type(data, type.base, baseTab, explicitSharpType)); - - return output; -} - -clean_base_type :: proc(data : ^GeneratorData, baseType : BaseType, baseTab : string = "", explicitSharpType := true) -> string { - options := data.options; - - if _type, ok := baseType.(BuiltinType); ok { - if _type == BuiltinType.Void do return options.mode == "jai" ? "void" : ""; - else if _type == BuiltinType.Int do return options.mode == "jai" ? "s64" : "_c.int"; - else if _type == BuiltinType.UInt do return options.mode == "jai" ? "u64" :"_c.uint"; - else if _type == BuiltinType.LongInt do return options.mode == "jai" ? "s64" :"_c.long"; - else if _type == BuiltinType.ULongInt do return options.mode == "jai" ? "u64" :"_c.ulong"; - else if _type == BuiltinType.LongLongInt do return options.mode == "jai" ? "s64" :"_c.longlong"; - else if _type == BuiltinType.ULongLongInt do return options.mode == "jai" ? "u64" :"_c.ulonglong"; - else if _type == BuiltinType.ShortInt do return options.mode == "jai" ? "s16" :"_c.short"; - else if _type == BuiltinType.UShortInt do return options.mode == "jai" ? "u16" :"_c.ushort"; - else if _type == BuiltinType.Char do return options.mode == "jai" ? "u8" :"_c.char"; - else if _type == BuiltinType.SChar do return options.mode == "jai" ? "s8" :"_c.schar"; - else if _type == BuiltinType.UChar do return options.mode == "jai" ? "u8" :"_c.uchar"; - else if _type == BuiltinType.Float do return options.mode == "jai" ? "float32" :"_c.float"; - else if _type == BuiltinType.Double do return options.mode == "jai" ? "float64" :"_c.double"; - else if _type == BuiltinType.LongDouble { - print_warning("Found long double which is currently not supported. Fallback to double in generated code."); - return options.mode == "jai" ? "double" :"_c.double"; - } - else if _type == BuiltinType.Int8 do return options.mode == "jai" ? "s8" :"i8"; - else if _type == BuiltinType.Int16 do return options.mode == "jai" ? "s16" :"i16"; - else if _type == BuiltinType.Int32 do return options.mode == "jai" ? "s32" :"i32"; - else if _type == BuiltinType.Int64 do return options.mode == "jai" ? "s64" :"i64"; - else if _type == BuiltinType.UInt8 do return options.mode == "jai" ? "u8" :"u8"; - else if _type == BuiltinType.UInt16 do return options.mode == "jai" ? "u16" :"u16"; - else if _type == BuiltinType.UInt32 do return options.mode == "jai" ? "u32" :"u32"; - else if _type == BuiltinType.UInt64 do return options.mode == "jai" ? "u64" :"u64"; - else if _type == BuiltinType.Size do return options.mode == "jai" ? "u64" :"_c.size_t"; - else if _type == BuiltinType.SSize do return options.mode == "jai" ? "u64" :"_c.ssize_t"; - else if _type == BuiltinType.PtrDiff do return options.mode == "jai" ? "s64" :"_c.ptrdiff_t"; - else if _type == BuiltinType.UIntPtr do return options.mode == "jai" ? "u64" :"_c.uintptr_t"; - else if _type == BuiltinType.IntPtr do return options.mode == "jai" ? "s64" :"_c.intptr_t"; - } - else if _type, ok := baseType.(PointerType); ok { - if options.mode == "jai" { - // Hide pointers to types that were not declared. - if !is_known_base_type(data, _type.type.base) { - print_warning("*", _type.type.base.(IdentifierType).name, " replaced by *void as the pointed type is unknown."); - return "*void"; - } - } else { - if __type, ok := _type.type.base.(BuiltinType); ok { - if __type == BuiltinType.Void do return "rawptr"; - else if __type == BuiltinType.Char do return "cstring"; - } - } - name := clean_type(data, _type.type^, baseTab); - return tcat(options.mode == "jai" ? "*" :"^", name); - } - else if _type, ok := baseType.(IdentifierType); ok { - return clean_pseudo_type_name(_type.name, options); - } - else if _type, ok := baseType.(FunctionType); ok { - output : string; - if explicitSharpType { - output = "#type "; - } - output = tcat(output, options.mode == "jai" ? "(" :"proc("); - parameters := clean_function_parameters(data, _type.parameters, baseTab); - output = tcat(output, parameters, ")"); - - returnType := clean_type(data, _type.returnType^); - if len(returnType) > 0 && returnType != "void" { - output = tcat(output, " -> ", returnType); - } - return output; - } - else if _type, ok := baseType.(FunctionPointerType); ok { - output : string; - if explicitSharpType { - output = "#type "; - } - output = tcat(output, options.mode == "jai" ? "(" :"proc("); - parameters := clean_function_parameters(data, _type.parameters, baseTab); - output = tcat(output, parameters, ")"); - - returnType := clean_type(data, _type.returnType^); - if len(returnType) > 0 && returnType != "void" { - output = tcat(output, " -> ", returnType); - } - - if options.mode == "jai" { - output = tcat(output, " #foreign"); - } - return output; - } - - return ""; -} - -clean_function_parameters :: proc(data : ^GeneratorData, parameters : [dynamic]FunctionParameter, baseTab : string) -> string { - output := ""; - options := data.options; - - // Special case: function(void) does not really have a parameter - if len(parameters) == 1 { - if _type, ok := parameters[0].type.base.(BuiltinType); ok { - if _type == BuiltinType.Void { - return ""; - } - } - } - - tab := ""; - if options.mode == "jai" { // @note :OdinCodingStyle Odin forces a coding style, now. Ugh. - if (len(parameters) > 1) { - output = tcat(output, "\n"); - tab = tcat(baseTab, " "); - } - } - - unamedParametersCount := 0; - for parameter, i in parameters { - type := clean_type(data, parameter.type); - - name : string; - if len(parameter.name) != 0 { - name = clean_variable_name(parameter.name, options); - } else { - name = tcat("unamed", unamedParametersCount); - unamedParametersCount += 1; - } - - output = tcat(output, tab, name, " : ", type); - - if i != len(parameters) - 1 { - if options.mode == "jai" { // @note :OdinCodingStyle - output = tcat(output, ",\n"); - } else { - output = tcat(output, ", "); - } - } - } - - if (len(parameters) > 1) { - if options.mode == "jai" { // @note :OdinCodingStyle - output = tcat(output, "\n", baseTab); - } - } - - return output; -} - -is_known_base_type :: proc(data : ^GeneratorData, baseType : BaseType) -> bool { - if _type, ok := baseType.(IdentifierType); ok { - for it in data.nodes.typedefs { - if _type.name == it.name { - return true; - } - } - for it in data.nodes.structDefinitions { - if _type.name == it.name { - return true; - } - } - for it in data.nodes.enumDefinitions { - if _type.name == it.name { - return true; - } - } - for it in data.nodes.unionDefinitions { - if _type.name == it.name { - return true; - } - } - return false; - } - - return true; -} diff --git a/core/bindgen/generator-export.odin b/core/bindgen/generator-export.odin deleted file mode 100644 index a04113ed9..000000000 --- a/core/bindgen/generator-export.odin +++ /dev/null @@ -1,166 +0,0 @@ -package bindgen - -import "core:os" -import "core:fmt" - -export_defines :: proc(data : ^GeneratorData) { - for node in data.nodes.defines { - defineName := clean_define_name(node.name, data.options); - - // @fixme fprint of float numbers are pretty badly handled, - // just has a 10^-3 precision. - fcat(data.handle, defineName, " :: ", node.value, ";\n"); - } - fcat(data.handle, "\n"); -} - -export_typedefs :: proc(data : ^GeneratorData) { - for node in data.nodes.typedefs { - name := clean_pseudo_type_name(node.name, data.options); - type := clean_type(data, node.type, "", true); - if name == type do continue; - fcat(data.handle, name, " :: ", type, ";\n"); - } - fcat(data.handle, "\n"); -} - -export_enums :: proc(data : ^GeneratorData) { - for node in data.nodes.enumDefinitions { - enumName := clean_pseudo_type_name(node.name, data.options); - - if data.options.mode == "jai" { - consideredFlags := false; - for postfix in data.options.enumConsideredFlagsPostfixes { - if ends_with(node.name, postfix) { - consideredFlags = true; - break; - } - } - - if consideredFlags { - fcat(data.handle, enumName, " :: enum_flags u32 {"); - } else { - fcat(data.handle, enumName, " :: enum s32 {"); - } - } else { - fcat(data.handle, enumName, " :: enum i32 {"); - } - - postfixes : [dynamic]string; - enumName, postfixes = clean_enum_name_for_prefix_removal(enumName, data.options); - - // Changing the case of postfixes to the enum value one, - // so that they can be removed. - enumValueCase := find_case(node.members[0].name); - for postfix, i in postfixes { - postfixes[i] = change_case(postfix, enumValueCase); - } - - // And changing the case of enumName to the enum value one - enumName = change_case(enumName, enumValueCase); - - // Merging enum value postfixes with postfixes that have been removed from the enum name. - for postfix in data.options.enumValuePostfixes { - append(&postfixes, postfix); - } - - export_enum_members(data, node.members, enumName, postfixes[:]); - fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); - fcat(data.handle, "\n"); - } -} - -export_structs :: proc(data : ^GeneratorData) { - for node in data.nodes.structDefinitions { - structName := clean_pseudo_type_name(node.name, data.options); - fcat(data.handle, structName, " :: struct {"); - export_struct_or_union_members(data, node.members); - fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); - fcat(data.handle, "\n"); - } -} - -export_unions :: proc(data : ^GeneratorData) { - for node in data.nodes.unionDefinitions { - unionName := clean_pseudo_type_name(node.name, data.options); - fcat(data.handle, unionName, data.options.mode == "jai" ? " :: union {" : " :: struct #raw_union {"); - export_struct_or_union_members(data, node.members); - fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n"); - fcat(data.handle, "\n"); - } -} - -export_functions :: proc(data : ^GeneratorData) { - for node in data.nodes.functionDeclarations { - functionName := clean_function_name(node.name, data.options); - if data.options.mode == "jai" { - fcat(data.handle, functionName, " :: ("); - } else { - fcat(data.handle, " @(link_name=\"", node.name, "\")\n"); - fcat(data.handle, " ", functionName, " :: proc("); - } - parameters := clean_function_parameters(data, node.parameters, data.options.mode == "jai" ? "" : " "); - fcat(data.handle, parameters, ")"); - returnType := clean_type(data, node.returnType); - if len(returnType) > 0 { - fcat(data.handle, " -> ", returnType); - } - if data.options.mode == "jai" { - fcat(data.handle, " #foreign ", data.foreignLibrary, " \"", node.name ,"\";\n"); - } else { - fcat(data.handle, " ---;\n"); - } - fcat(data.handle, "\n"); - } -} - -export_enum_members :: proc(data : ^GeneratorData, members : [dynamic]EnumMember, enumName : string, postfixes : []string) { - if (len(members) > 0) { - fcat(data.handle, "\n"); - } - - cleanedMembers : [dynamic]EnumMember; - for member in members { - cleanedMember : EnumMember; - cleanedMember.hasValue = member.hasValue; - cleanedMember.value = member.value; - cleanedMember.name = clean_enum_value_name(member.name, enumName, postfixes, data.options); - - if len(cleanedMember.name) == 0 { - // print_warning("Enum member ", member.name, " resolves to an empty name. Ignoring it."); - continue; - } - - // Ensuring that we don't collide with an other enum member. - foundCopy := false; - for existingCleanedMember in cleanedMembers { - if cleanedMember.name == existingCleanedMember.name && - cleanedMember.hasValue == existingCleanedMember.hasValue && - cleanedMember.value == existingCleanedMember.value { - print_warning("Enum member ", member.name, " is duplicated once cleaned. Keeping only one copy."); - foundCopy = true; - break; - } - } - if foundCopy do continue; - - fcat(data.handle, " ", cleanedMember.name); - if member.hasValue { - fcat(data.handle, data.options.mode == "jai" ? " :: " : " = ", member.value); - } - fcat(data.handle, data.options.mode == "jai" ? ";\n" : ",\n"); - - append(&cleanedMembers, cleanedMember); - } -} - -export_struct_or_union_members :: proc(data : ^GeneratorData, members : [dynamic]StructOrUnionMember) { - if (len(members) > 0) { - fcat(data.handle, "\n"); - } - for member in members { - type := clean_type(data, member.type, " "); - name := clean_variable_name(member.name, data.options); - fcat(data.handle, " ", name, " : ", type, data.options.mode == "jai" ? ";\n" : ",\n"); - } -} diff --git a/core/bindgen/generator-helpers.odin b/core/bindgen/generator-helpers.odin deleted file mode 100644 index a3b37f4f6..000000000 --- a/core/bindgen/generator-helpers.odin +++ /dev/null @@ -1,392 +0,0 @@ -package bindgen - -import "core:fmt" -import "core:os" -import "core:io" -import "core:strings" -import "core:unicode/utf8" - -Case :: enum { - Unknown, - Camel, - Constant, - Kebab, - Pascal, - Snake, -} - -WordCase :: enum { - Unknown, - Up, - Low, - FirstUp, - // When first upping, numbers are followed always by a capital - FirstUpNumberReset, -} - -// Change a character to a capital. -to_uppercase :: proc(c : rune) -> rune { - c := c; - if c >= 'a' && c <= 'z' { - c = c - 'a' + 'A'; - } - return c; -} - -// Change a character to lowercase. -to_lowercase :: proc(c : rune) -> rune { - c := c; - if c >= 'A' && c <= 'Z' { - c = c - 'A' + 'a'; - } - return c; -} - -// @note Stolen tprint and fprint from fmt package, because it was confusing due to args: ..any and sep default parameter. -tcat :: proc(args: ..any) -> string { - return fmt.tprint(args=args, sep=""); -} - -fcat :: proc(fd: os.Handle, args: ..any) -> int { - return fmt.fprint(fd=fd, args=args, sep=""); -} - -// Change the case convention of a word. -change_word_case :: proc(str : string, targetCase : WordCase) -> string { - newStr : string; - if targetCase == WordCase.Up { - for c in str { - newStr = tcat(newStr, to_uppercase(c)); - } - } - else if targetCase == WordCase.Low { - for c in str { - newStr = tcat(newStr, to_lowercase(c)); - } - } - else if targetCase == WordCase.FirstUp { - for c, i in str { - if i == 0 { - newStr = tcat(newStr, to_uppercase(c)); - } else { - newStr = tcat(newStr, to_lowercase(c)); - } - } - } - else if targetCase == WordCase.FirstUpNumberReset { - for c, i in str { - if i == 0 || (str[i - 1] >= '0' && str[i - 1] <= '9') { - newStr = tcat(newStr, to_uppercase(c)); - } else { - newStr = tcat(newStr, to_lowercase(c)); - } - } - } - return newStr; -} - -// Change the case convention of a string by detecting original convention, -// then splitting it into words. -change_case :: proc(str : string, targetCase : Case) -> string { - if targetCase == Case.Unknown { - return str; - } - - // Split - parts := autosplit_string(str); - - // Join - newStr : string; - if targetCase == Case.Pascal { - for part, i in parts { - newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset)); - } - } - else if targetCase == Case.Snake { - for part, i in parts { - newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "_" : ""); - } - } - else if targetCase == Case.Kebab { - for part, i in parts { - newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "-" : ""); - } - } - else if targetCase == Case.Camel { - for part, i in parts { - if i == 0 { - newStr = tcat(newStr, change_word_case(part, WordCase.Low)); - } else { - newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset)); - } - } - } - else if targetCase == Case.Constant { - for part, i in parts { - newStr = tcat(newStr, change_word_case(part, WordCase.Up), (i != len(parts) - 1) ? "_" : ""); - } - } - - return newStr; -} - -// Identify the case of the provided string. -// Full lowercase with no separator is identified as camelCase. -find_case :: proc(str : string) -> Case { - refuted : bool; - - // CONSTANT_CASE - refuted = false; - for c in str { - if (c != '_') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') { - refuted = true; - break; - } - } - if !refuted do return Case.Constant; - - for c in str { - // snake_case - if c == '_' { - return Case.Snake; - } // kebab-case - else if c == '-' { - return Case.Kebab; - } - } - - // PascalCase - if str[0] >= 'A' && str[0] <= 'Z' { - return Case.Pascal; - } - - // camelCase - return Case.Camel; -} - -// Splits the string according to detected case. -// HeyBuddy -> {"Hey", "Buddy"} -// hey-buddy -> {"hey", "buddy"} -// _hey_buddy -> {"", "hey", "buddy"} -// and such... -autosplit_string :: proc(str : string) -> [dynamic]string { - lowCount := 0; - upCount := 0; - for c in str { - // If any '_', split according to that (CONSTANT_CASE or snake_case) - if c == '_' { - return split_from_separator(str, '_'); - } // If any '-', split according to that (kebab-case) - else if c == '-' { - return split_from_separator(str, '-'); - } - else if c >= 'a' && c <= 'z' { - lowCount += 1; - } - else if c >= 'A' && c <= 'Z' { - upCount += 1; - } - } - - // If it seems to be only one word - if lowCount == 0 || upCount == 0 { - parts : [dynamic]string; - append(&parts, str); - return parts; - } - - // Split at each uppercase letter (PascalCase or camelCase) - return split_from_capital(str); -} - -split_from_separator :: proc(str : string, sep : rune) -> [dynamic]string { - parts : [dynamic]string; - - lastI := 0; - - // Empty strings for starting separators in string - for c in str { - if c == sep { - append(&parts, ""); - lastI += 1; - } else { - break; - } - } - - // Ignore non letter prefix - if lastI == 0 { - for c in str { - if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') { - lastI += 1; - } - else { - break; - } - } - } - - for c, i in str { - if i > lastI + 1 && c == sep { - append(&parts, str[lastI:i]); - lastI = i + 1; - } - } - - append(&parts, str[lastI:]); - - return parts; -} - -split_from_capital :: proc(str : string) -> [dynamic]string { - parts : [dynamic]string; - - // Ignore non letter prefix - lastI := 0; - for c in str { - if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') { - lastI += 1; - } - else { - break; - } - } - - // We want to handle: - // myBrainIsCRAZY -> my Brain Is Crazy - // myCRAZYBrain -> my CRAZY Brain - // SOLO -> SOLO - - // Do split - for i := 1; i < len(str); i += 1 { - if str[i] >= 'A' && str[i] <= 'Z' { - // Do not split too much if it seems to be a capitalized word - if (lastI == i - 1) && (str[lastI] >= 'A' && str[lastI] <= 'Z') { - for ; i + 1 < len(str); i += 1 { - if str[i + 1] < 'A' || str[i + 1] > 'Z' { - break; - } - } - if (i + 1 == len(str)) && (str[i] >= 'A' && str[i] <= 'Z') { - i += 1; - } - } - - append(&parts, str[lastI:i]); - lastI = i; - } - } - - if lastI != len(str) { - append(&parts, str[lastI:]); - } - - return parts; -} - -// Check if str if prefixed with any of the provided strings, -// even combinaisons of those, and remove them. -remove_prefixes :: proc(str : string, prefixes : []string, transparentPrefixes : []string = nil) -> string { - str := str; - transparentStr := ""; - - found := true; - for found { - found = false; - - // Remove effective prefixes - for prefix in prefixes { - if len(str) >= len(prefix) && - str[:len(prefix)] == prefix { - str = str[len(prefix):]; - if len(str) != 0 && (str[0] == '_' || str[0] == '-') { - str = str[1:]; - } - found = true; - break; - } - } - - if found do continue; - - // Remove transparent ones, only one by one, - // as we want effective ones to be fully removed. - for prefix in transparentPrefixes { - if len(str) >= len(prefix) && - str[:len(prefix)] == prefix { - str = str[len(prefix):]; - transparentStr = tcat(transparentStr, prefix); - if len(str) != 0 && (str[0] == '_' || str[0] == '-') { - str = str[1:]; - transparentStr = tcat(transparentStr, '_'); - } - found = true; - break; - } - } - } - - return tcat(transparentStr, str); -} - -// Check if str if postfixes with any of the provided strings, -// even combinaisons of those, and remove them. -remove_postfixes_with_removed :: proc( - str : string, - postfixes : []string, - transparentPostfixes : []string = nil) -> (string, [dynamic]string) { - str := str; - removedPostfixes : [dynamic]string; - transparentStr := ""; - - found := true; - for found { - found = false; - - // Remove effective postfixes - for postfix in postfixes { - if ends_with(str, postfix) { - str = str[:len(str) - len(postfix)]; - if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') { - str = str[:len(str)-1]; - } - append(&removedPostfixes, postfix); - found = true; - break; - } - } - - if found do continue; - - // Remove transparent ones, only one by one, - // as we want effective ones to be fully removed. - for postfix in transparentPostfixes { - if ends_with(str, postfix) { - str = str[:len(str) - len(postfix)]; - transparentStr = tcat(postfix, transparentStr); - if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') { - str = str[:len(str)-1]; - transparentStr = tcat('_', transparentStr); - } - found = true; - break; - } - } - } - - return tcat(str, transparentStr), removedPostfixes; -} - -remove_postfixes :: proc( - str : string, - postfixes : []string, - transparentPostfixes : []string = nil) -> string { - str := str; - removedPostfixes : [dynamic]string; - str, removedPostfixes = remove_postfixes_with_removed(str, postfixes, transparentPostfixes); - return str; -} - -ends_with :: proc(str : string, postfix : string) -> bool { - return len(str) >= len(postfix) && str[len(str) - len(postfix):] == postfix; -} diff --git a/core/bindgen/generator.odin b/core/bindgen/generator.odin deleted file mode 100644 index 3ef3d69c0..000000000 --- a/core/bindgen/generator.odin +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Odin binding generator from C header data. - */ - -package bindgen - -import "core:os" -import "core:fmt" -import "core:runtime" - -GeneratorOptions :: struct { - mode : string, // "odin" or "jai" - - // Variable - variableCase : Case, - - // Defines - definePrefixes : []string, - defineTransparentPrefixes : []string, - definePostfixes : []string, - defineTransparentPostfixes : []string, - defineCase : Case, - - // Pseudo-types - pseudoTypePrefixes : []string, - pseudoTypeTransparentPrefixes : []string, - pseudoTypePostfixes : []string, - pseudoTypeTransparentPostfixes : []string, - pseudoTypeCase : Case, - - // Enums - enumConsideredFlagsPostfixes : []string, - - // Functions - functionPrefixes : []string, - functionTransparentPrefixes : []string, - functionPostfixes : []string, - functionTransparentPostfixes : []string, - functionCase : Case, - - // Enum values - enumValuePrefixes : []string, - enumValueTransparentPrefixes : []string, - enumValuePostfixes : []string, - enumValueTransparentPostfixes : []string, - enumValueCase : Case, - enumValueNameRemove : bool, - enumValueNameRemovePostfixes : []string, - - parserOptions : ParserOptions, -} - -GeneratorData :: struct { - handle : os.Handle, - nodes : Nodes, - - // References - foreignLibrary : string, - options : ^GeneratorOptions, -} - -generate :: proc( - packageName : string, - foreignLibrary : string, - outputFile : string, - headerFiles : []string, - options : GeneratorOptions, -) { - options := options; - data : GeneratorData; - data.options = &options; - data.foreignLibrary = foreignLibrary; - - if options.mode == "" { - options.mode = "odin"; - } - - // Outputing odin file - errno : os.Errno; - - // chmod 664 when creating file - mode: int = 0; - when os.OS == "linux" || os.OS == "darwin" { - mode = os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IWGRP | os.S_IROTH; - } - - data.handle, errno = os.open(outputFile, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, mode); - if errno != 0 { - fmt.eprint("[bindgen] Unable to write to output file ", outputFile, " (", errno ,")\n"); - return; - } - defer os.close(data.handle); - - if options.mode == "jai" { - fcat(data.handle, foreignLibrary, " :: #foreign_library \"", foreignLibrary, "\";\n"); - fcat(data.handle, "\n"); - } else { - fcat(data.handle, "package ", packageName, "\n"); - fcat(data.handle, "\n"); - fcat(data.handle, "foreign import \"", foreignLibrary, "\"\n"); - fcat(data.handle, "\n"); - fcat(data.handle, "import _c \"core:c\"\n"); - fcat(data.handle, "\n"); - } - - // Parsing header files - anonymousStructCount = 0; - anonymousUnionCount = 0; - anonymousEnumCount = 0; - - for headerFile in headerFiles { - bytes, ok := os.read_entire_file(headerFile); - if !ok { - fmt.eprint("[bindgen] Unable to read file ", headerFile, "\n"); - return; - } - - // We fuse the SOAs - headerNodes := parse(bytes, options.parserOptions); - merge_generic_nodes(&data.nodes.defines, &headerNodes.defines); - merge_generic_nodes(&data.nodes.enumDefinitions, &headerNodes.enumDefinitions); - merge_generic_nodes(&data.nodes.unionDefinitions, &headerNodes.unionDefinitions); - merge_forward_declared_nodes(&data.nodes.structDefinitions, &headerNodes.structDefinitions); - merge_generic_nodes(&data.nodes.functionDeclarations, &headerNodes.functionDeclarations); - merge_generic_nodes(&data.nodes.typedefs, &headerNodes.typedefs); - } - - // Exporting - export_defines(&data); - export_typedefs(&data); - export_enums(&data); - export_structs(&data); - export_unions(&data); - - // Foreign block for functions - if options.mode != "jai" { - foreignLibrarySimple := simplify_library_name(foreignLibrary); - fcat(data.handle, "@(default_calling_convention=\"c\")\n"); - fcat(data.handle, "foreign ", foreignLibrarySimple, " {\n"); - fcat(data.handle, "\n"); - } - - export_functions(&data); - - if options.mode != "jai" { - fcat(data.handle, "}\n"); - } -} - -// system:foo.lib -> foo -simplify_library_name :: proc(libraryName : string) -> string { - startOffset := 0; - endOffset := len(libraryName); - - for c, i in libraryName { - if startOffset == 0 && c == ':' { - startOffset = i + 1; - } - else if c == '.' { - endOffset = i; - break; - } - } - - return libraryName[startOffset:endOffset]; -} - -merge_generic_nodes :: proc(nodes : ^$T, headerNodes : ^T) { - for headerNode in headerNodes { - // Check that there are no duplicated nodes (due to forward declaration or such) - duplicatedIndex := -1; - for i := 0; i < len(nodes); i += 1 { - node := nodes[i]; - if node.name == headerNode.name { - duplicatedIndex = i; - break; - } - } - - if duplicatedIndex < 0 { - append(nodes, headerNode); - } - } -} - -merge_forward_declared_nodes :: proc(nodes : ^$T, headerNodes : ^T) { - for headerNode in headerNodes { - // Check that there are no duplicated nodes (due to forward declaration or such) - duplicatedIndex := -1; - for i := 0; i < len(nodes); i += 1 { - node := nodes[i]; - if node.name == headerNode.name { - duplicatedIndex = i; - break; - } - } - - if duplicatedIndex < 0 { - append(nodes, headerNode); - } - else if !headerNode.forwardDeclared && len(headerNode.members) > 0 { - nodes[duplicatedIndex] = headerNode; - } - } -} diff --git a/wasm-ld b/wasm-ld deleted file mode 120000 index 01ef2a7e7..000000000 --- a/wasm-ld +++ /dev/null @@ -1 +0,0 @@ -/Volumes/Phill_Backup/pers/programming/sdk/emsdk/upstream/bin/lld \ No newline at end of file From 4aad835a6602ef95db3c4cc937c6637be0e7e34f Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:19:28 -0400 Subject: [PATCH 06/12] replaced ODIN_OS string values with enums --- vendor/glfw/bindings/bindings.odin | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index 52dc10a13..d1295dbf5 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -3,22 +3,25 @@ package glfw_bindings import "core:c" import vk "vendor:vulkan" -when ODIN_OS == "linux" { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux -when ODIN_OS == "darwin" { - foreign import glfw { - "../lib/darwin/libglfw3.a", - "system:Cocoa.framework", - "system:IOKit.framework", - "system:OpenGL.framework", - } -} -when ODIN_OS == "windows" { +when ODIN_OS == .Windows { foreign import glfw { "../lib/glfw3_mt.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib", } +} else when ODIN_OS == .Linux { + // TODO: Add the billion-or-so static libs to link to in linux + foreign import glfw "system:glfw" +} else when ODIN_OS == .Darwin { + foreign import glfw { + "../lib/darwin/libglfw3.a", + "system:Cocoa.framework", + "system:IOKit.framework", + "system:OpenGL.framework", + } +} else { + foreign import glfw "system:glfw" } #assert(size_of(c.int) == size_of(b32)) From f213622982d6662fe75a9ec0a19bee99527eff15 Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:20:37 -0400 Subject: [PATCH 07/12] replace ODIN_OS string with enums --- vendor/stb/image/stb_image.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index 12f7aea9f..27f4e7201 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -4,9 +4,9 @@ import c "core:c/libc" #assert(size_of(c.int) == size_of(b32)) -when ODIN_OS == "windows" { foreign import stbi "../lib/stb_image.lib" } -when ODIN_OS == "linux" { foreign import stbi "../lib/stb_image.a" } -when ODIN_OS == "darwin" { foreign import stbi "../lib/darwin/stb_image.a" } +when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" } +when ODIN_OS == .Linux { foreign import stbi "../lib/stb_image.a" } +when ODIN_OS == .Darwin { foreign import stbi "../lib/stb_image.a" } #assert(size_of(b32) == size_of(c.int)) From 3f27cb230937607b29baddff3c7c3ebaa0b6aed0 Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:22:00 -0400 Subject: [PATCH 08/12] replace ODIN_OS string with enums --- vendor/stb/image/stb_image_write.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin index 2a2ec240c..b9433e821 100644 --- a/vendor/stb/image/stb_image_write.odin +++ b/vendor/stb/image/stb_image_write.odin @@ -2,9 +2,9 @@ package stb_image import c "core:c/libc" -when ODIN_OS == "windows" { foreign import stbiw "../lib/stb_image_write.lib" } -when ODIN_OS == "linux" { foreign import stbiw "../lib/stb_image_write.a" } -when ODIN_OS == "darwin" { foreign import stbiw "../lib/darwin/stb_image_write.a" } +when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } +when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == .Darwin { foreign import stbiw "../lib/stb_image_write.a" } write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int) From 727a25f41f715b4c432504d6c53116916656e1f4 Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:23:24 -0400 Subject: [PATCH 09/12] Replace ODIN_OS strings with enum values --- vendor/stb/image/stb_image_resize.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index c75a95fc9..4268aeb34 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -2,9 +2,9 @@ package stb_image import c "core:c/libc" -when ODIN_OS == "windows" { foreign import lib "../lib/stb_image_resize.lib" } -when ODIN_OS == "linux" { foreign import lib "../lib/stb_image_resize.a" } -when ODIN_OS == "darwin" { foreign import lib "../lib/darwin/stb_image_resize.a" } +when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } +when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == .Darwin { foreign import stbiw "../lib/stb_image_write.a" } ////////////////////////////////////////////////////////////////////////////// // From 21f2c06f4be9ac8aa0738e9dc71d1024cb148e07 Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:25:18 -0400 Subject: [PATCH 10/12] Update stb_image_resize.odin --- vendor/stb/image/stb_image_resize.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index 4268aeb34..be1f8dbd6 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -2,9 +2,9 @@ package stb_image import c "core:c/libc" -when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } -when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } -when ODIN_OS == .Darwin { foreign import stbiw "../lib/stb_image_write.a" } +when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_write.lib" } +when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_write.a" } +when ODIN_OS == .Darwin { foreign import lib "../lib/stb_image_write.a" } ////////////////////////////////////////////////////////////////////////////// // From d26cfd2141a565dd14629c3b8c4c511f60499498 Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:26:22 -0400 Subject: [PATCH 11/12] Update bindings.odin --- vendor/glfw/bindings/bindings.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index d1295dbf5..aea09e31d 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -15,11 +15,11 @@ when ODIN_OS == .Windows { foreign import glfw "system:glfw" } else when ODIN_OS == .Darwin { foreign import glfw { - "../lib/darwin/libglfw3.a", - "system:Cocoa.framework", - "system:IOKit.framework", - "system:OpenGL.framework", - } + "../lib/darwin/libglfw3.a", + "system:Cocoa.framework", + "system:IOKit.framework", + "system:OpenGL.framework", + } } else { foreign import glfw "system:glfw" } From 9746e25784c208cf8a7883bcb2e1ac2317117aeb Mon Sep 17 00:00:00 2001 From: pvance Date: Thu, 28 Jul 2022 04:27:42 -0400 Subject: [PATCH 12/12] Update stb_image_resize.odin --- vendor/stb/image/stb_image_resize.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index be1f8dbd6..5763e142a 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -2,9 +2,9 @@ package stb_image import c "core:c/libc" -when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_write.lib" } -when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_write.a" } -when ODIN_OS == .Darwin { foreign import lib "../lib/stb_image_write.a" } +when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" } +when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_resize.a" } +when ODIN_OS == .Darwin { foreign import lib "../lib/stb_image_resize.a" } ////////////////////////////////////////////////////////////////////////////// //