From 2900f23394e35089aca94dbd1de195c7666365df Mon Sep 17 00:00:00 2001 From: Lino Le Van <11367844+lino-levan@users.noreply.github.com> Date: Thu, 18 Jan 2024 19:07:38 -0800 Subject: [PATCH] feat: add raw --- .github/logo.png | Bin 0 -> 10523 bytes README.md | 2 + crates/ast/src/lib.rs | 1 + crates/ast/src/parse_expression.rs | 54 +++----- crates/ast/src/parse_function_call.rs | 56 ++++++++ crates/ast/src/parse_statement.rs | 59 ++++----- crates/ast/src/parse_type.rs | 1 + crates/ast/src/types.rs | 13 +- crates/js_ast/src/lib.rs | 150 +++++++--------------- crates/js_ast/src/types.rs | 3 +- crates/js_printer/src/print_expression.rs | 13 +- crates/tokenizer/src/lib.rs | 11 +- examples/basics/control.blight | 2 + examples/basics/expressions.blight | 1 + examples/basics/fib.blight | 1 + examples/basics/functions.blight | 3 +- examples/basics/operations.blight | 3 + examples/basics/shadowing.blight | 2 + examples/basics/variables.blight | 3 + examples/basics/weird.blight | 1 + examples/interop/blight_in_js/main.js | 2 +- 21 files changed, 192 insertions(+), 189 deletions(-) create mode 100644 .github/logo.png create mode 100644 crates/ast/src/parse_function_call.rs diff --git a/.github/logo.png b/.github/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..46e7e472cc5655f578d3cd2e873d230107999375 GIT binary patch literal 10523 zcmeHt`9IWM`1cu0b}B_E%32YH$TBF|ml0*jGD@~=WjD5ImAizIok4O-i7eT&Rm4~Z zqwH(OI`$#P`W*N7dH#s!_4@uWug~Xmmg}5zopW99_qnc#G%?oUVC8280C4E(UN;4R z4!+U>=0otY7WiumJ{X*@8eIjTD4K2O4kG}pdajz9CO)P**G}tcX)0V&Qc$=cD}4z7 z-N^`95FU*590vM4l^`y~{!w6L(fpj2IVv7I_4Ync zGJU41+$R)`(rqBrVCjzQjxn4*Jk|Q$nXwUoW%{7NFyGJWJBUIrxQGY8rA3c6jqg9H zG7+}`r(?mG@X={DM2snDmcH413^bnrpUq0{v4S@MxCez?69ykR!2Ft?8YAe-iyPtv zeQ!_ZF@q=sNIt70N~iG^*x!0&Dn(cS9c1Qf2um~67a*`!WwJVS*cwLQ|JpK!OT!*u zldnm&fzwy$fTkdKJN;=x`pk=@y0JX;gJ%`G2vFY|-=1hdk~>xr-^m}ax;*yh%%AV> zMc3}|o;&QsLKaR-OcmkQou)S=vID?R>-x5LMLlMEiab8$H0{2$*7$bMZP`m$?aa#P zUiB+F25{K8V`%_AIoU)1pb7EWug)#c8Vr~Nmr}?hRs=!NU}d_~RPT0JE z!)y4H8G!4VkIsL-%EbQdSbjZc+P72H^}KX<4qew^7p+%4eC-e!dy+NlM8Z|RoAt_l z3|~Ie^JgAO89!Y5?a~#F>9M0Wk0=j#580o*6mJL}JU{=5`s(`1yj+e_lIayDo7$z3RVX z^D08iKGKq3yotwQ((2D%q7Lms-@0TLhp30-y z`tCyZ@6HrgXV(oEnOWZ|mfE1od=f)SzmwTd| zPbS&$U&ijlZ|9d{xc5+*1D?^nvZ> z$6H(Qn<|z~qO#@7$O*(F%vun}2kGC8+il0Bz&U~($ zebb@*CtuVVo}aRgE0))Kyv^w;Qf^5`cdd(Q^M?M6+XDVF!G>m=@ZWoIf%g*=r5>WDC)WY$>~$rC&dBGK<&WY1@8r(1IKb9(msvA|$ss{Z!=G3|!C_%F<>n-b?v%_6F>mF;_>%4PIJxg6eiWlXX6=L|@ zFI{n1Zi{i4aZ7To=vsa{{{Bd-OI2)xOLmuDwnT;aVubU=XlNEB4ppZ^x;&lSfbWsQ9Xcc>DUb`MW=; zro0=M|B=^__hZ(=S-?5VC!Knk_g{mU)}x93iM(bWx&P#PW?)+5C;1nvNME|wvs1sO z4t?tP_%+;yYz+OlZ6uv4K(PIRT)MipykYt0VcSG{Zffp#YRt5Zoxh!x-FA&2sw7Pu z-*eHUd9cBHtfn>CURe$4xJ8_$SNo|(mx0NMsQtHAcobPH64n!z9LBVR-&Wab-HqO? z8xLCLSutj`M|?v}B5EG-KPsVjqZeXGX2@Z>%oxS^^^gp^+VN}bEF4xs-f>>_ysH8< z2e~0^buKc?a|8;V`d%X@;|HWy~+eblhK52)Xhl^U^|( zojWi4L3-{+shRIX-wmmre6rQHbIt3O=)6~zDuegSy#1Z?@4K72JItq6U@JaUJPM51 z)LKbA>dP(4vJgpb=xabmPWaGGyQj#dkyCCa_&O9!4!y19oth=K;saEzE?dQfTzQss zG_hEH^2zCICNd{blewNor?^+2ranVy)xM2-d!wklLSGd(m2MvY_sXzJsOFZ-bCkB< zPdOHpsbo+rAFfh_YGi)BXC%L)|6%_Hr8jAB(y~oCToXzqdoPxsEk`*?O2%=JgQh%M z1mYrEHpn70AL`(7_h*J(*`=lhCY(HmGVdh=txs47R_NB~-u@*w>a;gU6JdMI6H*iN z*`(rgNnb^v)ykM~oz_<#k(Xw?0n(RjO{?w&x-OGKTU}a<6LwAhSeo8iy&p8R`r7mf zDJMr$^09?{eBK*Et7pO5?MjE^cjE8eTDqV3+uA(*Ja0TY|3Uuyg3Zs`6;ppKjM2YC z)`L6-21fMDTNWs~ly?-*{0*zRLj9WiSATatU*`BEuo5*XfcDTI@y){AUw_?R+TPMm zfBDYk1?#r5{K3^Mh3vnW^l;l&^W9G$%WM0^2YTv;1A?iXPfi_I8CiNWU;RZg(88@o zD|FqHwD@>9n*XjqRoztBaD`3)su3R@oDFaJWeM zW@+YCcKRv1Q#!Tf`(aC$CLH{lE=OD7Gtd0ToLqQvcJIQXg zH*9O1H9PR?yuOQu<>(Cpb!0l)cDee&n()TmL9ud!PsjqKPS}Ipaos{|FN)(v>w<-9 zf$y3TMWt)0JACVY{coS%&0cBSjG&sOpYsCcp5ntNE5xeSH~s%E@CL9h8V=cFq5}(e zY6o`bn6|j)!b|sx9P2&CHtp-}JAPPkEpf6$;P>9_cSnqqblP-&i)f2PMW+i132^Y& ztllHWjpr8Ua(A?ZnePWtd_GQ(?*7>}=&;=BTV|uZ?5HaU%AvrVs#vNTZK@GUKD(o_XF~1Ta%jr!L~W=|hwSahY&@lIU(mVI0ZHa*2VGMm z05IYJV4nhTz&o)s0Qg-5V9p)@yfZZzvqY()6>?EqR-Ul z#n~8mpC?3$>fq*4tJ*kToN6jLFz=yU*IDEkkH0w07Z+ViEy|fc2{sW+dt;Ttgx7;R z>GXQFE5xQm+`PxP0zS7y(3egw(F;4@4z*)kKA9d}w@qBy5U1V6$%qD3{(2vs?*8p4c~;YTOnuL9mWP-1-X|z z*0JV?>XEKJ#Fu(uX9)Iebqb&~`MPt%T-X)`t5PVXJx`PDdZNpqjbiNPD5hW zi0Zn+OHy?z@NDF@kwWT)NfX@k_HGPJGe&^U0)AIPIkdql)m6}dxA87xeUE5(ELmO5 zs#X_G52}8zie{jwmQ{Y2YU}SZ)H}z8C=w)i#>)_y;u*Tsq^B`RFffceCj1Lve*Uv=Bz{c{xn2-C^PRvx=f;%vhu=zH_XIvEl+4 z`zvU$`bj>zhAKM>HXq>XUQyTSH9orQQTw*XX+zB+bYl~Gd-CmUX8`zABHZq<+%%1$ z_u;^DiP3&ku*-lqvN$rAY?IkshZqnvq!vHt+yf>(E-6i9Cg*J~X8|A(w^JwTP_las z)W1Ce=T_~iu}D6sC{nH2&q;Tf&$(x-iM!HnK&#>CJb=scGoMw6-hk@Ixv7*J0n z$FY531}>2(GAC-d&I07?uez~S9s(}OXalNcn8DI1tVUXz;c7gS_7nBL_U46XE6gDeU7*2~l$O*+Zn#%qQ?-Q;FYM|~ zExILQRd(O%r#Y9i@4Ab&b_7X;4V%ggW`w!p%#?!WZHxs~0(O0Nccb!c>QvnnKQ(`d zk}URhasBp8sAB(B6U**c~ zmad7~A7KV#2~cIp*%8K0RN{K&M(n3qp%Z73ES4HX2IlJA^1p(F#PFralS9E*x|5}m zOqQqVKt(nolAyZXZb5BGtW7nTNYw8@@L&OOns4YTp$+T@osZx;DT8E8l0bmAmWD3` z)!lerDrut7@w{2iH1H7xSf&1rmMm3Tj9f}D)4C)`N1WetqI=FS`&Z^2f}41 z9|9LP*f4p8n&^FRvN~QFFrC1J_i2bhVW&ps)*-~K*4^$;b&_N?fW+pcP0k* zs&t4jcHSXPlH@Y)(}A;pX6$4RJ;gBqlZJ1KuM_a#mfIUauwbv3Ei>yDEr`dbz?mpLvFhD&z&jNH;m!pR=ep4(G@GGI>|B8D%?%bEQt-!HKNR!DcB}!p4 zzW<8n>Z7bLHgV!x%C;H6o6{iE=rTsY^_9G=s_Yxs^`4u8vo}Uof-8gYD3NQj@0(eU z1aXk?B)4RtwmrvLBc1{H#?<0#^M@|vrIuR?$TL=aHJ_0(Q@z;d*Z`J=xl5?6b)&ZH5aNT)PD!mE#iw+ir zHj+rh2T0%zI5^qwtyd8Pt;fE691dR*aZ#iLRedS#9}Q4Ru>{tFFy;kqpusC(-OcCB zls~@O)aeNY6^$3=c1;#o07&-mB#<`%CQgY3rhV zmIHg!^e$2lmF!(E!-fTgU3&r4S~Udt)U!9rhYgz5+g7h0IkEhS`F48^XVp-{_3gUv zVfHSWYYhJ_O(A{Orgms=x?kuR==46A-DInU+~xkg#DP;Mct9sSaaDbrvoCWbhHiw1 zix@C5g3=VI692j7eiHYh3vG^g#rlk|033V1^AR^}*3~!Xm?QDuNyw9v=$QOdxk8d# zbeVikthoC>4e#$$nG8@B+1hBYgn(wTmsx|*ybNNs=w^6nnmi2_ z^i9q)oTPbG-^ToWl|Nck2B)0>hcDU4+g0+J3z_8$_+?3I9)KF{z}{zpUfQcB>`E{? z@Z;JmzW!1N+bv88+hbGy945dvF*foeXfZW?r86Ao9%}CZbqiH?%JY18(1ObL>J~M9 zB`%z_GaK#__#SRNTqURf-hm%(@AaMw+|F28vaLZP`&T-rpd~`XRPLNKNGw_EFE3t- z*UZUn8~D4e=osi*0sG=%-%Ig%X=)+jOlXyqA6|kTzu;!-l_*^4%kWqlHN_k{i~t^P zcmLcbW>mhR<`SoWjh86x{mrvUO_D;o*$M8RPVzU4 zsBdX(VYc*92+z~d>2>$cv^r#9F48}tKX7s@$H3>a3G!R3eYrv{GfCw;S5=Ne*GXCO zB5P&@p|umE-{9$noj9Eh5-rIfh0zvtb&ng~U41-dQ8R)5*h5e2&T%+D z2WOOBbAKG~>Ys9SN7Ywzr`E+NE5F{BHRWv~-;)ps30>u=$(g}iS;$0A1uHmC6s*I| zv}W~XEnGxQO|EXnS1&L0QYZIUK2`6{KQc6g4ud5L0rBfaq+49jWO69&XXTz_2`TD*30OaX$?*`G3YMDFmt5d7XMwK8NuR<7smS&<+akd1Igq2=Xpj2iRY}HaOS~|4hcs$*$15mQ9^u7?i-xc699}~c$aSnpfUGMwnN1>DVo*#=OnPuw3 zA}8p*M`^1sg#qhfpm76w(x5F#naN*8ayhvgw;*f{k$>I9?@*_GR(2X;AAUFiwu80( z%BUH;d#zI#ehcst(JdwD@GsDo9s@AYazLoYewRZdFX%ms1Owl))mJslJ#FkTKe-@< zYx(u-rnoeUOxldMsSFfLB-#>_xu?CS8fb=w{?lRs=&(Og`L%9Z&!0!=qaGEAfzx_k z*@{skf4{28Z;jF#?PaS%$lH7F%H5R@{8c45(_6ZBC4A;K`+K--L?Q1B8W$*>ED{Qa zu+{lxU`a*rq6l)9Fw^${lClHjtMsPnbJqCFZ`&!oX`M(9rwvc&5XsAX+5MmWY+;}H z>O-Kap?*xG3|S$Tv1u*T@fslC#p;mgK zfmm(y^hmo*G#Y{}Cu9b;c|LV=U@1?rrgD44h}MTvP5Djvso#-YQqys&`GE59b^1X7 zsm#%YA&uP8#B?stb4W+y0^7=jCxwFNkn~j$&REypNo=TAUs&3nK|;4h*y9}`-u(AK zwZb4%IAEbKW+Qxl1R|Tq&Y#J&D}lvp>@(*fDJ^+8xHV5(Cc>J9`j2+(%xro<<5}5| zkA;HQQvOD-kV@eB#6sUa8b_urGkE_iRJ~L(+acZW!|()?DhFWG0vb67u-Sb_hE=s{ z|N1OT=Vi!--5ckMhQ5S)%<{?k@67NyA9@OHFw^_1AiVT{e`SO+nrV!V-yU;cnYRN14B`|#;Ci^r*5(IrJ(0@@+7bc4iHfvFK)3kHi)Gr_RtkwwwsRgD ze5BQziqF3d+4av?Hnk5b*BE93Auaaw{jEF8BIiB(7GP=6srYGT!@X>4&Uq=#%0LwZ zSW1GwE_fA-M0{5V$CT_ z->6z5E#V?^K@TKF6D!NHvE+2Jm3GfqWB+=)G!|b?Trq;bS`0>`N}N5Bsk& z-VIK`5`{)Vy>`KpbnbZ#Er%{9u?C$E%M@DiYg`f&>#zbnxuSnc&IS_B3Q5jgZ_N4L0=w49mli&=-*arPT*jL< z5vQPKC8y2hchiVH3Bv*g(11k1X+n4S%3V?~KDTiu8Nb+)G3Wdt{Ifcx46_+tFhJY) zSG-*k7BsSNu_%Ld&}IOll?s=V4Sh$FSMGma*n=pZ=IArE@9$=0M@iF}82X4U``tU! zJ{8=1;K1|%WIcnSsieAhb6Ba{VK4$FQIl=-m7uY$t zoT&6+TM>=$B3V|l{baDacVduRN_^vD=BNC@>hl!E;8Arc1q3LKs?|m>?l%`e(_%e9 z5U#L$773i3Z}5m)&;?lcm3nw6c=`~~F2@nzn4)Zz{Kjrf#9mfB1f-kjY#E`=kHN+7 zI&$u5r`! zM;3qjk2HeYbBneD-upWKITFylYW%LA=W$8)*zjmsY${XP)D(cTF&NsIdF}pn)Mu|# z`T(gh+ZgJeP^}_m$<7+X`rzOqo066FC}d1$<6i%2EaX5i0AYV4f3);`u$n(=D{(Cm zvM~sZJU8J*W-;77xNPVv!C*Ht3SOnZ!B{{7Q&^yd_QAyuu?PbO)E>z87In&;TWbWW z8@ZHWl4i>BAOP#%}2S6n^MnR$vMnjMm&uf=zo zQrJ1!-{9$`(n_L4C2;N+R2f{jVeG_xs7iqnklzli%C4Jhcs5XkkVTTj7C(nJu{(9k zswBwKJYT?|Q1Y2(xyq1kap4+k=9fbehl-tcSMx2^6XGdNvhuPwF-JRZZ}aPooUNg= zRE2QLXRCxO`kf6QX|czD@ZDCn#PFE(P@+U-66_FdMBF2>SqjDI;2yJ;cuy}J4JFE6 zl#kgP7vtmSZyuYmPk7Caxgt~%pNI+b+v@EVRWir0fKFLTaNJ3h_vf{v@Pf}NuC%r2 z@B}SW2?N&2g%Xi4npPDe0%O}d55JuO8kC(It2H2SH=PS)2HUESjBf5_j>?q4sCw*Z z@CGl8oAa`e4&-B8G%A#cD55n%^G0?5I zcNOQuCeI8kZKg@8{;0ZMbd?zpCG3gTm4YWwGJ^(5^+~5!yE6w2r-Vro zygJA-M0tRl$_AtO?t_IOldV+ms;7bq9N9};>B^uMjKe4=ktIl~<{i!MbYsIZ%M*G; z;wlXAznpMSX_~Uy#i|VgUEDM-M4a$UX~!DakK4d})XtFm{ zc1ACc!io-+kShdkwg=XregPRv7D@i$v!`hN0*?H{wdX|~BclG#Cd^%ZiQxJ3ljl6t zr#CJGwYu?V00BOm5XETy^3g?!ymQ*TvS4KWnJAY8ZBBSd0sJC=bQLsn_Qj0$TfTzA z6mcQ41eu1f48XpO_%4Wj_g+fVFUE39M2x(Q<|a+_D{e;{7pb*#8+3Ar!%W_yKJ~;F zK5;EQx{)0lkgiMp!w`(yF~;TbgcyMtQ8T^0;FP8ov_7@3^8M{2Up@5-(bpbk6`6oDvMZ&)EYNIGBAsr{L&lT7dw-mBNm8T!;)>BI%JLoAK zA7TVP>;5UzbNkvjnH)agk!?#irX4&=+Zws`xhd>-o^C7d%H^!Q?W~(=xtZaLxYl{{bch B7_R^T literal 0 HcmV?d00001 diff --git a/README.md b/README.md index a8c86bb587ee9cc3e6675df01bc6b647fa07b107..e95f7dda52704002c53d136983f133003890a02a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![Blight Logo](/.github/logo.png) + # Blight Blight sure is a programming language. diff --git a/crates/ast/src/lib.rs b/crates/ast/src/lib.rs index 8ba4651df3847987415e038f685d975ab26229b0..c4841db4e84a9184793e9563f94d5e15b3dbaa66 100644 --- a/crates/ast/src/lib.rs +++ b/crates/ast/src/lib.rs @@ -3,6 +3,7 @@ use miette::Result; mod error; mod parse_block; mod parse_expression; +mod parse_function_call; mod parse_statement; mod parse_type; mod types; diff --git a/crates/ast/src/parse_expression.rs b/crates/ast/src/parse_expression.rs index 1b4467820c608c13daa9a062466b0e487fcf1e75..f71c1cd26b5070d3577eb7bcd607b2f5e4417005 100644 --- a/crates/ast/src/parse_expression.rs +++ b/crates/ast/src/parse_expression.rs @@ -4,6 +4,7 @@ use tokenizer::Token; use super::error::AstError; use super::parse_block::parse_block; +use super::parse_function_call::parse_function_call; use super::types::{Ast, Block, ParserContext}; pub fn parse_expression(tokens: &mut ParserContext) -> Result { @@ -11,6 +12,16 @@ pub fn parse_expression(tokens: &mut ParserContext) -> Result { Some(token) => match token { Token::Number(number) => Ast::Number(number), Token::String(string) => Ast::String(string.clone()), + Token::BuiltIn(name) => { + match tokens.peek() { + Some(Token::OpenParanthesis) => { + // FRICK we consumed the open paranthesis + tokens.back(); + parse_function_call(tokens)? + } + _ => Ast::BuiltIn(name.clone()), + } + } Token::True => Ast::Bool(true), Token::False => Ast::Bool(false), Token::OpenBracket => { @@ -57,43 +68,16 @@ pub fn parse_expression(tokens: &mut ParserContext) -> Result { else_value, }); } - Token::Identifier(name) => match tokens.peek() { - Some(Token::OpenParanthesis) => { - tokens.next(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - - Ast::FunctionCall { - name: name.clone(), - arguments, + Token::Identifier(name) => { + match tokens.peek() { + Some(Token::OpenParanthesis) => { + // FRICK we consumed the open paranthesis + tokens.back(); + parse_function_call(tokens)? } + _ => Ast::Identifier(name.clone()), } - _ => Ast::Identifier(name.clone()), - }, + } _ => { println!("token: {:?}", token); return Err(AstError::new("Expected expression, but did not get it").into()); diff --git a/crates/ast/src/parse_function_call.rs b/crates/ast/src/parse_function_call.rs new file mode 100644 index 0000000000000000000000000000000000000000..57c177d8c77fb7e7aeb1b1d7cbd502c7651ca133 --- /dev/null +++ b/crates/ast/src/parse_function_call.rs @@ -0,0 +1,56 @@ +use miette::Result; + +use tokenizer::Token; + +use super::error::AstError; +use super::parse_expression::parse_expression; +use super::types::{Ast, ParserContext}; + +/// Parses a function call AS AN EXPRESSION +/// This does not consume the semicolon at the end of the function call +/// if it is a statement. +pub fn parse_function_call(tokens: &mut ParserContext) -> Result { + let identifier = match tokens.next() { + Some(Token::Identifier(identifier)) => Ast::Identifier(identifier), + Some(Token::BuiltIn(identifier)) => Ast::BuiltIn(identifier), + _ => return Err(AstError::new("Expected identifier").into()), + }; + + match tokens.peek() { + Some(Token::OpenParanthesis) => { + tokens.next(); + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + arguments.push(parse_expression(tokens)?); + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + Some(Token::ClosedParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected ) or , but found something else instead.", + ) + .into()) + } + } + } + + Ok(Ast::FunctionCall { + name: Box::new(identifier), + arguments, + }) + } + _ => Err(AstError::new("Unexpected identifier").into()), + } +} diff --git a/crates/ast/src/parse_statement.rs b/crates/ast/src/parse_statement.rs index 8cd4b63e89df1f9b19a88a30920aaac7aecba055..343aceff9eea0e9fc29c57e25fab2387e39f8b32 100644 --- a/crates/ast/src/parse_statement.rs +++ b/crates/ast/src/parse_statement.rs @@ -5,6 +5,7 @@ use tokenizer::Token; use super::error::AstError; use super::parse_block::parse_block; use super::parse_expression::parse_expression; +use super::parse_function_call::parse_function_call; use super::parse_type::parse_type; use super::types::{Argument, Ast, Block, ParserContext}; @@ -12,6 +13,16 @@ use super::types::{Argument, Ast, Block, ParserContext}; pub fn parse_statement(tokens: &mut ParserContext) -> Result { let token = tokens.next().unwrap(); match token { + Token::BuiltIn(name) => { + match tokens.peek() { + Some(Token::OpenParanthesis) => { + // Okay, so we messed up. We shouldn't have consumed that token. + tokens.back(); + parse_function_call(tokens) + } + _ => Ok(Ast::BuiltIn(name)), + } + } Token::OpenBracket => { // FRICK, we have to backtrack tokens.back(); @@ -44,7 +55,7 @@ pub fn parse_statement(tokens: &mut ParserContext) -> Result { Some(Token::Semicolon) => (), _ => { return Err( - AstError::new("Expected semicolon after variable declaration").into(), + AstError::new("Expected semicolon after constant declaration").into(), ) } }; @@ -213,45 +224,21 @@ pub fn parse_statement(tokens: &mut ParserContext) -> Result { else_value, }); } - Token::Identifier(name) => match tokens.peek() { + Token::Identifier(_) => match tokens.peek() { Some(Token::OpenParanthesis) => { - tokens.next(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - + // We need to give the identifier back to the parser + tokens.back(); + let result = parse_function_call(tokens); match tokens.next() { Some(Token::Semicolon) => (), - _ => return Err(AstError::new("Expected semicolon after function call").into()), + _ => { + return Err(AstError::new( + "Expected semicolon after function call statement", + ) + .into()) + } }; - - Ok(Ast::FunctionCall { - name: name.clone(), - arguments, - }) + result } _ => Err(AstError::new("Unexpected identifier").into()), }, diff --git a/crates/ast/src/parse_type.rs b/crates/ast/src/parse_type.rs index 9b061cdcc6f8483921a1067e99f81d91252ffb88..6837edec59b4d8f649ccc28c65f33362ef948c49 100644 --- a/crates/ast/src/parse_type.rs +++ b/crates/ast/src/parse_type.rs @@ -13,6 +13,7 @@ pub fn parse_type(tokens: &mut ParserContext) -> Result { "bigint" => Ok(Type::Bigint), "bool" => Ok(Type::Bool), "string" => Ok(Type::String), + "any" => Ok(Type::Any), _ => return Err(AstError::new("Expected type").into()), }, _ => return Err(AstError::new("Expected type").into()), diff --git a/crates/ast/src/types.rs b/crates/ast/src/types.rs index 9551f067516b0faf8c8333e6aa61bf56ca379ed4..3500088aa85499be1b8eb25c25ed7749ff58c598 100644 --- a/crates/ast/src/types.rs +++ b/crates/ast/src/types.rs @@ -41,28 +41,29 @@ impl ParserContext { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Type { Int, Float, Bigint, Bool, String, + Any, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Block { pub value: Vec, pub implicit_return: bool, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Argument { pub name: String, pub return_type: Type, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Ast { ConstantDeclaration { name: String, @@ -86,7 +87,8 @@ pub enum Ast { block: Block, }, FunctionCall { - name: String, + /// Identifier or BuiltIn + name: Box, arguments: Vec, }, If { @@ -101,6 +103,7 @@ pub enum Ast { Bool(bool), String(String), Identifier(String), + BuiltIn(String), Comment(String), DocComment(String), } diff --git a/crates/js_ast/src/lib.rs b/crates/js_ast/src/lib.rs index 56e87fae25b384bb4d4ced8aadd487ff87013804..f0f738cde7b062470fb261f949c656f770af9b8a 100644 --- a/crates/js_ast/src/lib.rs +++ b/crates/js_ast/src/lib.rs @@ -109,10 +109,27 @@ fn get_expression_handle(ast: &Ast, ctx: &mut TranslateContext) -> JsExpression for argument in arguments { handles.push(get_expression_handle(argument, ctx)); } - ctx.push_internal_variable(JsExpression::FunctionCall { - name: ctx.get_identifier(name.clone()), - arguments: handles, - }) + match *name.clone() { + Ast::Identifier(name) => ctx.push_internal_variable(JsExpression::FunctionCall { + name: Box::new(JsExpression::Identifier(ctx.get_identifier(name.clone()))), + arguments: handles, + }), + Ast::BuiltIn(name) => match name.as_str() { + "@raw" => { + if handles.len() != 1 { + panic!("@raw expects exactly one argument"); + } + match handles.get(0).unwrap() { + JsExpression::String(value) => { + return JsExpression::Raw(value.clone()); + } + _ => panic!("@raw expects a string argument"), + } + } + _ => panic!("Unknown built-in function {}", name), + }, + _ => panic!("Function name must be an identifier"), + } } Ast::Operation { operator, @@ -286,13 +303,32 @@ fn translate_statement(ast: &Ast, ctx: &mut TranslateContext) { for argument in arguments { handles.push(get_expression_handle(argument, ctx)); } - ctx.push(JsStatement::Expression(JsExpression::FunctionCall { - name: match name.as_str() { - "print" => "console.log".to_string(), - _ => name.clone(), + match *name.clone() { + Ast::Identifier(name) => { + ctx.push(JsStatement::Expression(JsExpression::FunctionCall { + name: Box::new(JsExpression::Identifier(ctx.get_identifier(name.clone()))), + arguments: handles, + })); + } + Ast::BuiltIn(name) => match name.as_str() { + "@raw" => { + if handles.len() != 1 { + panic!("@raw expects exactly one argument"); + } + match handles.get(0).unwrap() { + JsExpression::String(value) => { + ctx.push(JsStatement::Expression(JsExpression::FunctionCall { + name: Box::new(JsExpression::Raw(value.clone())), + arguments: handles, + })); + } + _ => panic!("@raw expects a string argument"), + } + } + _ => panic!("Unknown built-in function {}", name), }, - arguments: handles, - })); + _ => panic!("Function name must be an identifier"), + } } Ast::Comment(_) | Ast::DocComment(_) => {} _ => { @@ -310,97 +346,3 @@ pub fn translate(_ast: Vec) -> Result> { Ok(ctx.pop_context()) } - -#[cfg(test)] -mod tests { - use crate::translate; - use crate::{JsExpression, JsStatement}; - use ast::{Ast, Type}; - use util::Operator; - - #[test] - fn test_translate() { - let ast = Ast::ConstantDeclaration { - name: "hi".to_string(), - return_type: Type::Int, - value: Box::new(Ast::Operation { - operator: Operator::Add, - left: Box::new(Ast::Operation { - operator: Operator::Add, - left: Box::new(Ast::Number(1.0)), - right: Box::new(Ast::Operation { - operator: Operator::Add, - left: Box::new(Ast::Number(2.0)), - right: Box::new(Ast::Number(3.0)), - }), - }), - right: Box::new(Ast::Operation { - operator: Operator::Add, - left: Box::new(Ast::Number(4.0)), - right: Box::new(Ast::Number(5.0)), - }), - }), - }; - assert_eq!( - translate(vec![ast]).unwrap(), - vec![ - JsStatement::ConstantDeclaration { - name: "$0".to_string(), - value: JsExpression::Number(1.0) - }, - JsStatement::ConstantDeclaration { - name: "$1".to_string(), - value: JsExpression::Number(2.0) - }, - JsStatement::ConstantDeclaration { - name: "$2".to_string(), - value: JsExpression::Number(3.0) - }, - JsStatement::ConstantDeclaration { - name: "$3".to_string(), - value: JsExpression::Operation { - operator: Operator::Add, - left: Box::new(JsExpression::Identifier("$1".to_string())), - right: Box::new(JsExpression::Identifier("$2".to_string())) - } - }, - JsStatement::ConstantDeclaration { - name: "$4".to_string(), - value: JsExpression::Operation { - operator: Operator::Add, - left: Box::new(JsExpression::Identifier("$0".to_string())), - right: Box::new(JsExpression::Identifier("$3".to_string())) - } - }, - JsStatement::ConstantDeclaration { - name: "$5".to_string(), - value: JsExpression::Number(4.0) - }, - JsStatement::ConstantDeclaration { - name: "$6".to_string(), - value: JsExpression::Number(5.0) - }, - JsStatement::ConstantDeclaration { - name: "$7".to_string(), - value: JsExpression::Operation { - operator: Operator::Add, - left: Box::new(JsExpression::Identifier("$5".to_string())), - right: Box::new(JsExpression::Identifier("$6".to_string())) - } - }, - JsStatement::ConstantDeclaration { - name: "$8".to_string(), - value: JsExpression::Operation { - operator: Operator::Add, - left: Box::new(JsExpression::Identifier("$4".to_string())), - right: Box::new(JsExpression::Identifier("$7".to_string())) - } - }, - JsStatement::ConstantDeclaration { - name: "hi".to_string(), - value: JsExpression::Identifier("$8".to_string()) - } - ] - ) - } -} diff --git a/crates/js_ast/src/types.rs b/crates/js_ast/src/types.rs index 022641d491214b181b64f9af75bb54ae247661b3..18a2788da595867d00cc1249f0cbd40f5487f3d0 100644 --- a/crates/js_ast/src/types.rs +++ b/crates/js_ast/src/types.rs @@ -10,6 +10,7 @@ pub enum JsExpression { String(String), Bool(bool), Identifier(String), + Raw(String), Array(Vec), Object(HashMap), Operation { @@ -22,7 +23,7 @@ pub enum JsExpression { value: Vec, }, FunctionCall { - name: String, + name: Box, arguments: Vec, }, } diff --git a/crates/js_printer/src/print_expression.rs b/crates/js_printer/src/print_expression.rs index be771126970a835788f3a7f92e65e83e4f84143b..ff87066c667b0ed8496173cb4fbe09422702e859 100644 --- a/crates/js_printer/src/print_expression.rs +++ b/crates/js_printer/src/print_expression.rs @@ -4,6 +4,7 @@ use crate::print_statement::print_statement; pub fn print_expression(statement: &JsExpression) -> String { match statement { + JsExpression::Raw(value) => format!("{}", value), JsExpression::Number(value) => format!("{}", value), JsExpression::BigInt(value) => format!("{}n", value), JsExpression::String(value) => { @@ -61,7 +62,11 @@ pub fn print_expression(statement: &JsExpression) -> String { ), JsExpression::FunctionCall { name, arguments } => format!( "{}({})", - name, + match *name.clone() { + JsExpression::Identifier(value) => value.clone(), + JsExpression::Raw(value) => value.clone(), + _ => panic!("Function call name must be an identifier"), + }, arguments .iter() .map(|x| print_expression(x)) @@ -238,21 +243,21 @@ mod tests { fn function_call() { assert_eq!( print_expression(&JsExpression::FunctionCall { - name: "hello".to_string(), + name: Box::new(JsExpression::Identifier("hello".to_string())), arguments: vec![], }), "hello()" ); assert_eq!( print_expression(&JsExpression::FunctionCall { - name: "hello".to_string(), + name: Box::new(JsExpression::Identifier("hello".to_string())), arguments: vec![JsExpression::Number(1.0)], }), "hello(1)" ); assert_eq!( print_expression(&JsExpression::FunctionCall { - name: "hello".to_string(), + name: Box::new(JsExpression::Identifier("hello".to_string())), arguments: vec![JsExpression::Number(1.0), JsExpression::Number(2.0)], }), "hello(1,2)" diff --git a/crates/tokenizer/src/lib.rs b/crates/tokenizer/src/lib.rs index 5dc2c9f62e6a9beb435edeb98dfe5d911f7eddfd..7e2ae39951da2165efdf34c6e38391072362aaab 100644 --- a/crates/tokenizer/src/lib.rs +++ b/crates/tokenizer/src/lib.rs @@ -16,6 +16,7 @@ pub enum Token { Identifier(String), Number(f64), String(String), + BuiltIn(String), // Comments Comment(String), DocComment(String), @@ -49,7 +50,7 @@ pub fn tokenize(content: String) -> Result> { loop { match chars.next() { Some((_, c)) => match c { - 'a'..='z' | 'A'..='Z' | '_' => { + 'a'..='z' | 'A'..='Z' | '_' | '@' => { let mut current_token = String::new(); current_token.push(c); loop { @@ -77,7 +78,13 @@ pub fn tokenize(content: String) -> Result> { "return" => tokens.push(Token::Return), "true" => tokens.push(Token::True), "false" => tokens.push(Token::False), - _ => tokens.push(Token::Identifier(current_token)), + _ => { + if current_token.starts_with('@') { + tokens.push(Token::BuiltIn(current_token)); + } else { + tokens.push(Token::Identifier(current_token)) + } + } } } '"' => { diff --git a/examples/basics/control.blight b/examples/basics/control.blight index a6d7f06cd84c9b6e611d6cf9e42e988093f765e3..1428905a5fddb419fb987256783c401c956355d2 100644 --- a/examples/basics/control.blight +++ b/examples/basics/control.blight @@ -1,3 +1,5 @@ +let print: any = @raw("console.log"); + let x: bool = true; if x { diff --git a/examples/basics/expressions.blight b/examples/basics/expressions.blight index 553407cb046bdb2f0bcbe3bfc9a7db0b83366594..fbc8e4c4c024dff1abf958045fd7d5a3c189bd7c 100644 --- a/examples/basics/expressions.blight +++ b/examples/basics/expressions.blight @@ -7,4 +7,5 @@ let x: int = 5 + { y }; +let print: any = @raw("console.log"); print(x); // 10 diff --git a/examples/basics/fib.blight b/examples/basics/fib.blight index 95762dfe0f74f8409b8371ff4a3d6c4e92d625a1..898f001d4f163a3b4142a38a64a86fd2393b9181 100644 --- a/examples/basics/fib.blight +++ b/examples/basics/fib.blight @@ -8,4 +8,5 @@ pub fn fib(n: int) -> int { } } +let print: any = @raw("console.log"); print(fib(10)); diff --git a/examples/basics/functions.blight b/examples/basics/functions.blight index dc14aaef31aa61086b22d34a0946cf4c253e4e23..58cd31caa9d8c9c49aadd8609bc9ccc62bc36eb2 100644 --- a/examples/basics/functions.blight +++ b/examples/basics/functions.blight @@ -4,4 +4,5 @@ fn bingus(x: int, y: int) -> int { let result: int = bingus(10, 25); -print(result); // built-in function +let print: any = @raw("console.log"); +print(result); diff --git a/examples/basics/operations.blight b/examples/basics/operations.blight index f35a323df01bec88a06c2e9198ab22283c5be8a0..85ee1283b38b61b6840f20d8dd6f8c206d8cf7c9 100644 --- a/examples/basics/operations.blight +++ b/examples/basics/operations.blight @@ -1 +1,4 @@ let a: int = 10 - 2 / 4 * 15; + +let print: any = @raw("console.log"); +print(a); diff --git a/examples/basics/shadowing.blight b/examples/basics/shadowing.blight index 7e2b4c6228d78014922200d4b84b41bc477b1b7d..2a8514581e8a102a5f67b44c22f825aca3fd9252 100644 --- a/examples/basics/shadowing.blight +++ b/examples/basics/shadowing.blight @@ -1,3 +1,5 @@ +let print: any = @raw("console.log"); + let x: int = 0; let x: int = 1; print(x); // 1 diff --git a/examples/basics/variables.blight b/examples/basics/variables.blight index 3fd14633a137273fc6ee0ff72f516c67114dbeac..3bfe757ddba318fa7e40620b6a4bbbd6c3f2cf45 100644 --- a/examples/basics/variables.blight +++ b/examples/basics/variables.blight @@ -5,3 +5,6 @@ var z: bigint = 0; let a: int = 0; let b: float = 0; let c: bigint = 0; + +let print: any = @raw("console.log"); +print(x); diff --git a/examples/basics/weird.blight b/examples/basics/weird.blight index 9a78b1625bca53e3c2fe224a5c3efe7fe07e2fac..a10c1ec7a2f55dbbe68e90ab93503ceefd4c91aa 100644 --- a/examples/basics/weird.blight +++ b/examples/basics/weird.blight @@ -9,5 +9,6 @@ fn bingus(y: bool) -> int { x } +let print: any = @raw("console.log"); print(bingus(true)); print(bingus(false)); diff --git a/examples/interop/blight_in_js/main.js b/examples/interop/blight_in_js/main.js index 38a8ce7256c2388c8d9b669a82c8c6156bbe2ee4..18c652b5967116f7639c152c7fbebd1760631755 100644 --- a/examples/interop/blight_in_js/main.js +++ b/examples/interop/blight_in_js/main.js @@ -1,4 +1,4 @@ import { add, TOP_LEVEL } from "./add.js"; console.log(add(1, 2)); -console.log(TOP_LEVEL) +console.log(TOP_LEVEL); -- 2.54.0