From e93bded3565190633c775a9c39c866f082c3d509 Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Mon, 19 Sep 2022 12:26:40 +0300 Subject: [PATCH 01/15] Java API to ArkTS API mapping implementation. Change-Id: I9972202c6b0e452c71f099bfb7db15ec909a5611 Signed-off-by: Alexander Pavlyuk --- migrator/build.xml | 23 +- migrator/config/java-api-mapper.xml | 546 ++++++++++++ .../Java_API_to_ArkTS_API_mapping_rules.docx | Bin 0 -> 11837 bytes migrator/docs/java-api-mapper.xml | 400 +++++++++ .../com/ohos/migrator/AbstractTranspiler.java | 3 + .../src/com/ohos/migrator/Transpiler.java | 4 + .../ohos/migrator/apimapper/Arguments.java | 198 +++++ .../apimapper/ArrayLiteralExpression.java | 153 ++++ .../ohos/migrator/apimapper/ArrayType.java | 119 +++ .../migrator/apimapper/BinaryExpression.java | 382 +++++++++ .../migrator/apimapper/CallExpression.java | 126 +++ .../migrator/apimapper/CastExpression.java | 104 +++ .../migrator/apimapper/IntersectionType.java | 75 ++ .../com/ohos/migrator/apimapper/Literal.java | 106 +++ .../ohos/migrator/apimapper/PrimaryType.java | 89 ++ .../migrator/apimapper/SuperExpression.java | 72 ++ .../migrator/apimapper/TernaryExpression.java | 174 ++++ .../migrator/apimapper/ThisExpression.java | 72 ++ .../migrator/apimapper/TypeArguments.java | 136 +++ .../migrator/apimapper/TypeReference.java | 90 ++ .../migrator/apimapper/UnaryExpression.java | 119 +++ .../src/com/ohos/migrator/apimapper/Util.java | 66 ++ .../ohos/migrator/apimapper/WildcardType.java | 99 +++ .../com/ohos/migrator/java/JavaApiMapper.java | 810 ++++++++++++++++++ .../ohos/migrator/java/JavaTransformer.java | 384 +++++++-- .../ohos/migrator/java/JavaTranspiler.java | 30 +- .../com/ohos/migrator/java/NodeBuilder.java | 32 +- .../migrator/staticTS/NodeBuilderBase.java | 17 + .../staticTS/parser/StaticTSContextBase.java | 10 +- .../staticTS/writer/StaticTSWriter.java | 1 + .../java-mapper/CallExpressionRules1.java | 37 + .../java-mapper/CallExpressionRules1.java.sts | 33 + .../java-mapper/CallExpressionRules2.java | 33 + .../java-mapper/CallExpressionRules2.java.sts | 30 + .../java-mapper/CallExpressionRules3.java | 23 + .../java-mapper/CallExpressionRules3.java.sts | 24 + migrator/test/java-mapper/ImportRules1.java | 44 + .../test/java-mapper/ImportRules1.java.sts | 38 + migrator/test/java-mapper/TypeReference1.java | 28 + .../test/java-mapper/TypeReference1.java.sts | 27 + migrator/test/java/array_creation.java.sts | 1 + migrator/test/java/array_type.java.sts | 1 + migrator/test/java/assert.java.sts | 1 + migrator/test/java/assignments.java.sts | 1 + migrator/test/java/binary_operations.java.sts | 1 + .../java/class_instance_creation.java.sts | 1 + .../java/class_instance_initializer.java.sts | 1 + .../java/class_static_initializer.java.sts | 1 + .../test/java/conditional_expression.java.sts | 1 + migrator/test/java/constructor_test.java.sts | 1 + migrator/test/java/do_statement.java.sts | 1 + migrator/test/java/empty_class.java.sts | 1 + migrator/test/java/empty_statement.java.sts | 1 + .../test/java/enhanced_for_statement.java.sts | 1 + .../java/enum_with_class_behavior.java.sts | 1 + migrator/test/java/field_decl.java.sts | 1 + migrator/test/java/final_empty_class.java.sts | 1 + migrator/test/java/for_statement.java.sts | 1 + migrator/test/java/generic_class_1.java.sts | 1 + migrator/test/java/generic_class_2.java.sts | 1 + migrator/test/java/generic_class_3.java.sts | 9 +- migrator/test/java/generic_class_4.java.sts | 1 + .../test/java/generic_interface_1.java.sts | 1 + .../test/java/generic_interface_2.java.sts | 1 + migrator/test/java/if.java.sts | 1 + migrator/test/java/inferred_types.java.sts | 1 + migrator/test/java/inheritance.java.sts | 1 + migrator/test/java/interface_nested.java.sts | 1 + migrator/test/java/interface_public.java.sts | 1 + migrator/test/java/intersection-type.java.sts | 1 + migrator/test/java/labeled.java.sts | 1 + migrator/test/java/lambda_expr.java.sts | 3 +- migrator/test/java/literals.java.sts | 1 + migrator/test/java/method_empty.java.sts | 1 + migrator/test/java/method_full.java.sts | 1 + migrator/test/java/method_invocation.java.sts | 1 + migrator/test/java/method_references.java.sts | 5 +- migrator/test/java/named_types.java.sts | 1 + .../java/npe_in_ctor_declaration.java.sts | 1 + .../java/npe_in_method_declaration.java.sts | 1 + .../java/npe_in_method_reference.java.sts | 1 + .../test/java/npe_in_type_argument.java.sts | 1 + .../java/npe_in_type_parameter_bound.java.sts | 1 + .../test/java/npe_in_wildcard_bound.java.sts | 1 + migrator/test/java/super_expression.java.sts | 1 + migrator/test/java/switch_statement.java.sts | 1 + .../test/java/synchronized_blocks.java.sts | 1 + .../test/java/synchronized_methods.java.sts | 1 + migrator/test/java/test_enum.java.sts | 2 + migrator/test/java/test_interface.java.sts | 1 + migrator/test/java/this_expression.java.sts | 1 + migrator/test/java/throw_statement.java.sts | 1 + migrator/test/java/throws_test.java.sts | 7 +- migrator/test/java/try_catch_finally.java.sts | 1 + .../test/java/try_with_resources.java.sts | 1 + migrator/test/java/type_cast.java.sts | 1 + migrator/test/java/unary_operations.java.sts | 1 + migrator/test/java/var_declare.java.sts | 1 + migrator/test/java/while_statement.java.sts | 1 + 99 files changed, 4725 insertions(+), 112 deletions(-) create mode 100644 migrator/config/java-api-mapper.xml create mode 100644 migrator/docs/Java_API_to_ArkTS_API_mapping_rules.docx create mode 100644 migrator/docs/java-api-mapper.xml create mode 100644 migrator/src/com/ohos/migrator/apimapper/Arguments.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/ArrayLiteralExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/ArrayType.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/BinaryExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/CallExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/CastExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/IntersectionType.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/Literal.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/PrimaryType.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/SuperExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/TernaryExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/ThisExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/TypeArguments.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/TypeReference.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/UnaryExpression.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/Util.java create mode 100644 migrator/src/com/ohos/migrator/apimapper/WildcardType.java create mode 100644 migrator/src/com/ohos/migrator/java/JavaApiMapper.java mode change 100755 => 100644 migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java create mode 100644 migrator/test/java-mapper/CallExpressionRules1.java create mode 100644 migrator/test/java-mapper/CallExpressionRules1.java.sts create mode 100644 migrator/test/java-mapper/CallExpressionRules2.java create mode 100644 migrator/test/java-mapper/CallExpressionRules2.java.sts create mode 100644 migrator/test/java-mapper/CallExpressionRules3.java create mode 100644 migrator/test/java-mapper/CallExpressionRules3.java.sts create mode 100644 migrator/test/java-mapper/ImportRules1.java create mode 100644 migrator/test/java-mapper/ImportRules1.java.sts create mode 100644 migrator/test/java-mapper/TypeReference1.java create mode 100644 migrator/test/java-mapper/TypeReference1.java.sts diff --git a/migrator/build.xml b/migrator/build.xml index a16ddfa07..c0163b9ca 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -25,6 +25,7 @@ + @@ -70,6 +71,7 @@ + @@ -121,6 +123,19 @@ + + + + + + + + + + + + + @@ -138,7 +153,7 @@ - + - + - + - diff --git a/migrator/config/java-api-mapper.xml b/migrator/config/java-api-mapper.xml new file mode 100644 index 000000000..adb896333 --- /dev/null +++ b/migrator/config/java-api-mapper.xml @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/migrator/docs/Java_API_to_ArkTS_API_mapping_rules.docx b/migrator/docs/Java_API_to_ArkTS_API_mapping_rules.docx new file mode 100644 index 0000000000000000000000000000000000000000..3e39d0562c03a3325bb85fef5e46a7a8f487aab5 GIT binary patch literal 11837 zcma)i1y~)s8ZGYb?(XhIio3hJySuxykwTH;P~6=q?(R@rihGeh=#|rZ-n;jE|Ndsr zB$<^-vXVc^%uGUd2#)kwiYYmJF zGCb-1vgLYT-ySa8WT9_SRVZ?GXjC~OHv}V=_z>`ETte?4gEZ7>*7-_ngc%;I!E+Y$ zd#mLc)60(lyBST}ilF)i+7h>%#Mi~xY!PjG9C%8t0hLAo*GQpGaiB<`>9x+lV{(Z! z>z3)%&vT+PZ}Y>%@gC&_X$Bq`aA~*f0^>~7bsc3B1kI&iS0cq@ct>{`1(w^Z*FD2| zAL1u7M56&Y%f7%0(vVPlPIn@QZ`Gdy0RmF^uMLF!c87_*v4WGmgEOPCy^|?}hpkPh zlCFF(6PoY6dP1i#_2C?ZMxL2G1M@OQtbM~;4NY><>A>ANJ=4-0dFQ(G8)I3+`Dx`MB0icKpK4V$ zIze=RB~>D*6)Y)uA!#k7zP}wD$E~c^OMs@6jIdj>fy)f@xd=L=8PNI)?e|%Lu~pHR zcvaO=P}9jK#0h@v;~6*TN*eB`#fM8vZedL{u|&d+CzD#TMYh&lldJ44{d4U;{z}({ zTFR|$Jh;V=n(lqs&xsDrCbdhgq2@#{^Lc=n(z|4GR=2abPK*Qryv)JSwJAl{u@_Dh zVn2^2GUixPoSb+zESD7aA0kipwW}p%Jll=7buSNKc2DVITSl}t(7s+!zkG&%;J)+3 z(y|F-2@C|Z_CI+-`jaO^2Zwi>vJ@5Vdx?AkgB0Isc^eOp$V zT14HMuTQyVm5AOr(8Ip>>%N48(|ft+NgueXV)P2g`Yb`Tuu5<25<3^-^J!##wzRG$ zEHnzlFOHJdr&3rkbQHD#C0|}hY=x_xL)tBJ5BQ_&<7A9=CWS-n!ewTufDy%f?!JKH z80(O5flZ<84(Wls%%L~Nt%HG zNc57fYctS1WUkDjMr*0LM1|`B*FS6F#iHN_of#g6r_nb9&B;a60_19F-{k~odwY;hVnK)A)&Bd#7pRmyg>})?I8|~{& z8gv#HPRK7e`{6~n9BCQZs)do38i*bqfs)?-rI1UqXL!qiAmqy)1YMikq7Er|#4vC) z9g#J6F`8B3(!>^g8n-b6si?hDwxbeT+(d8sk8NN8kIKB_awzH}i4XVVf?YI9t zO%{>|VMYo)e~ywpw*gMX>gyGi<@$ux!+PXq-Uh$w#)=R3>9ns%M@L|IGY5YXG zc;{$fewf#wzQ;T-=S~DfFTB?a5ZUxi`Cd+jGV79dF3Ll?+y)huf5(`DCU0MFq=eRi zrYIM9lGaqPI6|7OR?({vZb+z#Gs$BD31B~FqGkeOE~-x!Z42se7+zbCLlC6Ld*PBB z8dG0E%%YeJJkoET#Ueg5dJ1XVSoJBS;kFDAjL*Tcr~xA3>fj_^iPpN+v~Cfr(rnaH z!@h+=#UKrr-HpjoCCso43oK<0PXj|mYSmJ#LY!UN&v0WjacR7JdM*4?%c#uy%yNSV z(|NKJmag}LGcxW^B_NF5h#jThhL<3IhBl(udZ%N*%BJX41e>zxz~Y!(nU2-KQ!Ch? z#!t8s>{LC4J!jnE?guJ`w--P^0#p#FTq*bn@^Cxtj4>C(_ z#`DXKO=csgdu7Eutv|HNc+7I#KuL(98Ilr!t4(BGWF83jO?izdjk-()zUkMd12L{A zODN{SoF2}I1_^GY56L`V%Ikw}dVcxHLZH_uw=zf{9>#F5vD9Vr;&lJIJeo?14*g;K zIzg}TZK`^`InH_IYQ1R21!q%1h(Q{G^;?b-@gQCYhL7;UU{ZG&_C8J@4Tjw~VNM%h ztaw0hT*jedZ|CBPvbVY>hX39~fC;R4p?DKNMsL4kj-N$9C?J3`M+vh}3u!|Im?lX5 z@Qe5Ya3Us}&9mK$3v;GK4U80MpN)%zQPh`-hpE972iRbyyE2haP&`Wnpn6*Sjfo|* z3Kz{<^syNo9w{2M19nO;c|chTmMvbK@?WSt*kr_D*GS6XBbwvGplXN>>PLNw2E4v6 z7sySFj$7fFeU44b&jAoF;BK+u6FD$eJ`rOUoPbjH$l&Q@gOWDt0Smjfa1JcyzB<$1 zNQ=k%9>*{cMEEba8jloLkoq!TYh2ydJW3%%!qSG?x1j~V#dCdtbR*DB$j)2h_ztO z4`RMPq0~E2Qv9~O>YeeE0pW$lF<3sFM2Kidt(NsAyniEhA-^7oT$545;tc!Uv*puvFnjRJy?N0C5K`Sv_y6x1J$K@FdE z^`W)~?>WmE>k(Yexb9actbvMR)&fC|q2#vU`Dk`WjvjBy{P2WYdqn$;Zk-KPu;IgX zs9tbG!9_(ZeQrq5p)_UHy_mKIGOq0lTY(43OO`A1t|$A;QnRR-ycGI3md!ET#GfDqxt-N3+EvPb&wHd5yaE-3fRL>k3J>erXZJn-MBP(3|mYqenI~ZxNVJ z325US-?68CG`0CoPMejF3%K+I$%44x*u2>~gOmp!oTJElv4tEYVdX4GKA+fkE2IAM zrWfW2C-lZOK<+~O_-DTdJQcNDWWe|$OHQ_e+pmozl~}Udu!q;Sst91qqv084ORv^k zp|mJkOk?cSN;+LtQFX$@LwK>ND%bM0!f-+DQQed**_UP{Si1aIc=O<2wh$61Ug1#U zw4yX-&Ab=R{L=&v?nECER2`PE#3LiTYcH`RFAm#wT;vY|C5wPOy>Kz_eYy=f5W0wR z*_f|AW*WNFw~_Tbw_hO*b^f6Hs?#dMUDS!^OxQ0MM%QxglkQTT|m54 zQO?BN7KB3)Dj}F4!VQQY)GYp{O39WOle7~DUD?E{q4f3u#kh!Jw!{DiqKJVQ+*zx) zi-fQ|4~KReQ%UvD#noh`305 zYsL#WFvc$dYaI4;QSkRgb1lxyk$eCOE8uF947qUCLog!wO- zLk!aJ4IhqGalxhBpw$QCf$hQi^e zC(TrH4E&_XGrj8CG9^h<4m8kfb#&Tt zlzO};E-S}4Eya)70)8k2Yd&E4z=NN0rZgN5l~rl_c&la`R0YK)19i5=wHSQHbV}H7 z^0z*cy(AOH)p`s+TT&8dQ=9cHv8jDeZxh6o*RMkVP!wjQt4&OQtaxEyiA@_>5#o;m zAmANBEftb8-7TXNU}sl}=*RPMA+LT-3^AtMB3Qbr+&I+Ic2rj_sfQPCRsVR$}v%`5DFEOXYiyjKL(78`ITl;1XaZf#G z&Z4Si#?7bQ9g+Cnuk_4hn$UGh^#8_H@$QUo)Wgzpa4Pp&Tx9H+*-b={w)_Q(gh4 zJfsg|C>gp*7xv?@w)C1|^)gKB-V~#;h3;cu@0r2Bm&_j@0v{X=FfYd)yJvbqyTXMz zMPYs9>Yt80kI$l9vfMtIGH2-PgfajRI(gjZ{W|aZ zS*vaO*3a^>pgVp-70`&u%MdX&faa?eVyA;l1kM{xo|0DH>p2z?@Jw4ST= zmW(i>R_+eYBG#89CK*^ZB+e8avlcD=du$_gj(oO)cID6xE6{oDpTwys#}! z_)NsWWA>9m%|ePf8D6(n3D}3aA1!>nbH3TD-c4WmUNrsa10-NDEve`V&@fbPn_(9f zFOS&-rI}&rbOfXhRMaVLNIceWJISrhjv*$xIZ1tTGqzMyS5~?L4_KSB%wTUHS#Sr;QW&o((|;N4%h?_)9$XXhPaRh zR-G+Fv|VrJY%tk4ol|1axH^Ub{NR2QuA`FVWRB0T-jB72s(oNcuhej(qY=yky0&S%aD}L+!Ni6`YhnKuc?2gXS%h{35HrvC8ER`sT!^+L@L6glJk3 zkJ&K8u~yM0&NDxKG3MzVFT*Bsi}%yjp-|1Q^?cnv9gZHyxP4g_C~&~-gc2Nf?Mn-& z2Wz&#Q^q?5U30g#SvMUFJ)eQ~v)Sfij3(qnHbYNsAp#u&=nSddXDlwHb6;m2Wl&gm z@Zq>=8mJz`OIhkjjLg-u+bv)*d;qGe`A$1kpMOt<+ldqtat6)gW*;tlR)1ValBqKp z$Hgd;6U&4?H{xRcRj%$!P}}Klv~n5ey^7ZA(3Q$LjL8=tK#30)!zL~B4nbCVGk6hq zolM=J3}7WC{<9_BvH(GC7fMh}S}Hkb@-AYOU3Bn8&Gfmxpm&>yM{0&zE!=JM! zBVWJmAlKrypE#WwZOK?=+V2TVq3q@utf=~UJPHzKgEDAwWu#`3~baM zUbXHArnl$(++@x2d>0FDL#-KX*%&td>f3Z>HZsUjf=#Q!fYC&+r9qckw%m*Ib&U;X z5fopmR4(=m#KB&?Ib7p>X2IH0z~HvFqSc~+GNY_jqQ4iIqF0`ZBEgYpWyTgehnfb6 z`*Ii9b-N^RUlr9hBnSSmp=re>(&BlR>FOng7m>gL{lV?QO|VNZJnF9WHLxw}p=DAR z1BE%Rt7Hzi5`GX?Bwh_WJn$-aOPJF2fJ65>_Cx8frANJqN#tAJ}uFL=+r(&qmpV(&^VHV=wxF(E2=E6QE(rw9ys>ir}at!82Gf{JlUQz_$jzmDEW}C=4tpsL0tPmxFP0gzEa7Uz=*R?&Z^S>h^swjDZtGT+eu;Xl#WqPD zM9}ItdAwYdWx34BWxcC>$oXu)&pU}H4$Dd@n!>A!|7W3PAgnBn2aa_*%6II%rur+95CSw0uI|+0rhi(K&PS7YQl^@zvY#ju?nqBUrMWYQ^;@zJUZj?}A2 zKAm3{o5!G9(@zP6j+7X2Pnm+k3%xyJ+s{HR$PFCR=he_$-ZF~Z$Vyz8g;zu&=n$gj z+CFkk|6$4bT|;m*^+*;dlgo?%PVz50|{H8}w} z?h0PQLGa;ll1lSkRyX8fc34SVK!L#L(=ZoaV#MS|=LW7jY;pcNu2MTB!2;niFdGRM zfx|p%IBVfN_*^Pn6kj&t=@m860RnfQ5W6}Tf2FUM*IJg;QXAlR5-Z_Hsd{8_ zM0~!fsO=+QF6`F`Vklq5M#?e)QOg<>&TxMcKHF;@1g?_H@~s&?br>y*kC%02#gNpM zA>OnrzWnKp*uU1+N1iBgIc_0iewnn)%D_6vihxIe(wl(|_F-t8rp%>$hFV^&DF|G| z=Fx+#Ok+Wf&cX%9HRwa?EYTkE_mcEhldH^H{Oz6RZ;#Pw=TaWBOe&3cU?8bb z6=G3z3<%JO<0jEKaop>zGBk!;l`*gfeza^4In^2eVza%d4WFv$yy znM{h29q)WFkdNHCX@9MIKQBr#IQmNU^I6}ALFm#{>ZD0MQeRn4Z=69kW+a(>`4 zwRPD&@DxslmFrXrawV+^t=?Rt&RG!p*f3Nuxf@7_E?H*E%yF~WcAfaP!ed0f+))-~ zDuNYb=I?d%B{9YL4$r2`BZ6AQFB1Z@_N#aUW93l*1kF#w4a?pU?KPyNH`o{8&?v1iFL%wr*TeB1!3XwJoXhr`EV`;~I|yTntl%?)8(5py9ZM8d`h z-Z^0^Op6Ne4K8)a>ngIWw36hu_(wtdUqp6kG{y#YXTjj-1PLYDcn1KEDC&JHccDek zMx)z?0NH5qv}Q`PohtXNLm! zn-4U)J@pMG$BCK7D48U*?H-Vzg2Jc48~TI9Ng#tj)36L)1VU(o;bmZk7l!b8_CQMJYo%AgwBiwlrrka zUy?nJAisq#n|_$68*SC0Cg>L!i2sQM?r!$A11Rjin^=;xRfF4&wmAb-3S8Q2G{kZu z`S~omt@3es=PW*mxQhhOVTmBpClqj@DPf=PWH@e4S^N;oOO$8Kw&e(S1QsXGWoci& z+5KsS$nW;o`x|F?rPnT23?Lw6Y2g3y2>|h5Z=9W7JZ(&!-(UTIQ|nP$WkTw>r{!yf zq)b+#5H_&jflCjZvfP@=C$UFC*Hj`;C-d=DZ$!uAWkBMg4>#y&SZK4~taS0}loGvx z8gL?qEO4J9N0ul;VK@MF@^@e6CQfu!p-`cM2CapVo|xp%WO!Pr0AGT-mtNIJ80zI- zk2fC0NKo?r!X{Bao-A3~SC~F1ZHi)x25LR+OS9c)ch4n9okrGtgwKvwn2BvVKZehg zGGN8A1LvgP+_5;GqlAoC@Pj?DV2;nEHTady)n^3U{e%w-rLbHeL)!FE#h?)jk-JX^ z^;>6ej9IT{7u%*x3!VC7mo#}+Y^tvn_FFN>iw&kalBU7na*)~R847Hffg8?xop^|L zpyeskZ;0wZoea6qr#p5v&?D?9$nNyLfk-by#c3dRs{?+_LU6$hO)W4B?eQ59@!kVY z;|1t>`f9?9_Q#&$U566uVUL(=4yFyFPwGY?))STF^3BAtd&8}N+gV^A(> z`xqjiEt+;Ul?R-)iUW8+?Jqul;%54s=2u%S-94sC{UDEGBt?a4l=tb%UtLXaa&h4q zrX)wHLu_7Jc#if&l%A}q){Nc;MU4UL?BX$6YN5g@QB#Z0;gZS11drfy z4C>8owCwWPQWSJ#``}5X<$;bM+9BQ~Y;$Tic(pu-`7x{Ok7yf9S(}}}F=QktYwT%= zvg_Mor0s=LyJ~4}m*)j@QW%2%pI|KRwq~tVPr5;BLm z(L5zbWRuk&egrWbrAI=55RjT*>0Tdw<_l=uUtmWW>CtVmDJyYmT2j4hq&dYsPOxH3 z6srgJk9@|@Lrg=?L{}IiUnTKmyyBGT)Xi;wu*IW2Eq?9vi8TQ!gU|;5x!AlC9^}s< zc;4KXt84y6@Yh+#-sARgcaDI4tD?_}WB$XOQ$CdZ-4D+9p&Ftkbz=t#1f-7ezdjD3 z{A;M%x!M|;I$7G8zmL|_bw#^;F)YZ7`|RG2$HqnwHZc{hYAIhOj)b*KS3wQnIB4K7 z49sT-3GzCG2)zO~%o(R>U4T|gQJ+r05J#4tb23dIx;HslFIJgR2>Jcwwl^q-uBi5u zgV!^}7`Oa*;vbBxo}Z6i2iUzlzhAas7V~|=kr%S_X@5HI+X<-xXeLCycx@x`Oc+26YRhkECbdiLQ41C=Ri5C}be`73W z8t?7-@oR_t9d66viDfnb)vX?>WB9DCHv=zP1~s8>JrW>zp;_{k3LGLmXFP2g2UfnxwdW&P_uMd*`I^Q-D50%t0?PtEFT6jd4H*NCoPg?SOe06L@P za%*H$^2MKEW|hJiH8u;DFr!k{x70S87^=-*H5aET%SIN8tJ%rU303PVMU&C3PL!8$ z0GxoYn#I&~v}S7gumTv2X4Y-3BljBxl1AFhDm&`I|WRcgV|q>+?-xwYO*7hIiMlP__(m8Q0V{)$HR zcg{{jHiJ^Nt`@XBv6V{pyF-FIp@QHzN82C2pe(ug5-UWe@pK`T1R3h;K&gj)@FSYfAg7%LqA~leB6YmeSfpG)0 zfgWVl)8mNoU^G-D1kfryOnfLyKPuzJK~x2iAmuAV!b9=aHUZB+Kp5LKfnwu^hQn_HXC$Sv1bo!gsRx}Bp-Yl5S1aExdJcRcOen-8AHk_yXVhXh>og=jd6WXh_^hxG=+(R{gJAz@3nL5 z_oay+K=3crf(gv;N3J7u>}{MwzJvbp{C}P9({C0YRa5^J{CA?S=*>VIoshjR#fRVJ zeJ|fI+V8To;d^oVr<2QjD%ejh8a}i)AZG~DbinTt=m=ZfjrgtttR3-N`wKC}e?Hc+i1o<@_lrf#S zd=d>=F7C4-v2ozB5e$Ks4~LIrI&k?U91<%R9vi`Q@A64HBvw8=HnRFu+9>Y6NfKNM zG!%zA28$*Jhc*U_E(V7_28$sEhcO0=DF%l*28$&IhcyO^Ee3}@28-i|!P;C-9T93; zM4SI_71zsUsOtzg5D?Dr|JO`lW^d=BVrXRZTgKG^ShxDE)_6iAzGpAPETpTPQSws! z8u}HHX+V=RA%`4w{pVe*qR^_XgBHQ|;I%I+~V}b#k{bTl5L_=Z7Kb3#NRHjE{3EAEy5V^+6pX zQnto$b0R<%z7|Bj`FuHu!6Vf%@hni$%bn-8^aHvTx``{#W{`UITr*>2@G{}-@&sL$ z-7SvG=`D)(N`+RAXe`Ok;`w5&JbA-9Y%f&`^(jM~GRmycc2U^$WZm!!bn`vB8`vT= zWNi)faNK1RH_DRh=I$BQTHfzE_{nD#{7mgXA6g=1GhOd5e;9z(`r)G41hu6cHGi3A ze4m$tVU=X$-b5R^Z;bqR70tgz8_uRKE^o8)??tq!!l+%ZAYA)BZC*zogvu>4vI1jC z_#M~_P@UtD)bg#>X~IlZ6|rc=+~?EuOON&ypRi6YLo@jrj%ZIyn3y;m!uW>AC3|!E zB7?vsL3w0rXEBb?x9e8rSfa__LhT}SVjGS`luYT{5I`?7QN+G!jR1?R`qY!|QJ6Xn zmCsDAnriYd0r6)vR6diyeA6HwL&!hmzAvo7{L+IFrg!JC1WjI;`K4;y_>r%N392Jo zIUHHUdCg%MR1Qp>IPh7m?Z}N>3@XDa<7e=BN9Ja!Q2tcHOP5Sfn~Y4wn5t2!ZAYIq zjWeq*9b@WURdESM6WShpWw!c;Xh8Q>FG11S7B2g<;$~;tE5v(48n>|u!MrtO-rMot z8}eOdr7ir{rQbA2`YN6drp~(WE1Zs$QMo=QB++{x(Or5e9Sx$8B)1-8Xx(IXrz}aU z2*TQ|nb!|HWKjy}8L1elmt!3VapICQ%VKKNIOV8Xrn@xh2~cQ@EefV$dYJN;^y#vU zGv5{hqN~+gV#?b&-IIAbL56km;Hk>dR;2bXr&H&cUVEgzECPn%_q03}`0sjxWo99% zG;|*i9fJqyG55$??VmtsNXI@&IqcWS2&W(%)2Z0SJ5*d{xj3fL37O9BsP#6F=0J<3 z@B$I{nSA%rxU@6Sm_bvx4qCJoMVQXi{53|#G1bHbEjz(CiA25VW7pu=i~&3R8ok*E zd%W}oS%YzliA0MKaZZ$&>x($OVv=CNhoa=V+}DB!YUJn%x^_S&wl1Gw?mU@Gp7 z`=O*VBqv^au=9g%H}uaalaI0c4u0B!y#7%O?r2q3Env|}*OZ49;=*VWy49w)(du?| zBK99Tp)Ls6{cEBoTB02iXZGWnUqIfuDj~Miuzuso0OFl1U=TE*zqGc0icH_Nw*P5= zC~yA`{8RP#K3@JZ;ThbS zf202r_WeDBKgC<`nz_G>@y#>*F9qG-bNX{r{-5p8{np(7m-OrJ@IN;S?>qOuj0OLn z@W1x)e+U0Lx4iEq{<3wVe}eyGXYqIZpWg64@dp(D#Q(>9^mqK9PT)W5?n?Eq!vEnx k{|^7NU;ZbHoz(wNzo8%v{??{IK(KGWj<;@NMf)E5KUms$7XSbN literal 0 HcmV?d00001 diff --git a/migrator/docs/java-api-mapper.xml b/migrator/docs/java-api-mapper.xml new file mode 100644 index 000000000..2144532c2 --- /dev/null +++ b/migrator/docs/java-api-mapper.xml @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/migrator/src/com/ohos/migrator/AbstractTranspiler.java b/migrator/src/com/ohos/migrator/AbstractTranspiler.java index 4c263ce32..88b3f9edd 100644 --- a/migrator/src/com/ohos/migrator/AbstractTranspiler.java +++ b/migrator/src/com/ohos/migrator/AbstractTranspiler.java @@ -124,4 +124,7 @@ public abstract class AbstractTranspiler implements Transpiler { public double getConversionRate() { return 0; } + + @Override + public void migrateAPI(CompilationUnitContext arktsCU) {} } diff --git a/migrator/src/com/ohos/migrator/Transpiler.java b/migrator/src/com/ohos/migrator/Transpiler.java index 719ceb931..903f76914 100644 --- a/migrator/src/com/ohos/migrator/Transpiler.java +++ b/migrator/src/com/ohos/migrator/Transpiler.java @@ -15,10 +15,14 @@ package com.ohos.migrator; +import com.ohos.migrator.staticTS.parser.StaticTSParser; + import java.util.List; public interface Transpiler { ResultCode transpile(); List getErrorList(); double getConversionRate(); + + void migrateAPI(StaticTSParser.CompilationUnitContext arktsCU); } diff --git a/migrator/src/com/ohos/migrator/apimapper/Arguments.java b/migrator/src/com/ohos/migrator/apimapper/Arguments.java new file mode 100644 index 000000000..3dd7ebaba --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/Arguments.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.staticTS.parser.StaticTSParser.ArgumentsContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.ExpressionSequenceContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.ArrayList; +import java.util.List; + +// // List of arguments. List of any the following child elements: +// // The source Argument with the specified index. +// // Any of the possible literals: +// +// +// +// +// // The unary operation applied to the source Argument with the specified index. +// +// // The two operands of the operation which could be either: +// // The source Argument with the specified index. +// // or any of possible literals +// // or any of the suitable SingleExpressions which may use source arguments to form the expression. +// +// +// // The tree operands which form the TernaryExpression and could be any of: +// // The source Argument with the specified index. +// // or any of possible literals +// //or any of the suitable SingleExpressions which may use source arguments to form the expression. +// +// +// +// +// +// +// +// +// // A sequence of SingleExpressions which could be any of: +// // The source Argument with the specified index. +// // or any of possible literals +// // or any of the suitable SingleExpressions which may use source arguments to form the expression. +// +// +// // A SingleExpression which could be any of: +// +// +// +// + +public class Arguments extends ArrayList { + static public String tag = "Arguments"; + + // The list of arguments. Its elements could be any of: + // - Integer - index of the source TypeArgumens list. + // - Leteral + // - CallExpression + // - UnaryExpression + // - BinaryExpression + // - TernaryExpression + // - ThisExpression + // - SuperExpression + // - ArrayLiteralExpression + // - CastExpression + + static public Arguments read(XMLEventReader xmlReader, XMLEvent xmlArgumentsEvent) throws XMLStreamException { + Arguments arguments = new Arguments(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("SrcArgument".equals(tag)) { + arguments.add(Integer.valueOf(Util.getAttribute(startElement, Util.indexAttr))); + } + else if (Literal.tag.equals(tag)) { + arguments.add(Literal.read(xmlReader, xmlEvent)); + } + else if (CallExpression.tag.equals(tag)) { + arguments.add(CallExpression.read(xmlReader, xmlEvent)); + } + else if (UnaryExpression.tag.equals(tag)) { + arguments.add(UnaryExpression.read(xmlReader, xmlEvent)); + } + else if (BinaryExpression.tag.equals(tag)) { + arguments.add(BinaryExpression.read(xmlReader, xmlEvent)); + } + else if (TernaryExpression.tag.equals(tag)) { + arguments.add(TernaryExpression.read(xmlReader, xmlEvent)); + } + else if (ThisExpression.tag.equals(tag)) { + arguments.add(ThisExpression.read(xmlReader, xmlEvent)); + } + else if (SuperExpression.tag.equals(tag)) { + arguments.add(SuperExpression.read(xmlReader, xmlEvent)); + } + else if (ArrayLiteralExpression.tag.equals(tag)) { + arguments.add(ArrayLiteralExpression.read(xmlReader, xmlEvent)); + } + else if (CastExpression.tag.equals(tag)) { + arguments.add(CastExpression.read(xmlReader, xmlEvent)); + } + else + assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (Arguments.tag.equals(tag)) { + break; + } + else { + assert ("SrcArgument".equals(tag) || Literal.tag.equals(tag) || CallExpression.tag.equals(tag) + || UnaryExpression.tag.equals(tag) || BinaryExpression.tag.equals(tag) + || TernaryExpression.tag.equals(tag) || ThisExpression.tag.equals(tag) + || SuperExpression.tag.equals(tag) || ArrayLiteralExpression.tag.equals(tag) + || CastExpression.tag.equals(tag)); + } + } + } + + return arguments; + } + + public void rebuildArktsNode(ExpressionSequenceContext arktsExpressionSequence, List arktsOrigTypeArguments, List arktsOrigArguments) { + arktsExpressionSequence.children.clear(); + + for(Object ruleArg : this) { + if (ruleArg instanceof Integer) { // "SrcArgument"{ + int index = (Integer)ruleArg; + arktsExpressionSequence.children.add(arktsOrigArguments.get(index)); + arktsOrigArguments.get(index).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof Literal) { + arktsExpressionSequence.addChild(((Literal)ruleArg).buildArktsNode()).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof CallExpression) { + arktsExpressionSequence.addChild(((CallExpression)ruleArg).buildArktsNode(arktsOrigTypeArguments, arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof UnaryExpression) { + arktsExpressionSequence.addChild(((UnaryExpression)ruleArg).buildArktsNode(arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof BinaryExpression) { + arktsExpressionSequence.addChild(((BinaryExpression)ruleArg).buildArktsNode(arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof TernaryExpression) { + arktsExpressionSequence.addChild(((TernaryExpression)ruleArg).buildArktsNode(arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof ThisExpression) { + arktsExpressionSequence.addChild(((ThisExpression)ruleArg).buildArktsNode()).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof SuperExpression) { + arktsExpressionSequence.addChild(((SuperExpression)ruleArg).buildArktsNode()).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof ArrayLiteralExpression) { + arktsExpressionSequence.addChild(((ArrayLiteralExpression)ruleArg).buildArktsNode(arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else if (ruleArg instanceof CastExpression) { + arktsExpressionSequence.addChild(((CastExpression)ruleArg).buildArktsNode(arktsOrigArguments)).setParent(arktsExpressionSequence); + } + else + assert false; + } + } + + public ArgumentsContext buildArktsNode(List arktsOrigTypeArguments, List arktsOrigArguments) { + ArgumentsContext arktsArguments = new ArgumentsContext(null, 0); + ExpressionSequenceContext arktsExpressionSequence = new ExpressionSequenceContext(arktsArguments, 0); + arktsExpressionSequence.setParent(arktsArguments); + + rebuildArktsNode(arktsExpressionSequence, arktsOrigTypeArguments, arktsOrigArguments); + + return arktsArguments; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/ArrayLiteralExpression.java b/migrator/src/com/ohos/migrator/apimapper/ArrayLiteralExpression.java new file mode 100644 index 000000000..0b839a75f --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/ArrayLiteralExpression.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.staticTS.parser.StaticTSParser.ExpressionSequenceContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.ArrayLiteralExpressionContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import static com.ohos.migrator.apimapper.Util.getAttribute; +import static com.ohos.migrator.apimapper.Util.indexAttr; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.ArrayList; +import java.util.List; + +// +// // A sequence of SingleExpressions which could be any of: +// +// // or any of possible literals +// // or any of the suitable SingleExpressions which may use source arguments to form the expression. +// +public class ArrayLiteralExpression extends ArrayList { + static public String tag = "ArrayLiteralExpression"; + + private List elemsnts = new ArrayList<>(); + + static ArrayLiteralExpression read(XMLEventReader xmlReader, XMLEvent xmlArrayLiteralExpressionEvent) throws XMLStreamException { + ArrayLiteralExpression arrayLiteral = new ArrayLiteralExpression(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("SrcArgument".equals(tag)) { + arrayLiteral.elemsnts.add(Integer.valueOf(getAttribute(startElement, indexAttr))); + } + else if (Literal.tag.equals(tag)) { + arrayLiteral.elemsnts.add(Literal.read(xmlReader, xmlEvent)); + } + else if (CallExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(CallExpression.read(xmlReader, xmlEvent)); + } + else if (UnaryExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(UnaryExpression.read(xmlReader, xmlEvent)); + } + else if (BinaryExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(BinaryExpression.read(xmlReader, xmlEvent)); + } + else if (TernaryExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(TernaryExpression.read(xmlReader, xmlEvent)); + } + else if (ThisExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(ThisExpression.read(xmlReader, xmlEvent)); + } + else if (SuperExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(SuperExpression.read(xmlReader, xmlEvent)); + } + else if (ArrayLiteralExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(ArrayLiteralExpression.read(xmlReader, xmlEvent)); + } + else if (CastExpression.tag.equals(tag)) { + arrayLiteral.elemsnts.add(CastExpression.read(xmlReader, xmlEvent)); + } + else + assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (ArrayLiteralExpression.tag.equals(tag)) { + break; + } + else { + assert("SrcArgument".equals(tag) || Literal.tag.equals(tag) || CallExpression.tag.equals(tag) + || UnaryExpression.tag.equals(tag) || BinaryExpression.tag.equals(tag) + || TernaryExpression.tag.equals(tag) || ThisExpression.tag.equals(tag) + || SuperExpression.tag.equals(tag) || ArrayLiteralExpression.tag.equals(tag) + || CastExpression.tag.equals(tag)); + } + } + } + + return arrayLiteral; + } + + public SingleExpressionContext buildArktsNode(List arktsOrigArguments) { + SingleExpressionContext arktsArrayLiteralExprParent = new SingleExpressionContext(); + ArrayLiteralExpressionContext arktsArrayLiteralExpr = new ArrayLiteralExpressionContext(arktsArrayLiteralExprParent); + + ExpressionSequenceContext arktsExprSequence = new ExpressionSequenceContext(arktsArrayLiteralExpr, 0); + + for (Object element : elemsnts) { + if (element instanceof Integer) { + // Add the original element DIRECTLY to arktsExprSequence.children and not via arktsExprSequence.addChild() here. + arktsExprSequence.children.add(arktsOrigArguments.get((Integer)element)); + } + else if (element instanceof Literal) { + arktsExprSequence.addChild(((Literal)element).buildArktsNode()).setParent(arktsExprSequence); + } + else if (element instanceof CallExpression) { + arktsExprSequence.addChild(((CallExpression)element).buildArktsNode(null, arktsOrigArguments)).setParent(arktsExprSequence); + } + else if (element instanceof UnaryExpression) { + arktsExprSequence.addChild(((UnaryExpression)element).buildArktsNode(arktsOrigArguments)).setParent(arktsExprSequence); + } + else if (element instanceof BinaryExpression) { + arktsExprSequence.addChild(((BinaryExpression)element).buildArktsNode(arktsOrigArguments)).setParent(arktsExprSequence); + } + else if (element instanceof TernaryExpression) { + arktsExprSequence.addChild(((TernaryExpression)element).buildArktsNode(arktsOrigArguments)).setParent(arktsExprSequence); + } + else if (element instanceof ThisExpression) { + arktsExprSequence.addChild(((ThisExpression)element).buildArktsNode()).setParent(arktsExprSequence); + } + else if (element instanceof SuperExpression) { + arktsExprSequence.addChild(((SuperExpression)element).buildArktsNode()).setParent(arktsExprSequence); + } + else if (element instanceof ArrayLiteralExpression) { + arktsExprSequence.addChild(((ArrayLiteralExpression)element).buildArktsNode(arktsOrigArguments)).setParent(arktsExprSequence); + } + else if (element instanceof CastExpression) { + arktsExprSequence.addChild(((CastExpression)element).buildArktsNode(arktsOrigArguments)).setParent(arktsExprSequence); + } + else + assert false; + + } + + return arktsArrayLiteralExprParent; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/ArrayType.java b/migrator/src/com/ohos/migrator/apimapper/ArrayType.java new file mode 100644 index 000000000..def71283b --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/ArrayType.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.ArrayTypeContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.PredefinedTypeContext; +import org.eclipse.jdt.core.dom.PrimitiveType; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// +// // OR +// +// +public class ArrayType { + static public String tag = "ArrayType"; + private String predefinedType = null; + private TypeReference typeReference = null; + + static ArrayType read(XMLEventReader xmlReader) throws XMLStreamException { + ArrayType arrayType = new ArrayType(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("PredefinedType".equals(tag)) { + arrayType.predefinedType = Util.getAttribute(startElement, Util.nameAttr); + } + else if (TypeReference.tag.equals(tag)) { + arrayType.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (ArrayType.tag.equals(tag)) { + break; + } + else { + assert ("PredefinedType".equals(tag) || TypeReference.tag.equals(tag)); + } + } + } + + return arrayType; + } + + // ArkTS: + // arrayType: (predefinedType | typeReference) {notLineTerminator()}? (OpenBracket CloseBracket)+ + // The rule: + // + // + // // OR + // --> + // + public ArrayTypeContext buildArktsNode(List arktsOrigTypeArguments) { + ArrayTypeContext arktsArrayType = new ArrayTypeContext(null, 0); + + if (predefinedType != null) { + int arktsTypeNameCode = -1; + + if (predefinedType.equals(PrimitiveType.BOOLEAN.toString())) + arktsTypeNameCode = StaticTSParser.Boolean; + else if (predefinedType.equals(PrimitiveType.BYTE.toString())) + arktsTypeNameCode = StaticTSParser.Byte; + else if (predefinedType.equals(PrimitiveType.CHAR.toString())) + arktsTypeNameCode = StaticTSParser.Char; + else if (predefinedType.equals(PrimitiveType.INT.toString())) + arktsTypeNameCode = StaticTSParser.Int; + else if (predefinedType.equals(PrimitiveType.DOUBLE.toString())) + arktsTypeNameCode = StaticTSParser.Double; + else if (predefinedType.equals(PrimitiveType.FLOAT.toString())) + arktsTypeNameCode = StaticTSParser.Float; + else if (predefinedType.equals(PrimitiveType.LONG.toString())) + arktsTypeNameCode = StaticTSParser.Long; + else if (predefinedType.equals(PrimitiveType.SHORT.toString())) + arktsTypeNameCode = StaticTSParser.Short; + else + assert false; + + PredefinedTypeContext arktsPredefinedType = new PredefinedTypeContext(null, 0); + arktsPredefinedType.addChild(NodeBuilder.terminalNode(arktsTypeNameCode)).setParent(arktsPredefinedType); + } + else { + assert (typeReference != null); + arktsArrayType.addChild(typeReference.buildArktsNode(arktsOrigTypeArguments)).setParent(arktsArrayType); + } + + return arktsArrayType; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/BinaryExpression.java b/migrator/src/com/ohos/migrator/apimapper/BinaryExpression.java new file mode 100644 index 000000000..db2663e18 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/BinaryExpression.java @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.MultiplicativeExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.AdditiveExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.BitShiftExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.RelationalExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.EqualityExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.BitAndExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.BitXOrExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.BitOrExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.LogicalAndExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.LogicalOrExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.ShiftOperatorContext; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import static com.ohos.migrator.apimapper.Util.*; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// // The two operands of the operation which could be either: +// // The source Argument with the specified index. +// // or any of possible literals +// // or any of the suitable SingleExpressions which may use source arguments to form the expression. +// +public class BinaryExpression { + static public String tag = "BinaryExpression"; + private enum Operation { + MULTIPLY, DIVIDE, REMAINDER, PLUS, MINUS, SHIFT_LEFT, SHIFT_RIGHT, UNSIGN_SHIFT_RIGH, LESS, LESS_EQUAL, EQUAL, NOT_EQUAL, + MORE_EQUAL, MORE, BIT_AND, BIT_XOR, BIT_OR, AND, OR + } + + private Object operand1 = null; + private Object operand2 = null; + private Operation operation; + + private void setOperand(Object op) { + if (operand1 == null) { + operand1 = op; + } + else { + assert operand2 == null; + operand2 = op; + } + } + + static BinaryExpression read(XMLEventReader xmlReader, XMLEvent xmlBinaryExpressionEvent) throws XMLStreamException { + BinaryExpression binaryExpression = new BinaryExpression(); + + assert xmlBinaryExpressionEvent.isStartElement(); + StartElement startBinaryExpressionElement = xmlBinaryExpressionEvent.asStartElement(); + + String op = getAttribute(startBinaryExpressionElement, operationAttr); + + if ("*".equals(op)) { + binaryExpression.operation = Operation.MULTIPLY; + } + else if ("/".equals(op)) { + binaryExpression.operation = Operation.DIVIDE; + } else if ("%".equals(op)) { + binaryExpression.operation = Operation.REMAINDER; + } else if ("+".equals(op)) { + binaryExpression.operation = Operation.PLUS; + } else if ("-".equals(op)) { + binaryExpression.operation = Operation.MINUS; + } else if ("<<".equals(op)) { + binaryExpression.operation = Operation.SHIFT_LEFT; + } else if (">>".equals(op)) { + binaryExpression.operation = Operation.SHIFT_RIGHT; + } else if (">>>".equals(op)) { + binaryExpression.operation = Operation.UNSIGN_SHIFT_RIGH; + } else if ("<".equals(op)) { + binaryExpression.operation = Operation.LESS; + } else if ("<=".equals(op)) { + binaryExpression.operation = Operation.LESS_EQUAL; + } else if ("==".equals(op)) { + binaryExpression.operation = Operation.EQUAL; + } else if ("!=".equals(op)) { + binaryExpression.operation = Operation.NOT_EQUAL; + } else if (">=".equals(op)) { + binaryExpression.operation = Operation.MORE_EQUAL; + } else if (">".equals(op)) { + binaryExpression.operation = Operation.MORE; + } else if ("&".equals(op)) { + binaryExpression.operation = Operation.BIT_AND; + } else if ("^".equals(op)) { + binaryExpression.operation = Operation.BIT_XOR; + } else if ("|".equals(op)) { + binaryExpression.operation = Operation.BIT_OR; + } else if ("&&".equals(op)) { + binaryExpression.operation = Operation.AND; + } else if ("||".equals(op)) { + binaryExpression.operation = Operation.OR; + } else { + assert false; + } + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("SrcArgument".equals(tag)) { + binaryExpression.setOperand(Integer.valueOf(getAttribute(startElement, indexAttr))); + } + else if (Literal.tag.equals(tag)) { + binaryExpression.setOperand(Literal.read(xmlReader, xmlEvent)); + } + else if (CallExpression.tag.equals(tag)) { + binaryExpression.setOperand(CallExpression.read(xmlReader, xmlEvent)); + } + else if (UnaryExpression.tag.equals(tag)) { + binaryExpression.setOperand(UnaryExpression.read(xmlReader, xmlEvent)); + } + else if (BinaryExpression.tag.equals(tag)) { + binaryExpression.setOperand(BinaryExpression.read(xmlReader, xmlEvent)); + } + else if (TernaryExpression.tag.equals(tag)) { + binaryExpression.setOperand(TernaryExpression.read(xmlReader, xmlEvent)); + } + else if (ThisExpression.tag.equals(tag)) { + binaryExpression.setOperand(ThisExpression.read(xmlReader, xmlEvent)); + } + else if (SuperExpression.tag.equals(tag)) { + binaryExpression.setOperand(SuperExpression.read(xmlReader, xmlEvent)); + } + else if (ArrayLiteralExpression.tag.equals(tag)) { + binaryExpression.setOperand(ArrayLiteralExpression.read(xmlReader, xmlEvent)); + } + else if (CastExpression.tag.equals(tag)) { + binaryExpression.setOperand(CastExpression.read(xmlReader, xmlEvent)); + } + else + assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (BinaryExpression.tag.equals(tag)) { + break; + } + else { + assert ("SrcArgument".equals(tag) || Literal.tag.equals(tag) || CallExpression.tag.equals(tag) + || UnaryExpression.tag.equals(tag) || BinaryExpression.tag.equals(tag) + || TernaryExpression.tag.equals(tag) || ThisExpression.tag.equals(tag) + || SuperExpression.tag.equals(tag) || ArrayLiteralExpression.tag.equals(tag) + || CastExpression.tag.equals(tag)); + } + } + } + + return binaryExpression; + } + + static private ParserRuleContext buildArktsOperandNode(Object operand, List arktsOrigArguments) { + ParserRuleContext arktsOperand = null; + + if (operand instanceof Integer) { + int index = (Integer)operand; + assert (arktsOrigArguments != null); + assert (arktsOrigArguments.size() > index); + + arktsOperand = (ParserRuleContext)arktsOrigArguments.get(index); + } + else if (operand instanceof Literal) { + arktsOperand = ((Literal)operand).buildArktsNode(); + } + else if (operand instanceof CallExpression) { + arktsOperand = ((CallExpression)operand).buildArktsNode(null, arktsOrigArguments); + } + else if (operand instanceof UnaryExpression) { + arktsOperand = ((UnaryExpression)operand).buildArktsNode(arktsOrigArguments); + } + else if (operand instanceof BinaryExpression) { + arktsOperand = ((BinaryExpression)operand).buildArktsNode(arktsOrigArguments); + } + else if (operand instanceof TernaryExpression) { + arktsOperand = ((TernaryExpression)operand).buildArktsNode(arktsOrigArguments); + } + else if (operand instanceof ThisExpression) { + arktsOperand = ((ThisExpression)operand).buildArktsNode(); + } + else if (operand instanceof SuperExpression) { + arktsOperand = ((SuperExpression)operand).buildArktsNode(); + } + else if (operand instanceof ArrayLiteralExpression) { + arktsOperand = ((ArrayLiteralExpression)operand).buildArktsNode(arktsOrigArguments); + } + else if (operand instanceof CastExpression) { + arktsOperand = ((CastExpression)operand).buildArktsNode(arktsOrigArguments); + } + else + assert false; + + return arktsOperand; + } + + private ShiftOperatorContext shiftOperator() { + StaticTSParser.ShiftOperatorContext arktsShiftOp = new StaticTSParser.ShiftOperatorContext(null, 0); + + if (operation == Operation.SHIFT_LEFT) { + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.LessThan)); + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.LessThan)); + } + else if (operation == Operation.SHIFT_RIGHT) { + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.MoreThan)); + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.MoreThan)); + } + else if (operation == Operation.UNSIGN_SHIFT_RIGH) { + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.MoreThan)); + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.MoreThan)); + arktsShiftOp.addChild(NodeBuilder.terminalNode(StaticTSParser.MoreThan)); + } + + return arktsShiftOp; + } + + private int arktsOperatorType() { + int arktsOperator = -1; + + if (operation == Operation.MULTIPLY) arktsOperator = StaticTSParser.Multiply; + else if (operation == Operation.DIVIDE) arktsOperator = StaticTSParser.Divide; + else if (operation == Operation.REMAINDER) arktsOperator = StaticTSParser.Modulus; + else if (operation == Operation.PLUS) arktsOperator = StaticTSParser.Plus; + else if (operation == Operation.MINUS) arktsOperator = StaticTSParser.Minus; + else if (operation == Operation.LESS) arktsOperator = StaticTSParser.LessThan; + else if (operation == Operation.MORE) arktsOperator = StaticTSParser.MoreThan; + else if (operation == Operation.LESS_EQUAL) arktsOperator = StaticTSParser.LessThanEquals; + else if (operation == Operation.MORE_EQUAL) arktsOperator = StaticTSParser.GreaterThanEquals; + else if (operation == Operation.EQUAL) arktsOperator = StaticTSParser.Equals; + else if (operation == Operation.NOT_EQUAL) arktsOperator = StaticTSParser.NotEquals; + else if (operation == Operation.AND) arktsOperator = StaticTSParser.BitAnd; + else if (operation == Operation.BIT_XOR) arktsOperator = StaticTSParser.BitXor; + else if (operation == Operation.OR) arktsOperator = StaticTSParser.BitOr; + else if (operation == Operation.AND) arktsOperator = StaticTSParser.And; + else if (operation == Operation.OR) arktsOperator = StaticTSParser.Or; + + assert(arktsOperator != -1); + + return arktsOperator; + } + + private ParseTree createArktsInfixOperator() { + if (operation == Operation.SHIFT_LEFT || operation == Operation.SHIFT_RIGHT || operation == Operation.UNSIGN_SHIFT_RIGH) + return shiftOperator(); + else + return NodeBuilder.terminalNode(arktsOperatorType()); + } + + public SingleExpressionContext buildArktsNode(List arktsOrigArguments) { + SingleExpressionContext arktsBinExprParent = new SingleExpressionContext(); + SingleExpressionContext arktsBinExpr = null; + int arktsOpCode = -1; + + switch (operation) { + case MULTIPLY: + arktsBinExpr = new MultiplicativeExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Multiply; + break; + + case DIVIDE: + arktsBinExpr = new MultiplicativeExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Divide; + break; + + case PLUS: + arktsBinExpr = new AdditiveExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Plus; + break; + + case MINUS: + arktsBinExpr = new AdditiveExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Minus; + break; + + case SHIFT_LEFT: + arktsBinExpr = new BitShiftExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.LeftShiftArithmeticAssign; + break; + + case SHIFT_RIGHT: + arktsBinExpr = new BitShiftExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.RightShiftArithmeticAssign; + break; + + case UNSIGN_SHIFT_RIGH: + arktsBinExpr = new BitShiftExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.RightShiftLogicalAssign; + break; + + case LESS: + arktsBinExpr = new RelationalExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.LessThan; + break; + + case LESS_EQUAL: + arktsBinExpr = new RelationalExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.LessThanEquals; + break; + + case EQUAL: + arktsBinExpr = new EqualityExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Equals; + break; + + case NOT_EQUAL: + arktsBinExpr = new EqualityExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.NotEquals; + break; + + case MORE_EQUAL: + arktsBinExpr = new RelationalExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.GreaterThanEquals; + break; + + case MORE: + arktsBinExpr = new RelationalExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.MoreThan; + break; + + case BIT_AND: + arktsBinExpr = new BitAndExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.BitAnd; + break; + + case BIT_XOR: + arktsBinExpr = new BitXOrExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.BitXor; + break; + + case BIT_OR: + arktsBinExpr = new BitOrExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.BitOr; + break; + + case AND: + arktsBinExpr = new LogicalAndExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.And; + break; + + case OR: + arktsBinExpr = new LogicalOrExpressionContext(arktsBinExprParent); + arktsOpCode = StaticTSParser.Or; + break; + } + + arktsBinExpr.addChild(buildArktsOperandNode(operand1, arktsOrigArguments)).setParent(arktsBinExpr); + arktsBinExpr.addAnyChild(createArktsInfixOperator()).setParent(arktsBinExpr); + arktsBinExpr.addChild(buildArktsOperandNode(operand2, arktsOrigArguments)).setParent(arktsBinExpr); + + assert (arktsBinExpr != null); + return arktsBinExprParent; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/CallExpression.java b/migrator/src/com/ohos/migrator/apimapper/CallExpression.java new file mode 100644 index 000000000..7a0526458 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/CallExpression.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import org.antlr.v4.runtime.tree.ParseTree; + +import static com.ohos.migrator.staticTS.parser.StaticTSParser.CallExpressionContext; +import static com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import static com.ohos.migrator.staticTS.parser.StaticTSParser.MemberAccessExpressionContext; +import static com.ohos.migrator.staticTS.parser.StaticTSParser.IdentifierExpressionContext; +import static com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; + +import static com.ohos.migrator.apimapper.Util.javaMethodNameAttr; +import static com.ohos.migrator.apimapper.Util.getAttribute; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// | singleExpression typeArguments? arguments # CallExpression +// +// +// +// +public class CallExpression { + static public String tag = "CallExpression"; + + private String arktsMethodName = null; + private TypeReference typeReference = null; // Optional. Type of the class/interface for static methods. + private TypeArguments typeArguments = null; + private Arguments arguments = null; + + static CallExpression read(XMLEventReader xmlReader, XMLEvent xmlCallExpressionEvent) throws XMLStreamException { + CallExpression callExpression = new CallExpression(); + + StartElement callExpressionElement = xmlCallExpressionEvent.asStartElement(); + callExpression.arktsMethodName = getAttribute(callExpressionElement, javaMethodNameAttr); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + callExpression.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else if (TypeArguments.tag.equals(tag)) { + callExpression.typeArguments = TypeArguments.read(xmlReader); + } + else if (Arguments.tag.equals(tag)) { + callExpression.arguments = Arguments.read(xmlReader, xmlEvent); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (CallExpression.tag.equals(tag)) { + break; + } + else { + assert (TypeArguments.tag.equals(tag) || Arguments.tag.equals(tag)); + } + } + } + + return callExpression; + } + + public SingleExpressionContext buildArktsNode(List arktsOrigTypeArguments, List arktsOrigArguments) { + SingleExpressionContext arktsCallExpressionParent = new SingleExpressionContext(); + CallExpressionContext arktsCallExpression = new CallExpressionContext(arktsCallExpressionParent); + arktsCallExpression.setParent(arktsCallExpressionParent); + + String arktsTypeName = (typeReference != null) ? typeReference.getArktsName() : null; + + if (arktsTypeName != null) { + // | singleExpression Dot identifier # MemberAccessExpression + SingleExpressionContext arktsSingleExpression = new SingleExpressionContext(); + MemberAccessExpressionContext arktsMemberAccessExpression = new MemberAccessExpressionContext(arktsSingleExpression); + arktsMemberAccessExpression.setParent(arktsSingleExpression); + arktsCallExpression.addChild(arktsSingleExpression).setParent(arktsCallExpression); + + arktsMemberAccessExpression.addChild(NodeBuilder.typeReference(arktsTypeName)).setParent(arktsMemberAccessExpression); + + arktsMemberAccessExpression.addChild(NodeBuilder.terminalIdentifier(arktsMethodName)); + } + else { + SingleExpressionContext arktsSingleExpression = new SingleExpressionContext(); + IdentifierExpressionContext arktsIdentifierExpression = new IdentifierExpressionContext(arktsSingleExpression); + arktsCallExpression.addChild(arktsIdentifierExpression).setParent(arktsCallExpression); + arktsIdentifierExpression.setParent(arktsSingleExpression); + arktsIdentifierExpression.addChild(NodeBuilder.terminalIdentifier(arktsMethodName)); + } + + if (typeArguments != null) { + arktsCallExpression.addChild(typeArguments.buildArktsNode(arktsOrigTypeArguments)).setParent(arktsCallExpression); + } + + if (arguments != null) { + arktsCallExpression.addChild(arguments.buildArktsNode(arktsOrigTypeArguments, arktsOrigArguments)).setParent(arktsCallExpression); + } + + return arktsCallExpressionParent; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/CastExpression.java b/migrator/src/com/ohos/migrator/apimapper/CastExpression.java new file mode 100644 index 000000000..ce1f9218a --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/CastExpression.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.CastExpressionContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import static com.ohos.migrator.apimapper.Util.*; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// // | singleExpression As (intersectionType | primaryType) # CastExpression +// +// +// +// +public class CastExpression { + static public String tag = "CastExpression"; + + private int index; + private PrimaryType primaryType = null; + private IntersectionType intersectionType = null; + + static CastExpression read(XMLEventReader xmlReader, XMLEvent xmlCastExpressionEvent) throws XMLStreamException { + CastExpression castExpression = new CastExpression(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("SrcArgument".equals(tag)) { + castExpression.index = Integer.valueOf(getAttribute(startElement, indexAttr)); + } + else if (PrimaryType.tag.equals(tag)) { + castExpression.primaryType = PrimaryType.read(xmlReader, xmlEvent); + } + else if (IntersectionType.tag.equals(tag)) { + castExpression.intersectionType = IntersectionType.read(xmlReader, xmlEvent); + } + else + assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (CastExpression.tag.equals(tag)) { + break; + } + else { + assert ("SrcArgument".equals(tag) || PrimaryType.tag.equals(tag) || IntersectionType.tag.equals(tag)); + } + } + } + + return castExpression; + } + + public SingleExpressionContext buildArktsNode(List arktsOrigArguments) { + assert (arktsOrigArguments != null); + assert (index >= 0 && arktsOrigArguments.size() > index); + + SingleExpressionContext arktsCastExprParent = new SingleExpressionContext(); + CastExpressionContext arktsCastExpr = new CastExpressionContext(arktsCastExprParent); + + arktsCastExpr.children.add(arktsOrigArguments.get(index)); + arktsCastExpr.addChild(NodeBuilder.terminalNode(StaticTSParser.As)); + + if (primaryType != null ) { + arktsCastExpr.addChild(primaryType.buildArktsNode()); + } + else { + assert (intersectionType != null); + arktsCastExpr.addChild(intersectionType.buildArktsNode()); + } + + return arktsCastExprParent; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/IntersectionType.java b/migrator/src/com/ohos/migrator/apimapper/IntersectionType.java new file mode 100644 index 000000000..27a3887bd --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/IntersectionType.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.staticTS.parser.StaticTSParser.IntersectionTypeContext; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import java.util.ArrayList; +import java.util.List; + +// intersectionType: OpenParen typeReference (BitAnd typeReference)+ CloseParen +public class IntersectionType { + static public String tag = "IntersectionType"; + + List types = new ArrayList<>(); + + static IntersectionType read(XMLEventReader xmlReader, XMLEvent xmlIntersectionTypeEvent) throws XMLStreamException { + IntersectionType intersectionType = new IntersectionType(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + intersectionType.types.add(TypeReference.read(xmlReader, xmlEvent)); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (IntersectionType.tag.equals(tag)) { + break; + } + else { + assert (TypeReference.tag.equals(tag)); + } + } + } + + return intersectionType; + } + + public IntersectionTypeContext buildArktsNode() { + IntersectionTypeContext arktsIntersectionType = new IntersectionTypeContext(null, 0); + + for(TypeReference typeReference : types) { + arktsIntersectionType.addChild(typeReference.buildArktsNode(null)).setParent(arktsIntersectionType); + } + + return arktsIntersectionType; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/Literal.java b/migrator/src/com/ohos/migrator/apimapper/Literal.java new file mode 100644 index 000000000..e26f4a5cc --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/Literal.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +// + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +public class Literal { + static public String tag = "Literal"; + + private enum Type { + NULL, BOOLEAN, STRING, CHAR, DECIMAL, HEXINTEGER, OCTALINTEGER, BINARYINTEGER + } + + private Type type; + private String value = null; + + static private QName typeAttr = new QName("type"); + static private QName valueAttr = new QName("value"); + + static Literal read(XMLEventReader xmlReader, XMLEvent xmlLiteralEvent) throws XMLStreamException { + Literal literal = new Literal(); + + assert (xmlLiteralEvent.isStartElement()); + StartElement startElement = xmlLiteralEvent.asStartElement(); + + String tp = Util.getAttribute(startElement, typeAttr); + + if ("null".equals(tp)) { + literal.type = Type.NULL; + } + else if ("boolean".equals(tp)) { + literal.type = Type.BOOLEAN; + } + else if ("string".equals(tp)) { + literal.type = Type.STRING; + } + else if ("char".equals(tp)) { + literal.type = Type.CHAR; + } + else if ("decimal".equals(tp)) { + literal.type = Type.DECIMAL; + } + else if ("hexInteger".equals(tp)) { + literal.type = Type.HEXINTEGER; + } + else if ("octalInteger".equals(tp)) { + literal.type = Type.OCTALINTEGER; + } + else if ("binaryInteger".equals(tp)) { + literal.type = Type.BINARYINTEGER; + } + else { + assert false; + } + + literal.value = Util.getAttribute(startElement, valueAttr); + + // Read the end event. + assert (xmlReader.hasNext()); + XMLEvent xmlEvent = xmlReader.nextEvent(); + assert xmlEvent.isEndElement(); + EndElement endElement = xmlEvent.asEndElement(); + assert Literal.tag.equals(endElement.getName().getLocalPart()); + + return literal; + } + + public StaticTSParser.SingleExpressionContext buildArktsNode() { + switch (type) { + case NULL: return NodeBuilder.nullLiteral(); + case BOOLEAN: return NodeBuilder.boolLiteral(Boolean.parseBoolean(value)); + case STRING: return NodeBuilder.stringLiteral(value); + case CHAR: return NodeBuilder.charLiteral(value); + case DECIMAL: + case HEXINTEGER: + case OCTALINTEGER: + case BINARYINTEGER: return NodeBuilder.numericLiteral(value); + } + + assert false; + return null; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/PrimaryType.java b/migrator/src/com/ohos/migrator/apimapper/PrimaryType.java new file mode 100644 index 000000000..83e4f0efd --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/PrimaryType.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser.PrimaryTypeContext; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +// primaryType: predefinedType | typeReference | arrayType; + +public class PrimaryType { + static public String tag = "PrimaryType"; + + private String predefinedType = null; + private TypeReference typeReference = null; + private ArrayType arrayType = null; + + static PrimaryType read(XMLEventReader xmlReader, XMLEvent xmlPrimaryTypeEveent) throws XMLStreamException { + PrimaryType primaryType = new PrimaryType(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("PredefinedType".equals(tag)) { + primaryType.predefinedType = Util.getAttribute(startElement, Util.nameAttr); + } + else if (TypeReference.tag.equals(tag)) { + primaryType.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else if (ArrayType.tag.equals(tag)) { + primaryType.arrayType = ArrayType.read(xmlReader); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (PrimaryType.tag.equals(tag)) { + break; + } + else { + assert ("PredefinedType".equals(tag) || TypeReference.tag.equals(tag) || ArrayType.tag.equals(tag)); + } + } + } + + return primaryType; + } + + public PrimaryTypeContext buildArktsNode() { + PrimaryTypeContext arktsPrimaryType = new PrimaryTypeContext(null, 0); + + if (!Util.isStringEmpty(predefinedType)) { + arktsPrimaryType.addChild(NodeBuilder.predefinedType(predefinedType)).setParent(arktsPrimaryType); + } + else if (typeReference != null) { + arktsPrimaryType.addChild(typeReference.buildArktsNode(null)).setParent(arktsPrimaryType); + } + else { + assert (arrayType != null); + arktsPrimaryType.addChild(arrayType.buildArktsNode(null)).setParent(arktsPrimaryType); + } + + return arktsPrimaryType; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/SuperExpression.java b/migrator/src/com/ohos/migrator/apimapper/SuperExpression.java new file mode 100644 index 000000000..edc822c76 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/SuperExpression.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +// +// +// // Optional +// +public class SuperExpression { + static public String tag = "SuperExpression"; + + private TypeReference typeReference = null; + + static SuperExpression read(XMLEventReader xmlReader, XMLEvent xmlThisExpressionEvent) throws XMLStreamException { + SuperExpression superExpression = new SuperExpression(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + superExpression.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else { + assert false; + } + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (SuperExpression.tag.equals(tag)) { + break; + } + else { + assert (TypeReference.tag.equals(tag)); + } + } + } + + return superExpression; + } + + public StaticTSParser.SingleExpressionContext buildArktsNode() { + return NodeBuilder.superExpression(typeReference.buildArktsNode(null)); + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/TernaryExpression.java b/migrator/src/com/ohos/migrator/apimapper/TernaryExpression.java new file mode 100644 index 000000000..8e79f3728 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/TernaryExpression.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.staticTS.parser.StaticTSParser.TernaryExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// // The tree operands which form the TernaryExpression and could be any of: +// +// // Optional +// +public class ThisExpression { + static public String tag = "ThisExpression"; + + private TypeReference typeReference = null; + + static ThisExpression read(XMLEventReader xmlReader, XMLEvent xmlThisExpressionEvent) throws XMLStreamException { + ThisExpression thisExpression = new ThisExpression(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + thisExpression.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else { + assert false; + } + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (ThisExpression.tag.equals(tag)) { + break; + } + else { + assert (TypeReference.tag.equals(tag)); + } + } + } + + return thisExpression; + } + + public SingleExpressionContext buildArktsNode() { + return NodeBuilder.thisExpression(typeReference.buildArktsNode(null)); + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/TypeArguments.java b/migrator/src/com/ohos/migrator/apimapper/TypeArguments.java new file mode 100644 index 000000000..7438f62a6 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/TypeArguments.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentsContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentListContext; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.ArrayList; +import java.util.List; + +// +// +// +// // Optional type arguments. Any sequence of children of following types: +// +// // Look below for the structure of arrayType element. +// // Look below for the structure of wildcardType element. +// +// +// +// +// // or +// // Look above for the structure of typeReference element. +// +// +// // Optional. If not specified then only a question mark will be used as the wildcard type. +// // Look above for the structure of typeReference element. +// +// +// +public class TypeArguments { + static public String tag = "TypeArguments"; + + // The list of arguments. Its elements could be any of: + // - Integer - index of the source TypeArgumens list. + // - TypeReference + // - ArrayType + // - WildcardType + private List arguments = new ArrayList<>(); + + static public TypeArguments read(XMLEventReader xmlReader) throws XMLStreamException { + TypeArguments typeArguments = new TypeArguments(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("SrcTypeArgument".equals(tag)) { + typeArguments.arguments.add(Integer.valueOf(Util.getAttribute(startElement, Util.indexAttr))); + } + else if (TypeReference.tag.equals(tag)) { + typeArguments.arguments.add(TypeReference.read(xmlReader, xmlEvent)); + } + else if (ArrayType.tag.equals(tag)) { + typeArguments.arguments.add(ArrayType.read(xmlReader)); + } + else if (WildcardType.tag.equals(tag)) { + typeArguments.arguments.add(WildcardType.read(xmlReader, xmlEvent)); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (TypeArguments.tag.equals(tag)) { + break; + } + else { + assert ("SrcTypeArgument".equals(tag) || TypeReference.tag.equals(tag) || ArrayType.tag.equals(tag) + || WildcardType.tag.equals(tag)); + } + } + } + + return typeArguments; + } + + // ArkTS Tree: + // typeArguments: LessThan typeArgumentList? MoreThan + // typeArgumentList: typeArgument (Comma typeArgument)* + // typeArgument: typeReference | arrayType | wildcardType + public TypeArgumentsContext buildArktsNode(List arktsOrigTypeArguments) {//{List javaTypeArgs) { + TypeArgumentsContext arktsTypeArguments = new TypeArgumentsContext(null, 0); + + TypeArgumentListContext arktsTypeArgumentList = new TypeArgumentListContext(arktsTypeArguments, 0); + arktsTypeArguments.addChild(arktsTypeArgumentList); + + for (Object arg : arguments) { + TypeArgumentContext arktsTypeArgument = new TypeArgumentContext(null, 0); + arktsTypeArgumentList.addChild(arktsTypeArgument).setParent(arktsTypeArgumentList); + + if (arg instanceof Integer) { + assert (arktsOrigTypeArguments != null); + Integer index = (Integer)arg; + arktsTypeArgument.children.add(arktsOrigTypeArguments.get(index)); + } + else if (arg instanceof TypeReference) { + arktsTypeArgument.addChild(((TypeReference)arg).buildArktsNode(arktsOrigTypeArguments)).setParent(arktsTypeArgument); + } + else if (arg instanceof ArrayType) { + arktsTypeArgument.addChild(((ArrayType)arg).buildArktsNode(arktsOrigTypeArguments)).setParent(arktsTypeArgument); + } + else if (arg instanceof WildcardType) { + arktsTypeArgument.addChild(((WildcardType)arg).buildArktsNode(arktsOrigTypeArguments)).setParent(arktsTypeArgument); + } + else + assert false; + } + + return arktsTypeArguments; + } + +} diff --git a/migrator/src/com/ohos/migrator/apimapper/TypeReference.java b/migrator/src/com/ohos/migrator/apimapper/TypeReference.java new file mode 100644 index 000000000..7c96ecfec --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/TypeReference.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeReferenceContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// // Optional type arguments. Any sequence of children of following types: +// +// // Look ArrayType class for details. +// // Look WildcardType class for details. +// +// +public class TypeReference { + static public String tag = "TypeReference"; + private String arktsName = null; + private TypeArguments typeArguments = null; + + public String getArktsName() { + return arktsName; + } + + static public TypeReference read(XMLEventReader xmlReader, XMLEvent xmlTypeReferenceEvent) throws XMLStreamException { + TypeReference typeReference = new TypeReference(); + + assert xmlTypeReferenceEvent.isStartElement(); + StartElement startElement = xmlTypeReferenceEvent.asStartElement(); + typeReference.arktsName = Util.getAttribute(startElement, Util.arktsNameAttr); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeArguments.tag.equals(tag)) { + typeReference.typeArguments = TypeArguments.read(xmlReader); + } + else + assert false : " may has as a child only ."; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + break; + } + else { + assert (TypeArguments.tag.equals(tag)); + } + } + } + + return typeReference; + } + + public TypeReferenceContext buildArktsNode(List arktsOrigTypeArguments) { + TypeReferenceContext arktsTypeReference = NodeBuilder.typeReference(arktsName); + + if (typeArguments != null) { + arktsTypeReference.addChild(typeArguments.buildArktsNode(arktsOrigTypeArguments)).setParent(arktsTypeReference); + } + + return arktsTypeReference; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/UnaryExpression.java b/migrator/src/com/ohos/migrator/apimapper/UnaryExpression.java new file mode 100644 index 000000000..26c476104 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/UnaryExpression.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +// + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.SingleExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.UnaryPlusExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.UnaryMinusExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.NotExpressionContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.BitNotExpressionContext; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.tree.ParseTree; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +public class UnaryExpression { + static public String tag = "UnaryExpression"; + private enum Operation { + MINUS, PLUS, BIT_NOT, NOT + } + + private int index = -1; + private Operation operation; + + static UnaryExpression read(XMLEventReader xmlReader, XMLEvent xmlUnaryExpressionEvent) throws XMLStreamException { + UnaryExpression unaryExpression = new UnaryExpression(); + + assert xmlUnaryExpressionEvent.isStartElement(); + StartElement startElement = xmlUnaryExpressionEvent.asStartElement(); + + unaryExpression.index = Integer.valueOf(Util.getAttribute(startElement, Util.indexAttr)); + + String op = Util.getAttribute(startElement, Util.operationAttr); + + if ("+".equals(op)) { + unaryExpression.operation = Operation.PLUS; + } else if ("-".equals(op)) { + unaryExpression.operation = Operation.MINUS; + } else if ("~".equals(op)) { + unaryExpression.operation = Operation.BIT_NOT; + } else if ("!".equals(op)) { + unaryExpression.operation = Operation.NOT; + } else { + assert false; + } + + // Read the end event. + assert (xmlReader.hasNext()); + XMLEvent xmlEvent = xmlReader.nextEvent(); + assert xmlEvent.isEndElement(); + EndElement endElement = xmlEvent.asEndElement(); + assert UnaryExpression.tag.equals(endElement.getName().getLocalPart()); + + return unaryExpression; + } + + public SingleExpressionContext buildArktsNode(List arktsOrigArguments) { + assert (index >= 0); + assert (arktsOrigArguments != null); + assert (arktsOrigArguments.size() > index); + + SingleExpressionContext arktsUnaryExprParent = new SingleExpressionContext(); + SingleExpressionContext arktsUnaryExpr = null; + + int arktsOpType = -1; + + switch (operation) + { + case PLUS: + arktsUnaryExpr = new UnaryPlusExpressionContext(arktsUnaryExprParent); + arktsOpType = StaticTSParser.Plus; + break; + + case MINUS: + arktsUnaryExpr = new UnaryMinusExpressionContext(arktsUnaryExprParent); + arktsOpType = StaticTSParser.Minus; + break; + + case NOT: + arktsUnaryExpr = new NotExpressionContext(arktsUnaryExprParent); + arktsOpType = StaticTSParser.Not; + break; + + case BIT_NOT: + arktsUnaryExpr = new BitNotExpressionContext(arktsUnaryExprParent); + arktsOpType = StaticTSParser.BitNot; + break; + } + + assert (arktsUnaryExpr != null); + + arktsUnaryExpr.addChild(NodeBuilder.terminalNode(arktsOpType)); + + arktsUnaryExpr.addChild((RuleContext)arktsOrigArguments.get(index)); + + return arktsUnaryExprParent; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/Util.java b/migrator/src/com/ohos/migrator/apimapper/Util.java new file mode 100644 index 000000000..d01d367e2 --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/Util.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser.MemberAccessExpressionContext; + +import javax.xml.namespace.QName; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.StartElement; + +public class Util { + static public QName indexAttr = new QName("index"); + static public QName nameAttr = new QName("name"); + static public QName valueAttr = new QName("value"); + static public QName operationAttr = new QName("operation"); + static public QName typeAttr = new QName("type"); + static public QName javaMethodNameAttr = new QName("javaMethodName"); + static public QName javaMemberNameAttr = new QName("javaMemberName"); + static public QName javaObjectTypeAttr = new QName("javaObjectType"); + static public QName javaObjectTypeArgsAttr = new QName("javaObjectTypeArgs"); + static public QName javaMethodTypeArgsAttr = new QName("javaMethodTypeArgs"); + static public QName javaMethodArgsAttr = new QName("javaMethodArgs"); + static public QName javaPackageAttr = new QName("javaPackage"); + static public QName arktsNameAttr = new QName("arktsName"); + static public QName arktsPackageAttr = new QName("arktsPackage"); + + static public boolean isStringEmpty(String s) { + return (s == null || s.isEmpty()); + } + + // | singleExpression Dot Identifier #MemberAccessExpression + static public void rebuildMemberAccessExpression(MemberAccessExpressionContext arktsMemberAccessExpr, String arktsNewType, String arktsNewName, TypeArguments newTypeArguments) { + if (!isStringEmpty(arktsNewName)) { + int i = arktsMemberAccessExpr.children.indexOf(arktsMemberAccessExpr.Identifier()); + arktsMemberAccessExpr.children.remove(i); + arktsMemberAccessExpr.children.add(i, NodeBuilder.terminalIdentifier(arktsNewName)); + } + + if (!isStringEmpty(arktsNewType)) { + // TODO: + } + + if (newTypeArguments != null) { + // TODO: + } + } + + static public String getAttribute(StartElement element, QName attrName) { + Attribute attribute = element.getAttributeByName(attrName); + return attribute != null ? attribute.getValue() : null; + } +} diff --git a/migrator/src/com/ohos/migrator/apimapper/WildcardType.java b/migrator/src/com/ohos/migrator/apimapper/WildcardType.java new file mode 100644 index 000000000..33945d51a --- /dev/null +++ b/migrator/src/com/ohos/migrator/apimapper/WildcardType.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.apimapper; + +import com.ohos.migrator.java.NodeBuilder; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.WildcardTypeContext; +import com.ohos.migrator.staticTS.parser.StaticTSParser.TypeArgumentContext; +import static com.ohos.migrator.apimapper.Util.isStringEmpty; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.List; + +// +// // Optional bounds. If it's not specified then only a question mark will be used as the wildcard type. +// // Look TypeReference class for details. +// +// +public class WildcardType { + static public String tag = "WildcardType"; + private String type = null; + private TypeReference typeReference = null; + + static WildcardType read(XMLEventReader xmlReader, XMLEvent xmlWildcardTypeEvent) throws XMLStreamException { + WildcardType wildcardType = new WildcardType(); + + if (!xmlWildcardTypeEvent.isEndElement()) { + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("WildcardBound".equals(tag)) { + wildcardType.type = Util.getAttribute(startElement, Util.typeAttr); + } + else if (TypeReference.tag.equals(tag)) { + wildcardType.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else + assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (WildcardType.tag.equals(tag)) { + break; + } + else { + assert ("WildcardBound".equals(tag) || TypeReference.tag.equals(tag)); + } + } + } + } + + return wildcardType; + } + + // ArkTS: + // wildcardType + // : { this.next(IN) }? Identifier typeReference + // | { this.next(OUT) }? Identifier typeReference? + + // List arktsOrigTypeArguments + public WildcardTypeContext buildArktsNode(List arktsOrigTypeArguments) { + WildcardTypeContext arktsWildcardType = new WildcardTypeContext(null, 0); + + if (isStringEmpty(type)) { + assert (type.equals(StaticTSParser.OUT) || type.equals(StaticTSParser.IN)); + + arktsWildcardType.addChild(NodeBuilder.terminalIdentifier(type)); + + if (typeReference != null) { + arktsWildcardType.addChild(typeReference.buildArktsNode(arktsOrigTypeArguments)).setParent(arktsWildcardType); + } + } + + return arktsWildcardType; + } +} diff --git a/migrator/src/com/ohos/migrator/java/JavaApiMapper.java b/migrator/src/com/ohos/migrator/java/JavaApiMapper.java new file mode 100644 index 000000000..bedb0ec93 --- /dev/null +++ b/migrator/src/com/ohos/migrator/java/JavaApiMapper.java @@ -0,0 +1,810 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.java; + +import com.ohos.migrator.apimapper.*; +import com.ohos.migrator.staticTS.NodeBuilderBase; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.*; +import static com.ohos.migrator.apimapper.Util.isStringEmpty; +import static com.ohos.migrator.apimapper.Util.rebuildMemberAccessExpression; +import static com.ohos.migrator.apimapper.Util.getAttribute; +import static com.ohos.migrator.apimapper.Util.javaPackageAttr; +import static com.ohos.migrator.apimapper.Util.arktsPackageAttr; +import static com.ohos.migrator.apimapper.Util.javaObjectTypeAttr; +import static com.ohos.migrator.apimapper.Util.javaObjectTypeArgsAttr; +import static com.ohos.migrator.apimapper.Util.javaMethodArgsAttr; +import static com.ohos.migrator.apimapper.Util.javaMethodTypeArgsAttr; +import static com.ohos.migrator.apimapper.Util.javaMethodNameAttr; +import static com.ohos.migrator.apimapper.Util.valueAttr; +import static com.ohos.migrator.apimapper.Util.arktsNameAttr; + +import com.ohos.migrator.staticTS.parser.StaticTSParserBaseVisitor; +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.TerminalNodeImpl; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + + +public class JavaApiMapper extends StaticTSParserBaseVisitor { + static private StringBuilder sb = new StringBuilder(); + + // + // or + // + // + // // ... + // + static private class ImportDeclarationRule { + static public String tag = "ImportDeclarationRule"; + private String javaPackage = null; + private List arktsPackages = null; + + public void apply(ImportDeclarationContext arktsImportDeclatation) { + assert (arktsImportDeclatation.parent instanceof ParserRuleContext); + ParserRuleContext arktsParent = (ParserRuleContext)arktsImportDeclatation.parent; + + assert (arktsParent.children != null); + int index = arktsParent.children.indexOf(arktsImportDeclatation); + // The current importDeclaraion has to be removed in any case. + arktsParent.children.remove(arktsImportDeclatation); + + if (arktsPackages != null) { + // Add the new importDeclaraions. + for (String arktsPackage : arktsPackages) { + ImportDeclarationContext arktsImportDeclaration = new ImportDeclarationContext(arktsParent, 0); + arktsImportDeclaration.addChild(NodeBuilderBase.terminalNode(StaticTSParser.Import)); + arktsImportDeclaration.addChild(NodeBuilderBase.qualifiedName(arktsPackage)); + + // Add the new nodes on the place of the removed one. + arktsParent.children.add(index, arktsImportDeclaration); + } + } + } + + public void apply(CompilationUnitContext arktsCompilationUnit) { + assert (arktsPackages != null); + + ImportDeclarationContext arktsImportFirst = arktsCompilationUnit.importDeclaration(0); + int index = (arktsImportFirst != null) ? arktsCompilationUnit.children.indexOf(arktsImportFirst) : 0; + + // Add the new importDeclaraions. + for (String arktsPackage : arktsPackages) { + ImportDeclarationContext arktsImportDeclaration = new ImportDeclarationContext(arktsCompilationUnit, 0); + arktsImportDeclaration.addChild(NodeBuilderBase.terminalNode(StaticTSParser.Import)); + arktsImportDeclaration.addChild(NodeBuilderBase.qualifiedName(arktsPackage)); + + // Add the new nodes on the place of the removed one. + arktsCompilationUnit.children.add(index, arktsImportDeclaration); + } + } + + static public String signature(ImportDeclarationContext arktsImportDeclatation) { + return arktsImportDeclatation.javaPackage; + } + + public String signature(StartElement importDeclarationElement) { + javaPackage = getAttribute(importDeclarationElement, javaPackageAttr); + return javaPackage; + } + + static ImportDeclarationRule read(XMLEventReader xmlReader, XMLEvent xmlImportDeclarationRuleEvent, StartElement ruleStartElement) throws XMLStreamException { + ImportDeclarationRule rule = new ImportDeclarationRule(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + assert "ImportDeclaration".equals(startElement.getName().getLocalPart()) : " may has only child"; + String arktsPackage = getAttribute(startElement, arktsPackageAttr); + // The 'arktsPackage' may be not specified. In such case the rule/import is considered as a mandatory one. + // Corresponding import statement will be automatically added to each resulting code. + + if (rule.arktsPackages == null) { + rule.arktsPackages = new ArrayList<>(); + } + + rule.arktsPackages.add(arktsPackage); + } + else if (xmlEvent.isEndElement()) { + // It has to be either or + EndElement endElement = xmlEvent.asEndElement(); + if (ImportDeclarationRule.tag.equals(endElement.getName().getLocalPart())) { + break; + } + else { + // Just eat EndElement for element. + assert "ImportDeclaration".equals(endElement.getName().getLocalPart()); + } + } + } + + return rule; + } + } + + static private void renameIdentifier(IdentifierExpressionContext arktsIdentifier, String arktsNewName) { + arktsIdentifier.children.clear(); + arktsIdentifier.addChild(NodeBuilder.terminalIdentifier(arktsNewName)); + } + + // + // // Optional qualified name of ArkTS class or interface for a static + // // method call. If the method is a static one then it should be called + // // via qualified name of the class or interface. The class/interface in ArkTS may change. + // //Optional method rename. If it's not specified then the method name remains. + // // Optional list of new type arguments. If it's not specified then + // // the current type arguments remain. + // // Optional new list of arguments. If it's not specified then + // // the current arguments remain. + // + static private class CallExpressionRule { + static public String tag = "CallExpressionRule"; + + private String javaObjectType = null; + private String javaObjectTypeArgs = null; + private String javaMethodTypeArgs = null; + private String arktsTypeName = null; + private String arktsMethodName = null; + private TypeArguments arktsObjectTypeArgs = null; + private TypeArguments arktsMethodTypeArgs = null; + private Arguments arguments = null; + + public void apply(CallExpressionContext arktsCallExpression) { + SingleExpressionContext arktsExpression = arktsCallExpression.singleExpression(); + if (arktsMethodName != null) { + if (arktsExpression instanceof IdentifierExpressionContext) { + assert (arktsTypeName == null); + renameIdentifier((IdentifierExpressionContext)arktsExpression, arktsMethodName); + } + else if (arktsExpression instanceof SingleExpressionContext && (arktsTypeName != null || arktsMethodName != null)) { + assert arktsExpression.getChildCount() > 0; + ParseTree arktsChildNode = arktsExpression.getChild(0); + + if (arktsChildNode instanceof MemberAccessExpressionContext) { + rebuildMemberAccessExpression((MemberAccessExpressionContext)arktsChildNode, arktsTypeName, arktsMethodName, arktsObjectTypeArgs); + } + else assert false; // TODO: + } + } + + if (arktsMethodTypeArgs == null) { + // Java method is generic (has type arguments) and its ArtTS equivalent is NOT a generic one then + // just remove the type arguments. + TypeArgumentsContext arktsTypeArgs = arktsCallExpression.typeArguments(); + if (arktsTypeArgs != null) { + arktsCallExpression.children.remove(arktsTypeArgs); + } + } + else { + List arktsOgitTypeArgsList = null; + + TypeArgumentsContext arktsTypeArgs = arktsCallExpression.typeArguments(); + + if (arktsTypeArgs != null) { + TypeArgumentListContext arktsOrigTypeArgs = arktsTypeArgs.typeArgumentList(); + + if (arktsOrigTypeArgs == null) { + arktsOgitTypeArgsList = arktsOrigTypeArgs.typeArgument(); + } + } + + arktsCallExpression.children.remove(arktsTypeArgs); + arktsCallExpression.addChild(arktsMethodTypeArgs.buildArktsNode(arktsOgitTypeArgsList)); + } + + if (arguments != null) { + ExpressionSequenceContext arktsExpressionSequence = arktsCallExpression.arguments().expressionSequence(); + + // The list of arguments will be completely rebuild. At the same time new arguments may referes to some arguments + // from the old list. So preserve the old list of arguments. + List arktsOrigArguments = new ArrayList<>(arktsExpressionSequence.children); + + // Clear the current list of arguments... + arktsExpressionSequence.children.clear(); + // ...and build the new one based on the rule's list of arguments. + + List arktsOrigTypeArguments = null; + TypeArgumentsContext arktsTypeArguments = arktsCallExpression.typeArguments(); + if (arktsTypeArguments != null) { + arktsOrigTypeArguments = arktsTypeArguments.typeArgumentList().typeArgument(); + } + + arguments.rebuildArktsNode(arktsExpressionSequence, arktsOrigTypeArguments, arktsOrigArguments); + } + } + + static private String signature(String javaObjectType, String javaObjectTypeArgs, String javaMethodName, String javaMethodTypeArgs, String javaMethodArgs) { + sb.setLength(0); // Clear the StringBuilder. + + if (!isStringEmpty(javaObjectType)) { + sb.append(javaObjectType); + } + + sb.append('@'); + + if (!isStringEmpty(javaObjectTypeArgs)) { + sb.append(javaObjectTypeArgs); + } + + sb.append('@'); + + if (!isStringEmpty(javaMethodName)) { + sb.append(javaMethodName); + } + + sb.append('@'); + + if (!isStringEmpty(javaMethodTypeArgs)) { + sb.append(javaMethodTypeArgs); + } + + sb.append('@'); + + if (!isStringEmpty(javaMethodArgs)) { + sb.append(javaMethodArgs); + } + + return sb.toString(); + } + + public String signature(StartElement callExpressionElement) { + javaObjectType = getAttribute(callExpressionElement, javaObjectTypeAttr); + javaObjectTypeArgs = getAttribute(callExpressionElement, javaObjectTypeArgsAttr); + String javaMethodName = getAttribute(callExpressionElement, javaMethodNameAttr); + javaMethodTypeArgs = getAttribute(callExpressionElement, javaMethodTypeArgsAttr); + String javaMethodArgs = getAttribute(callExpressionElement, javaMethodArgsAttr); + + return signature(javaObjectType, javaObjectTypeArgs, javaMethodName, javaMethodTypeArgs, javaMethodArgs); + } + + static public String signature1(CallExpressionContext arktsCall) { + return signature(arktsCall.javaObjectType, arktsCall.javaObjectTypeArgs, arktsCall.javaName, arktsCall.javaMethodTypeArgs, arktsCall.javaMethodArgs); + } + + static public String signature2(CallExpressionContext arktsCall) { + return signature(arktsCall.javaObjectType, arktsCall.javaObjectTypeArgs, arktsCall.javaName, null, arktsCall.javaMethodArgs); + } + + static public String signature3(CallExpressionContext arktsCall) { + return signature(arktsCall.javaObjectType, null, arktsCall.javaName, arktsCall.javaMethodTypeArgs, arktsCall.javaMethodArgs); + } + + static public String signature4(CallExpressionContext arktsCall) { + return signature(arktsCall.javaObjectType, null, arktsCall.javaName, null, arktsCall.javaMethodArgs); + } + + static CallExpressionRule read(XMLEventReader xmlReader) throws XMLStreamException { + CallExpressionRule callExpressionRule = new CallExpressionRule(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if ("ArktsTypeName".equals(tag)) { + callExpressionRule.arktsTypeName = getAttribute(startElement, valueAttr); + } + else if ("ArktsMethodName".equals(tag)) { + callExpressionRule.arktsMethodName = getAttribute(startElement, valueAttr); + } + else if ("ArktsObjectTypeArgs".equals(tag)) { + while (xmlReader.hasNext()) { + xmlEvent = xmlReader.nextEvent(); + if (xmlEvent.isStartElement()) { + tag = xmlEvent.asStartElement().getName().getLocalPart(); + + if (TypeArguments.tag.equals(tag)) { + callExpressionRule.arktsObjectTypeArgs = TypeArguments.read(xmlReader); + } + } + else if (xmlEvent.isEndElement()) { + tag = xmlEvent.asEndElement().getName().getLocalPart(); + + if ("ArktsObjectTypeArgs".equals(tag)) { + break; + } + else + assert false; + } + } + } + else if ("ArktsMethodTypeArgs".equals(tag)) { + while (xmlReader.hasNext()) { + xmlEvent = xmlReader.nextEvent(); + if (xmlEvent.isStartElement()) { + tag = xmlEvent.asStartElement().getName().getLocalPart(); + + if (TypeArguments.tag.equals(tag)) { + callExpressionRule.arktsMethodTypeArgs = TypeArguments.read(xmlReader); + } + } + else if (xmlEvent.isEndElement()) { + tag = xmlEvent.asEndElement().getName().getLocalPart(); + + if ("ArktsMethodTypeArgs".equals(tag)) { + break; + } + else + assert false; + } + } + } + else if (Arguments.tag.equals(tag)) { + callExpressionRule.arguments = Arguments.read(xmlReader, xmlEvent); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + + if (CallExpressionRule.tag.equals(tag)) { + break; + } + else { + assert ("ArktsTypeName".equals(tag) || "ArktsMethodName".equals(tag) + || TypeArguments.tag.equals(tag) || Arguments.tag.equals(tag)); + } + } + } + + return callExpressionRule; + } + } + + // + static private class MemberAccessExpressionRule { + static public String tag = "MemberAccessExpressionRule"; + + private String arktsName = null; + + // ArkTS: + // | singleExpression Dot Identifier # MemberAccessExpression + public void apply(MemberAccessExpressionContext arktsMemberAccessExpression) { + assert arktsName != null; + + arktsMemberAccessExpression.children.remove(arktsMemberAccessExpression.Identifier()); + arktsMemberAccessExpression.addChild(new TerminalNodeImpl(new CommonToken(StaticTSParser.Identifier, arktsName))); + } + + static private String signature(String javaObjectType, String javaName) { + sb.setLength(0); // Clear the StringBuilder. + + if (!isStringEmpty(javaObjectType)) { + sb.append(javaObjectType); + } + + sb.append('@'); + + if (!isStringEmpty(javaName)) { + sb.append(javaName); + } + + return sb.toString(); + } + + static public String signature(MemberAccessExpressionContext arktsMemberAccessExpression) { + return signature(arktsMemberAccessExpression.javaObjectType, arktsMemberAccessExpression.javaName); + } + + static public String signature(StartElement callExpressionElement) { + String javaObjectType = getAttribute(callExpressionElement, javaObjectTypeAttr); + String javaName = getAttribute(callExpressionElement, javaMethodNameAttr); + + return signature(javaObjectType, javaName); + } + static MemberAccessExpressionRule read(XMLEventReader xmlReader, XMLEvent xmlMemberAccessExpressionEvent, StartElement ruleStartElement) throws XMLStreamException { + MemberAccessExpressionRule memberAccessExpressionRule = new MemberAccessExpressionRule(); + + memberAccessExpressionRule.arktsName = getAttribute(ruleStartElement, arktsNameAttr); + + // Read the end event () + assert (xmlReader.hasNext()); + XMLEvent xmlEvent = xmlReader.nextEvent(); + assert (xmlEvent.isEndElement()); + EndElement endElement = xmlEvent.asEndElement(); + assert (tag.equals(endElement.getName().getLocalPart())); + + return memberAccessExpressionRule; + } + } + +// +// // Optional ArkTS class. If it's not specified then current class remains. +// // Optional list of ArkTS type arguments. If it's not specified then the current type arguments remain. +// // Optional new list of arguments. If it's not specified then the current arguments remain. +// + static private class NewClassInstanceExpressionRule { + static public String tag = "NewClassInstanceExpressionRule"; + + private TypeReference typeReference = null; + private TypeArguments typeArguments = null; + private Arguments arguments = null; + + // ArkTS: + // New typeArguments? typeReference arguments? classBody? # NewClassInstanceExpression + public void apply(NewClassInstanceExpressionContext arktsNewClassInstanceExpression) { + TypeArgumentsContext arktsOrigTypeArguments = arktsNewClassInstanceExpression.typeArguments(); + List arktsOrigTypeArgsList = null; + + if (typeReference != null) { + TypeReferenceContext arktsOrigTypeReference = arktsNewClassInstanceExpression.typeReference(); + arktsNewClassInstanceExpression.children.remove(arktsOrigTypeReference); + + if (arktsOrigTypeArguments != null) { + arktsOrigTypeArgsList = arktsOrigTypeArguments.typeArgumentList().typeArgument(); + } + + arktsNewClassInstanceExpression.addChild(typeReference.buildArktsNode(arktsOrigTypeArgsList)); + } + + if (typeArguments != null) { + arktsNewClassInstanceExpression.children.remove(arktsOrigTypeArguments); + + if (arktsOrigTypeArguments != null) { + arktsOrigTypeArgsList = arktsOrigTypeArguments.typeArgumentList().typeArgument(); + } + + arktsNewClassInstanceExpression.addChild(typeArguments.buildArktsNode(arktsOrigTypeArgsList)); + } + + if (arguments != null) { + ExpressionSequenceContext arktsExpressionSequence = arktsNewClassInstanceExpression.arguments().expressionSequence(); + + // The list of arguments will be completely rebuild. At the same time new arguments may referes to some arguments + // from the old list. So preserve the old list of arguments. + List arktsOrigArguments = new ArrayList<>(arktsExpressionSequence.children); + + // Clear the current list of arguments... + arktsExpressionSequence.children.clear(); + // ...and build the new one based on the rule's list of arguments. + + if (arktsOrigTypeArguments != null) { + arktsOrigTypeArgsList = arktsOrigTypeArguments.typeArgumentList().typeArgument(); + } + + arguments.rebuildArktsNode(arktsExpressionSequence, arktsOrigTypeArgsList, arktsOrigArguments); + } + } + + static private String signature(String javaObjectType, String javaObjectTypeArgs, String javaMethodTypeArgs, String javaMethodArgs) { + sb.setLength(0); // Clear the StringBuilder. + + if (!isStringEmpty(javaObjectType)) { + sb.append(javaObjectType); + } + + sb.append('@'); + + if (!isStringEmpty(javaObjectTypeArgs)) { + sb.append(javaObjectTypeArgs); + } + + sb.append('@'); + + if (!isStringEmpty(javaMethodTypeArgs)) { + sb.append(javaMethodTypeArgs); + } + + sb.append('@'); + + if (!isStringEmpty(javaMethodArgs)) { + sb.append(javaMethodArgs); + } + + return sb.toString(); + } + + static public String signature(StartElement newClassInstanceExpressionElement) { + String javaObjectType = getAttribute(newClassInstanceExpressionElement, javaObjectTypeAttr); + String javaObjectTypeArgs = getAttribute(newClassInstanceExpressionElement, javaObjectTypeArgsAttr); + String javaMethodTypeArgs = getAttribute(newClassInstanceExpressionElement, javaMethodTypeArgsAttr); + String javaMethodArgs = getAttribute(newClassInstanceExpressionElement, javaMethodArgsAttr); + + return signature(javaObjectType, javaObjectTypeArgs, javaMethodTypeArgs, javaMethodArgs); + } + + static public String signature(NewClassInstanceExpressionContext arktsNewClass) { + return signature(arktsNewClass.javaObjectType, arktsNewClass.javaObjectTypeArgs, arktsNewClass.javaMethodTypeArgs, arktsNewClass.javaMethodArgs); + } + + static NewClassInstanceExpressionRule read(XMLEventReader xmlReader, XMLEvent xmlNewClassExpressionEvent, StartElement ruleStartElement) throws XMLStreamException { + NewClassInstanceExpressionRule newClassExpressionRule = new NewClassInstanceExpressionRule(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + newClassExpressionRule.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else if (TypeArguments.tag.equals(tag)) { + newClassExpressionRule.typeArguments = TypeArguments.read(xmlReader); + } + else if (Arguments.tag.equals(tag)) { + newClassExpressionRule.arguments = Arguments.read(xmlReader, xmlEvent); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + assert NewClassInstanceExpressionRule.tag.equals(endElement.getName().getLocalPart()); + break; + } + } + + return newClassExpressionRule; + } + } + + // + // + // + + static private class TypeReferenceRule { + static public String tag = "TypeReferenceRule"; + + private TypeReference typeReference = null; + + public void apply(TypeReferenceContext arktsTypeReference) { + assert typeReference != null; + + // TODO: The code here expects that there is only 1 TypeReferencePart. If really there will be case + // with many TypeReferenceParts then the code has to be addopted to it. + TypeReferencePartContext arktsOrigTypeReferencePart = arktsTypeReference.typeReferencePart(0); + List arktsOrigTypeArgsList = null; + TypeArgumentsContext arktsTypeArguments = arktsOrigTypeReferencePart.typeArguments(); + + if (arktsTypeArguments != null) { + arktsOrigTypeArgsList = arktsTypeArguments.typeArgumentList().typeArgument(); + } + + assert (arktsTypeReference.parent instanceof ParserRuleContext); + ParserRuleContext arktsTypeReferenceParent = (ParserRuleContext) arktsTypeReference.parent; + arktsTypeReferenceParent.children.remove(arktsTypeReference); + + arktsTypeReferenceParent.addChild(typeReference.buildArktsNode(arktsOrigTypeArgsList)); + } + + static private String signature(String javaObjectType, String javaObjectTypeArgs) { + sb.setLength(0); // Clear the StringBuilder. + + if (!isStringEmpty(javaObjectType)) { + sb.append(javaObjectType); + } + + sb.append('@'); + + if (!isStringEmpty(javaObjectTypeArgs)) { + sb.append(javaObjectTypeArgs); + } + + return sb.toString(); + } + + static public String signature(StartElement typeReferenceElement) { + String javaObjectType = getAttribute(typeReferenceElement, javaObjectTypeAttr); + String javaObjectTypeArgs = getAttribute(typeReferenceElement, javaObjectTypeArgsAttr); + + return signature(javaObjectType, javaObjectTypeArgs); + } + + static public String signature(TypeReferenceContext arktsTypeReference) { + return signature(arktsTypeReference.javaObjectType, arktsTypeReference.javaObjectTypeArgs); + } + + static TypeReferenceRule read(XMLEventReader xmlReader, XMLEvent xmlNewClassExpressionEvent, StartElement ruleStartElement) throws XMLStreamException { + TypeReferenceRule typeReferenceRule = new TypeReferenceRule(); + + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (TypeReference.tag.equals(tag)) { + typeReferenceRule.typeReference = TypeReference.read(xmlReader, xmlEvent); + } + else assert false; + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + assert TypeReferenceRule.tag.equals(endElement.getName().getLocalPart()); + break; + } + } + + return typeReferenceRule; + } + } + + // For some items from 'java.lang' package its equivalents in ArkTS located in NOT implicitly imported packages. + // To make such items available for usage corresponding imports have to be added to the resulting code. + // In the first iteration add the imports always without attempt to figure out whether any item of the packages is + // really used in the code or not. + private HashSet mandatoryImportRules = new HashSet<>(); + private HashMap importDeclarationRules = new HashMap<>(); + private HashMap callExpressionRules = new HashMap<>(); + private HashMap memberAccessExpressionRules = new HashMap<>(); + private HashMap newClassInstanceExpressionRules = new HashMap<>(); + private HashMap typeReferenceRules = new HashMap<>(); + + @Override + public Void visitCompilationUnit(CompilationUnitContext arktsCompilationUnit) { + super.visitCompilationUnit(arktsCompilationUnit); + + for(ImportDeclarationRule rule : mandatoryImportRules) { + rule.apply(arktsCompilationUnit); + } + + return null; + } + + @Override + public Void visitImportDeclaration(ImportDeclarationContext arktsImportDeclatation) { + ImportDeclarationRule rule = importDeclarationRules.get(ImportDeclarationRule.signature(arktsImportDeclatation)); + if (rule != null) { + rule.apply(arktsImportDeclatation); + } + + return null; + } + + @Override + public Void visitCallExpression(CallExpressionContext arktsCallExpression) { + CallExpressionRule rule = callExpressionRules.get(CallExpressionRule.signature1(arktsCallExpression)); + + if (rule == null) { + rule = callExpressionRules.get(CallExpressionRule.signature2(arktsCallExpression)); + } + + if (rule == null) { + rule = callExpressionRules.get(CallExpressionRule.signature3(arktsCallExpression)); + } + + if (rule == null) { + rule = callExpressionRules.get(CallExpressionRule.signature4(arktsCallExpression)); + } + + if (rule != null) { + rule.apply(arktsCallExpression); + } + + return null; + } + + @Override + public Void visitMemberAccessExpression(MemberAccessExpressionContext arktsMemberAccessExpression) { + MemberAccessExpressionRule rule = memberAccessExpressionRules.get(MemberAccessExpressionRule.signature(arktsMemberAccessExpression)); + if (rule != null) { + rule.apply(arktsMemberAccessExpression); + } + + return null; + } + + @Override + public Void visitNewClassInstanceExpression(NewClassInstanceExpressionContext arktsNewClassInstanceExpression) { + NewClassInstanceExpressionRule rule = newClassInstanceExpressionRules.get(NewClassInstanceExpressionRule.signature(arktsNewClassInstanceExpression)); + if (rule != null) { + rule.apply(arktsNewClassInstanceExpression); + } + + return null; + } + + @Override + public Void visitTypeReference(TypeReferenceContext arktsTypeReference) { + TypeReferenceRule rule = typeReferenceRules.get(TypeReferenceRule.signature(arktsTypeReference)); + if (rule != null) { + rule.apply(arktsTypeReference); + } + + return null; + } + + private JavaApiMapper(XMLEventReader xmlReader) throws XMLStreamException { + while (xmlReader.hasNext()) { + XMLEvent xmlEvent = xmlReader.nextEvent(); + if (xmlEvent.isStartElement()) { + StartElement startElement = xmlEvent.asStartElement(); + String tag = startElement.getName().getLocalPart(); + + if (ImportDeclarationRule.tag.equals(tag)) { + ImportDeclarationRule rule = ImportDeclarationRule.read(xmlReader, xmlEvent, startElement); + String signature = rule.signature(startElement); + + if (rule.javaPackage == null) { + mandatoryImportRules.add(rule); + } + else { + assert !isStringEmpty(signature) && rule != null; + importDeclarationRules.put(signature, rule); + } + } + else if (CallExpressionRule.tag.equals(tag)) { + CallExpressionRule rule = CallExpressionRule.read(xmlReader); + String signature = rule.signature(startElement); + + assert !isStringEmpty(signature) && rule != null; + callExpressionRules.put(signature, rule); + } + else if (MemberAccessExpressionRule.tag.equals(tag)) { + String signature = MemberAccessExpressionRule.signature(startElement); + MemberAccessExpressionRule rule = MemberAccessExpressionRule.read(xmlReader, xmlEvent, startElement); + + assert !isStringEmpty(signature) && rule != null; + memberAccessExpressionRules.put(signature, rule); + } + else if (NewClassInstanceExpressionRule.tag.equals(tag)) { + String signature = NewClassInstanceExpressionRule.signature(startElement); + NewClassInstanceExpressionRule rule = NewClassInstanceExpressionRule.read(xmlReader, xmlEvent, startElement); + + assert !isStringEmpty(signature) && rule != null; + newClassInstanceExpressionRules.put(signature, rule); + } + else if (TypeReferenceRule.tag.equals(tag)) { + String signature = TypeReferenceRule.signature(startElement); + TypeReferenceRule rule = TypeReferenceRule.read(xmlReader, xmlEvent, startElement); + + assert !isStringEmpty(signature) && rule != null; + typeReferenceRules.put(signature, rule); + } + else { + assert "JavaApiMappingRules".equals(tag); + } + } + else if (xmlEvent.isEndElement()) { + EndElement endElement = xmlEvent.asEndElement(); + String tag = endElement.getName().getLocalPart(); + if ("JavaApiMappingRules".equals(tag)) { + break; + } + else { + assert false : "Unexpected XmlElement $tag"; + } + } + } + } + + static public JavaApiMapper readRules(String path) throws FileNotFoundException, XMLStreamException { + XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + FileInputStream fis = new FileInputStream(path); + XMLEventReader xmlReader = xmlInputFactory.createXMLEventReader(fis); + return new JavaApiMapper(xmlReader); + } +} diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index a435e7e87..1b40cf21c 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -809,8 +809,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new TypeParametersContext(stsCurrent, 0)); pushCurrent(new TypeParameterListContext(stsCurrent, 0)); - for (TypeParameter javaType : javaTypeParameters) { - javaType.accept(this); + for (TypeParameter javaTypeParam : javaTypeParameters) { + javaTypeParam.accept(this); } popCurrent(); // TypeParameterListContext @@ -1051,17 +1051,22 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // : Import qualifiedName (Dot Multiply)? SemiColon? @Override public boolean visit(ImportDeclaration javaImportDeclaration) { - pushCurrent(new ImportDeclarationContext(stsCurrent, 0)); + ImportDeclarationContext stsImportDeclaration = new ImportDeclarationContext(stsCurrent, 0); + pushCurrent(stsImportDeclaration); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Import)); - stsCurrent.addChild(NodeBuilder.qualifiedName(javaImportDeclaration.getName())); + + String javaImportName = javaImportDeclaration.getName().getFullyQualifiedName(); + stsCurrent.addChild(NodeBuilder.qualifiedName(javaImportName)); + + stsImportDeclaration.javaPackage = javaImportName; if (javaImportDeclaration.isOnDemand()) { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Dot)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Multiply)); - } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.SemiColon)); + stsImportDeclaration.javaPackage += ".*"; + } popCurrent(); // ImportDeclarationContext @@ -1114,6 +1119,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + private void fillMapperMatchAtributs(TypeReferenceContext stsTypeRef, ITypeBinding javaTypeBinding) { + if (javaTypeBinding != null) { + stsTypeRef.javaObjectType = javaTypeBinding.getQualifiedName(); + stsTypeRef.javaObjectTypeArgs = buildSignature(javaTypeBinding.getTypeArguments()); + } + } + // Java tree: // SimpleType: { Annotation } TypeName // @@ -1130,6 +1142,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { String typeFQN = javaSimpleType.getName().getFullyQualifiedName(); TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(typeFQN); + fillMapperMatchAtributs(stsTypeRef, javaSimpleType.resolveBinding()); + // Add empty type arguments list if this is a raw type NodeBuilder.addEmptyTypeArgumentsToRawType(stsTypeRef, javaSimpleType); @@ -1171,6 +1185,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { TypeReferencePartContext stsTypeRefPart = NodeBuilder.typeReferencePart(typeName); stsTypeRef.addChild(stsTypeRefPart).setParent(stsTypeRef); + fillMapperMatchAtributs(stsTypeRef, javaQualifiedType.resolveBinding()); + // Add empty type arguments list if this is a raw type NodeBuilder.addEmptyTypeArgumentsToRawType(stsTypeRef, javaQualifiedType); @@ -1195,12 +1211,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Construct TypeReferenceContext from qualifier name and type name. String javaQualifierText = javaNameQualifiedType.getQualifier().getFullyQualifiedName(); String typeFQN = javaQualifierText + '.' + javaNameQualifiedType.getName().getFullyQualifiedName(); - TypeReferenceContext stsType = NodeBuilder.typeReference(typeFQN); + TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(typeFQN); + //stsTypeRef.javaObjectType = typeFQN; + fillMapperMatchAtributs(stsTypeRef, javaNameQualifiedType.resolveBinding()); // Add empty type arguments list if this is a raw type - NodeBuilder.addEmptyTypeArgumentsToRawType(stsType, javaNameQualifiedType); + NodeBuilder.addEmptyTypeArgumentsToRawType(stsTypeRef, javaNameQualifiedType); - stsCurrent.addChild(stsType).setParent(stsCurrent); + stsCurrent.addChild(stsTypeRef).setParent(stsCurrent); if (needPrimaryType) popCurrent(); // PrimaryTypeContext typeTransformed.add(javaNameQualifiedType); @@ -1233,6 +1251,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Translate and add type arguments to last TypeReferencePartContext node pushCurrent((TypeReferencePartContext)stsLastChild, false); List javaTypeArgs = javaParametrizedType.typeArguments(); + if (javaTypeArgs != null && !javaTypeArgs.isEmpty()) { translateTypeArguments(javaTypeArgs); } @@ -1245,6 +1264,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(stsTypeArgs).setParent(stsCurrent); } } + popCurrent(); // (TypeReferencePartContext)stsLastChild if (needPrimaryType) popCurrent(); // PrimaryTypeContext @@ -1326,19 +1346,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void translateTypeBinding(ITypeBinding javaType, ASTNode javaNode) { - if (javaType == null || javaType.isRecovered()) { + private void translateTypeBinding(ITypeBinding javaTypeBinding, ASTNode javaNode) { + if (javaTypeBinding == null || javaTypeBinding.isRecovered()) { // Warn and emit __UnknownType__ as result type - String typeName = javaType != null ? javaType.getName() : ""; + String typeName = javaTypeBinding != null ? javaTypeBinding.getName() : ""; reportError("Failed to resolve type " + typeName, javaNode); - stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaType)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaTypeBinding)).setParent(stsCurrent); return; } pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.translateTypeBinding(javaType)); + stsCurrent.addChild(NodeBuilder.translateTypeBinding(javaTypeBinding)); popCurrent(); // PrimaryTypeContext popCurrent(); // TypeAnnotationContext @@ -1701,11 +1721,15 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } } + private StringBuilder sb = new StringBuilder(); + // STS Tree: // typeArguments: LessThan typeArgumentList? MoreThan // typeArgumentList: typeArgument (Comma typeArgument)* // typeArgument: typeReference | arrayType | wildcardType - private void translateTypeArguments(List javaTypeArgs) { + private String translateTypeArguments(List javaTypeArgs) { + sb.setLength(0); // Clear the string builder. + if (javaTypeArgs != null && !javaTypeArgs.isEmpty()) { pushCurrent(new TypeArgumentsContext(stsCurrent, 0)); @@ -1725,11 +1749,21 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popCurrent(); // TypeArgumentContext + + ITypeBinding javaTypeBinding = javaTypeArg.resolveBinding(); + assert (javaTypeBinding != null); + sb.append(javaTypeBinding.getQualifiedName()).append(','); + } + + if (sb.length() > 1) { + sb.setLength(sb.length() - 1); // Remove the ending extra comma. } popCurrent(); // TypeArgumentListContext popCurrent(); // TypeArgumentsContext } + + return sb.length() > 0 ? sb.toString() : null; // The signature of the type arguments list. It's used by the API mapper. } // STS tree: @@ -2909,19 +2943,42 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(ConstructorInvocation javaCtorInvocation) { IMethodBinding javaCtorBinding = javaCtorInvocation.resolveConstructorBinding(); boolean isThrowingCall = false; + + ConstructorCallContext stsConstructorCall = new ConstructorCallContext(stsCurrent, 0); + + if (javaCtorBinding != null) { isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; if(isThrowingCall && checkThrownExceptionSet(javaCtorInvocation)) addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); + + stsConstructorCall.javaMethodArgs = buildSignature(javaCtorBinding.getParameterTypes()); + + //ITypeBinding javaClassType = javaCtorInvocation.getExpression().resolveTypeBinding(); + ITypeBinding javaClassType = javaCtorBinding.getDeclaringClass(); + stsConstructorCall.javaObjectType = javaClassType.getQualifiedName(); + //stsConstructorCall.javaObjectType = javaCtorBinding.getDeclaringClass().getQualifiedName(); + stsConstructorCall.javaObjectTypeArgs = buildSignature(javaClassType.getTypeArguments()); } else { reportError("Failed to resolve constructor call", javaCtorInvocation); } - translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.This), - javaCtorInvocation.typeArguments(), - javaCtorInvocation.arguments(), - null, isThrowingCall); + pushCurrent(stsConstructorCall); + + // Add 'try' keyword if this is a throwing call. + if (isThrowingCall) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.This)); + + translateTypeArguments(javaCtorInvocation.typeArguments()); + stsConstructorCall.javaMethodTypeArgs = buildSignature(javaCtorInvocation.typeArguments()); + + translateArguments(javaCtorInvocation.arguments()); + + popCurrent(); // ConstructorCallContext stmtTransformed.add(javaCtorInvocation); return false; @@ -2942,47 +2999,54 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | (singleExpression . )? super typeArguments? arguments SemiColon @Override public boolean visit(SuperConstructorInvocation javaSuperCtorInvocation) { - IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); boolean isThrowingCall = false; + ConstructorCallContext stsConstructorCall = new ConstructorCallContext(stsCurrent, 0); + + IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); if (javaCtorBinding != null) { isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; if(isThrowingCall && checkThrownExceptionSet(javaSuperCtorInvocation)) addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); + + stsConstructorCall.javaMethodArgs = buildSignature(javaCtorBinding.getParameterTypes()); + Expression javaExpression = javaSuperCtorInvocation.getExpression(); + + if (javaExpression != null) { + ITypeBinding javaClassType = javaExpression.resolveTypeBinding(); + if (javaClassType != null) { + stsConstructorCall.javaObjectType = javaClassType.getQualifiedName(); + //stsConstructorCall.javaObjectType = javaCtorBinding.getDeclaringClass().getQualifiedName(); + stsConstructorCall.javaObjectTypeArgs = buildSignature(javaClassType.getTypeArguments()); + } + } } else { reportError("Failed to report constructor call", javaSuperCtorInvocation); } - translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.Super), - javaSuperCtorInvocation.typeArguments(), - javaSuperCtorInvocation.arguments(), - javaSuperCtorInvocation.getExpression(), - isThrowingCall); - - stmtTransformed.add(javaSuperCtorInvocation); - return false; - } - - // NOTE: If ctor called can throw exceptions, prepend 'try' keyword to result. - private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, - List javaArgs, Expression javaCtorExpr, - boolean isThrowingCall) { - pushCurrent(new ConstructorCallContext(stsCurrent, 0)); + pushCurrent(stsConstructorCall); // Add 'try' keyword if this is a throwing call. if (isThrowingCall) { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } + + Expression javaCtorExpr = javaSuperCtorInvocation.getExpression(); if (javaCtorExpr != null) { javaCtorExpr.accept(this); } - stsCurrent.addChild(stsThisOrSuper); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); + + translateTypeArguments(javaSuperCtorInvocation.typeArguments()); + stsConstructorCall.javaMethodTypeArgs = buildSignature(javaSuperCtorInvocation.typeArguments()); - translateTypeArguments(javaTypeArgs); - translateArguments(javaArgs); + translateArguments(javaSuperCtorInvocation.arguments()); popCurrent(); // ConstructorCallContext + + stmtTransformed.add(javaSuperCtorInvocation); + return false; } private List translateArguments(List javaArgs) { @@ -2994,9 +3058,17 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(stsExprSeq); for (Expression javaExpr : javaArgs) { + ITypeBinding javaTypeBinding = javaExpr.resolveTypeBinding(); + assert (javaTypeBinding != null); + sb.append(javaTypeBinding.getQualifiedName()).append(','); + javaExpr.accept(this); } + if (sb.length() > 1) { + sb.setLength(sb.length() - 1); // Remove the ending extra comma. + } + popCurrent(); // ExpressionSequenceContext result = stsExprSeq.singleExpression(); } @@ -3122,7 +3194,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new CastExpressionContext(pushSingleExpression())); javaCastExpression.getExpression().accept(this); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.As)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.As)); javaCastExpression.getType().accept(this); popSingleExpression(); // CastExpressionContext @@ -3197,6 +3269,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public boolean visit(ClassInstanceCreation javaClassInstanceCreation) { IMethodBinding javaCtorBinding = javaClassInstanceCreation.resolveConstructorBinding(); boolean ctorCanThrow = false; + if (javaCtorBinding != null) { ctorCanThrow = javaCtorBinding.getExceptionTypes().length > 0; } @@ -3208,30 +3281,55 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (ctorCanThrow) { if(checkThrownExceptionSet(javaClassInstanceCreation)) addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); + pushCurrent(new TryExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } // Add outer class object, if any. Expression javaOuterObject = javaClassInstanceCreation.getExpression(); + SingleExpressionContext stsNewClassInstanceExpr; SingleExpressionContext stsOuterObject = null; + if (javaOuterObject != null) { - pushCurrent(new NewInnerClassInstanceExpressionContext(pushSingleExpression())); + stsNewClassInstanceExpr = new NewInnerClassInstanceExpressionContext(pushSingleExpression()); + pushCurrent(stsNewClassInstanceExpr); javaOuterObject.accept(this); stsOuterObject = ((NewInnerClassInstanceExpressionContext)stsCurrent).singleExpression(); } else { - pushCurrent(new NewClassInstanceExpressionContext(pushSingleExpression())); + stsNewClassInstanceExpr = new NewClassInstanceExpressionContext(pushSingleExpression()); + pushCurrent(stsNewClassInstanceExpr); } stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); + translateTypeArguments(javaClassInstanceCreation.typeArguments()); + stsNewClassInstanceExpr.javaMethodTypeArgs = buildSignature(javaClassInstanceCreation.typeArguments()); + + Type javaClassType = javaClassInstanceCreation.getType(); - javaClassInstanceCreation.getType().accept(this); + javaClassType.accept(this); + + try { + ITypeBinding classTypeBinding = javaClassType.resolveBinding(); + ITypeBinding erasureTypeBinding = classTypeBinding.getErasure(); + stsNewClassInstanceExpr.javaObjectType = (erasureTypeBinding != null) ? erasureTypeBinding.getQualifiedName() : classTypeBinding.getQualifiedName(); // Used by the API mapper. + + stsNewClassInstanceExpr.javaObjectTypeArgs = buildSignature(classTypeBinding.getTypeArguments()); + } + catch (Exception e) { + reportError("Fail to resolve class type", javaClassType); + } List stsArgs = translateArguments(javaClassInstanceCreation.arguments()); + if (javaCtorBinding != null) { + stsNewClassInstanceExpr.javaMethodArgs = buildSignature(javaCtorBinding.getParameterTypes()); + } + AnonymousClassDeclaration javaAnonymousClassDeclaration = javaClassInstanceCreation.getAnonymousClassDeclaration(); + if (javaAnonymousClassDeclaration != null) { // Store outer object and ctor arguments (if any) in javaAnonymousClassDeclaration. // We might need them if anonymous class contains instance initializer, see @@ -3464,7 +3562,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { Name javaQualifier = javaSuperFieldAccess.getQualifier(); if (javaQualifier != null) { - stsCurrent.addChild(NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName())).setParent(stsCurrent); + TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName()); + stsCurrent.addChild(stsTypeRef).setParent(stsCurrent); + + fillMapperMatchAtributs(stsTypeRef, javaQualifier.resolveTypeBinding()); } stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); @@ -3499,6 +3600,46 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + private String buildSignature(ITypeBinding typeArguments[]) { + if (typeArguments != null) { + sb.setLength(0); + + for (ITypeBinding typeArgument : typeArguments) { + sb.append(typeArgument.getQualifiedName()).append(','); + } + + if (sb.length() > 0) { + return sb.substring(0, sb.length() - 1); // Remove the ending extra comma. + } + } + + return null; + } + + private String buildSignature(List javaTypeArgs) { + sb.setLength(0); // Clear the string builder. + + if (javaTypeArgs != null && !javaTypeArgs.isEmpty()) { + for (Type javaTypeArg : javaTypeArgs) { + try { + ITypeBinding javaTypeBinding = javaTypeArg.resolveBinding(); + assert (javaTypeBinding != null); + sb.append(javaTypeBinding.getQualifiedName()).append(','); + } + catch (Exception e) { + reportError("Friled to resolve type argument", javaTypeArg); + } + } + + if (sb.length() > 1) { + return sb.substring(0, sb.length() - 1); // Remove the ending extra comma. + } + } + + return null; + } + + // Java tree: // MethodInvocation: // [ Expression . ] @@ -3516,21 +3657,16 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | Try singleExpression #TryExpression @Override public boolean visit(MethodInvocation javaMethodInvocation) { - // resolveMethodBinding() can throw exceptions, - // so let's catch them to make sure we proceed. - IMethodBinding javaMethodBinding; + boolean isThrowingCall = false; + // resolveMethodBinding() can throw exceptions, so let's catch them to make sure we proceed. + IMethodBinding javaMethodBinding = null; try { javaMethodBinding = javaMethodInvocation.resolveMethodBinding(); + if (javaMethodBinding != null) { + isThrowingCall = javaMethodBinding.getExceptionTypes().length > 0; + } } catch (Exception e) { - javaMethodBinding = null; - } - - boolean isThrowingCall = false; - if (javaMethodBinding != null) { - isThrowingCall = javaMethodBinding.getExceptionTypes().length > 0; - } - else { reportError("Failed to resolve method call", javaMethodInvocation); } @@ -3538,28 +3674,53 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (isThrowingCall) { if(checkThrownExceptionSet(javaMethodInvocation)) addMultipleThrownExceptions(javaMethodBinding.getExceptionTypes()); + pushCurrent(new TryExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } - pushCurrent(new CallExpressionContext(pushSingleExpression())); + CallExpressionContext stsCallExpression = new CallExpressionContext(pushSingleExpression()); + pushCurrent(stsCallExpression); Expression javaObjectExpression = javaMethodInvocation.getExpression(); + String javaMethodName = javaMethodInvocation.getName().getIdentifier(); + stsCallExpression.javaName = javaMethodName; // Used by the API mapper. + if (javaObjectExpression != null) { + ITypeBinding objectTypeBinding = javaObjectExpression.resolveTypeBinding(); + if (objectTypeBinding != null) { + // The API mapper needs name of fully qualified RAW type. So look for erasure. + ITypeBinding erasureType = objectTypeBinding.getErasure(); + stsCallExpression.javaObjectType = (erasureType != null) ? erasureType.getQualifiedName() : objectTypeBinding.getQualifiedName(); // Used by the API mapper. + + stsCallExpression.javaObjectTypeArgs = buildSignature(objectTypeBinding.getTypeArguments()); + } + else { + // TODO: If the type binding was not resolved then it's very probably the source code was invalid. + // Log the problem informatioin. + } + // | singleExpression Dot identifier # MemberAccessExpression pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); javaObjectExpression.accept(this); - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodInvocation.getName())); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodName)); popSingleExpression(); // MemberAccessExpressionContext - } else { + } + else { pushCurrent(new IdentifierExpressionContext(pushSingleExpression())); - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodInvocation.getName())); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodName)); popSingleExpression(); // IdentifierExpressionContext } translateTypeArguments(javaMethodInvocation.typeArguments()); + stsCallExpression.javaMethodTypeArgs = buildSignature(javaMethodInvocation.typeArguments()); + translateArguments(javaMethodInvocation.arguments()); + if (javaMethodBinding != null) { + stsCallExpression.javaMethodArgs = buildSignature(javaMethodBinding.getParameterTypes()); + } + popSingleExpression(); // CallExpressionContext if (isThrowingCall) { @@ -3584,25 +3745,67 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | (typeReference Dot)? Super # SuperExpression @Override public boolean visit(SuperMethodInvocation javaSuperMethodInvocation) { - pushCurrent(new CallExpressionContext(pushSingleExpression())); + boolean isThrowingCall = false; + // resolveMethodBinding() can throw exceptions, so let's catch them to make sure we proceed. + IMethodBinding javaMethodBinding = null; + try { + javaMethodBinding = javaSuperMethodInvocation.resolveMethodBinding(); + if (javaMethodBinding != null) { + isThrowingCall = javaMethodBinding.getExceptionTypes().length > 0; + } + } + catch (Exception e) { + reportError("Failed to resolve super method call", javaSuperMethodInvocation); + } + + // Add TryExpressionContext if this is a throwing call. + if (isThrowingCall) { + if(checkThrownExceptionSet(javaSuperMethodInvocation)) + addMultipleThrownExceptions(javaMethodBinding.getExceptionTypes()); + + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + + CallExpressionContext stsCallExpression = new CallExpressionContext(pushSingleExpression()); + pushCurrent(stsCallExpression); + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); pushCurrent(new SuperExpressionContext(pushSingleExpression())); Name javaQualifier = javaSuperMethodInvocation.getQualifier(); + if (javaQualifier != null) { - stsCurrent.addChild(NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName())).setParent(stsCurrent); + // TODO: Take into account the Qualifier for the API mapper. + TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName()); + stsCurrent.addChild(stsTypeRef).setParent(stsCurrent); + + fillMapperMatchAtributs(stsTypeRef, javaQualifier.resolveTypeBinding()); } stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); popSingleExpression(); // SuperExpressionContext - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaSuperMethodInvocation.getName())); + String javaMethodName = javaSuperMethodInvocation.getName().getFullyQualifiedName(); + + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodName)); popStatement(); // MemberAccessExpressionContext translateTypeArguments(javaSuperMethodInvocation.typeArguments()); + stsCallExpression.javaObjectTypeArgs = buildSignature(javaSuperMethodInvocation.typeArguments()); + + if (javaMethodBinding != null) { + stsCallExpression.javaMethodArgs = buildSignature(javaMethodBinding.getParameterTypes()); + } + translateArguments(javaSuperMethodInvocation.arguments()); + popSingleExpression(); // CallExpressionContext + if (isThrowingCall) { + popSingleExpression(); // TryExpressionContext + } + exprTransformed.add(javaSuperMethodInvocation); return false; } @@ -3617,7 +3820,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { Name javaQualifier = javaThisExpr.getQualifier(); if (javaQualifier != null) { - stsCurrent.addChild(NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName())).setParent(stsCurrent); + TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName()); + stsCurrent.addChild(stsTypeRef).setParent(stsCurrent); + + fillMapperMatchAtributs(stsTypeRef, javaQualifier.resolveTypeBinding()); } stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.This)); @@ -3987,21 +4193,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // resolveMethodBinding() can throw exceptions, // so let's catch them to make sure we proceed. - IMethodBinding lambdaMethod; try { - lambdaMethod = javaLambdaExpr.resolveMethodBinding(); - } - catch (Exception e) { - lambdaMethod = null; - } - - if (lambdaMethod != null) { + IMethodBinding lambdaMethod = javaLambdaExpr.resolveMethodBinding(); translateTypeBinding(lambdaMethod.getReturnType(), javaLambdaExpr); if(checkThrownExceptionSet(javaLambdaExpr)) addMultipleThrownExceptions(lambdaMethod.getExceptionTypes()); } - else { - // Warn and emit __UnknownType__ as return type + catch (Exception e) { reportError("Failed to resolve lambda expression", javaLambdaExpr); stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation()).setParent(stsCurrent); } @@ -4147,12 +4345,12 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private void translateClassCreationReference(CreationReference javaCreationRef) { // resolveMethodBinding() can throw exceptions, // so let's catch them to make sure we proceed. - IMethodBinding javaCtorBinding; + IMethodBinding javaCtorBinding = null; try { javaCtorBinding = javaCreationRef.resolveMethodBinding(); } catch (Exception e) { - javaCtorBinding = null; + reportError("Failed to resolve CreationReference", javaCreationRef); } // Exclude recovered bindings as well here, as information we need @@ -4172,12 +4370,25 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } - pushCurrent(new NewClassInstanceExpressionContext(pushSingleExpression())); + NewClassInstanceExpressionContext stsNewClassInstanceExpression = new NewClassInstanceExpressionContext(pushSingleExpression()); + pushCurrent(stsNewClassInstanceExpression); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); translateTypeArguments(javaCreationRef.typeArguments()); + stsNewClassInstanceExpression.javaObjectTypeArgs = buildSignature(javaCreationRef.typeArguments()); - javaCreationRef.getType().accept(this); + Type javaCreationType = javaCreationRef.getType(); + javaCreationType.accept(this); + + try { + ITypeBinding javaTypeBinding = javaCreationType.resolveBinding(); + // TODO: + //stsNewClassInstanceExpression.javaObjectType = + } + catch (Exception e) { + reportError("Failed to resolve creation type", javaCreationType); + } createMethodRefCallArgs(javaCtorBinding.getParameterTypes().length, 1); @@ -4197,6 +4408,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private void createMethodRefCallArgs(int argsCount, int argIdx) { pushCurrent(new ArgumentsContext(stsCurrent, 0)); + if (argsCount > 0) { pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); @@ -4206,6 +4418,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ExpressionSequenceContext } + popCurrent(); // ArgumentsContext } @@ -4230,6 +4443,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } catch (Exception e) { javaMethodBinding = null; + reportError("Failed to resolve super method reference", javaSuperMethodRef); } // Exclude recovered bindings as well here, as information we need @@ -4249,7 +4463,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } - pushCurrent(new CallExpressionContext(pushSingleExpression())); + CallExpressionContext stsCallExpression = new CallExpressionContext(pushSingleExpression()); + pushCurrent(stsCallExpression); // | singleExpression Dot identifier # MemberAccessExpression // where @@ -4259,7 +4474,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { Name javaQualifier = javaSuperMethodRef.getQualifier(); if (javaQualifier != null) { - stsCurrent.addChild(NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName())).setParent(stsCurrent); + TypeReferenceContext stsTypeRef = NodeBuilder.typeReference(javaQualifier.getFullyQualifiedName()); + stsCurrent.addChild(stsTypeRef).setParent(stsCurrent); + + fillMapperMatchAtributs(stsTypeRef, javaQualifier.resolveTypeBinding()); } stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); @@ -4268,7 +4486,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // MemberAccessExpressionContext translateTypeArguments(javaSuperMethodRef.typeArguments()); + stsCallExpression.javaObjectTypeArgs = buildSignature(javaSuperMethodRef.typeArguments()); + // TODO: fill stsCallExpression.javaArgsSignature createMethodRefCallArgs(javaMethodBinding.getParameterTypes().length, 1); popSingleExpression(); // CallExpressionContext @@ -4312,6 +4532,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } catch (Exception e) { javaMethodBinding = null; + reportError("Failed to resolve type method reference", javaTypeMethodRef); } // Exclude recovered bindings as well here, as information we need @@ -4368,6 +4589,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } catch (Exception e) { javaMethodBinding = null; + reportError("Failed to resolve expression method reference", javaExprMethodRef); } Expression javaExpr = javaExprMethodRef.getExpression(); @@ -4439,7 +4661,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } - pushCurrent(new CallExpressionContext(pushSingleExpression())); + CallExpressionContext stsCallExpression = new CallExpressionContext(pushSingleExpression()); + pushCurrent(stsCallExpression); boolean needInstanceParam = false; int lambdaParamIdx = 1; @@ -4458,10 +4681,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } else { javaTypeOrExpression.accept(this); } + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaName)); popSingleExpression(); // MemberAccessExpressionContext translateTypeArguments(javaMethodRef.typeArguments()); + stsCallExpression.javaObjectTypeArgs = buildSignature(javaMethodRef.typeArguments()); + // TODO: Fill stsCallExpression.javaArgsSignature // In case of type method reference, the arity of the functional interface method // would be one more than that of the referenced method (due to having a parameter diff --git a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java index f7c2a91fe..0c15954c7 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java +++ b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java @@ -17,15 +17,20 @@ package com.ohos.migrator.java; import com.ohos.migrator.AbstractTranspiler; +import com.ohos.migrator.Main; import com.ohos.migrator.ResultCode; import com.ohos.migrator.TranspileException; import com.ohos.migrator.staticTS.parser.StaticTSParser.*; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; +import javax.xml.stream.XMLStreamException; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URISyntaxException; import java.util.List; /** @@ -52,6 +57,8 @@ public class JavaTranspiler extends AbstractTranspiler { CompilationUnitContext stsCU = transform(javaCU, srcFile); + migrateAPI(stsCU); + write(stsCU, srcFile); } catch (IOException e) { throw new TranspileException(ResultCode.InputError, e); @@ -83,4 +90,25 @@ public class JavaTranspiler extends AbstractTranspiler { public double getConversionRate() { return JavaTransformer.getTransformationRate() * 100.; } -} \ No newline at end of file + + @Override + public void migrateAPI(CompilationUnitContext arktsCU) + { + try { + File path = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); + File configDir = new File(path, "config"); + //String dir = new File(".").getAbsolutePath(); + //File configDir = new File(dir, "config"); + File f = new File(configDir, "java-api-mapper.xml"); + String rulesFilePath = f.getPath(); + JavaApiMapper mapper = JavaApiMapper.readRules(rulesFilePath); + mapper.visitCompilationUnit(arktsCU); + } + catch (FileNotFoundException | URISyntaxException e) { + Main.addError(ResultCode.InputError, "Fail to find the API mapper rules file. \n" + e.getMessage()); + } + catch (XMLStreamException e) { + Main.addError(ResultCode.ParseError, "Fail to parse the API mapper rules file. \n" + e.getMessage()); + } + } +} diff --git a/migrator/src/com/ohos/migrator/java/NodeBuilder.java b/migrator/src/com/ohos/migrator/java/NodeBuilder.java index 94e71e0c1..cffed9ea5 100644 --- a/migrator/src/com/ohos/migrator/java/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/java/NodeBuilder.java @@ -243,19 +243,19 @@ public class NodeBuilder extends NodeBuilderBase { return stsShiftOp; } - public static ParserRuleContext translateTypeBinding(ITypeBinding javaType) { - if (javaType.isPrimitive()) { - return predefinedType(javaType.getName()); + public static ParserRuleContext translateTypeBinding(ITypeBinding javaTypeBinding) { + if (javaTypeBinding.isPrimitive()) { + return predefinedType(javaTypeBinding.getName()); } - if (javaType.isArray()) { - ITypeBinding javaArrayElemType = javaType.getElementType(); + if (javaTypeBinding.isArray()) { + ITypeBinding javaArrayElemType = javaTypeBinding.getElementType(); ParserRuleContext stsArrayElemType = translateTypeBinding(javaArrayElemType); - return arrayType(stsArrayElemType, javaType.getDimensions()); + return arrayType(stsArrayElemType, javaTypeBinding.getDimensions()); } - if (javaType.isParameterizedType()) { - ITypeBinding javaErasedType = javaType.getErasure(); + if (javaTypeBinding.isParameterizedType()) { + ITypeBinding javaErasedType = javaTypeBinding.getErasure(); ParserRuleContext stsType = translateTypeBinding(javaErasedType); if (stsType.getRuleIndex() != StaticTSParser.RULE_typeReference) { stsType = unknownTypeReference(javaErasedType.getQualifiedName()); @@ -263,16 +263,16 @@ public class NodeBuilder extends NodeBuilderBase { // Translate type arguments and inject them into last child of TypeReferenceContext node TypeReferencePartContext stsLastTypePart = (TypeReferencePartContext)stsType.getChild(stsType.getChildCount()-1); - TypeArgumentsContext stsTypeArgs = translateTypeArguments(javaType.getTypeArguments()); + TypeArgumentsContext stsTypeArgs = translateTypeArguments(javaTypeBinding.getTypeArguments()); stsLastTypePart.addChild(stsTypeArgs).setParent(stsLastTypePart); return stsType; } - if (javaType.isWildcardType()) { + if (javaTypeBinding.isWildcardType()) { WildcardTypeContext stsWildCardType = new WildcardTypeContext(null, 0); - ITypeBinding javaBoundType = javaType.getBound(); + ITypeBinding javaBoundType = javaTypeBinding.getBound(); if (javaBoundType != null) { - String stsInOrOutKeyword = javaType.isUpperbound() ? StaticTSParser.OUT : StaticTSParser.IN; + String stsInOrOutKeyword = javaTypeBinding.isUpperbound() ? StaticTSParser.OUT : StaticTSParser.IN; stsWildCardType.addChild(terminalIdentifier(stsInOrOutKeyword)); ParserRuleContext stsBoundType = translateTypeBinding(javaBoundType); stsWildCardType.addChild(stsBoundType).setParent(stsWildCardType); @@ -283,9 +283,9 @@ public class NodeBuilder extends NodeBuilderBase { return stsWildCardType; } - if (javaType.isIntersectionType()) { + if (javaTypeBinding.isIntersectionType()) { IntersectionTypeContext stsIntersectionType = new IntersectionTypeContext(null, 0); - for (ITypeBinding javaIntersectedType : javaType.getTypeBounds()) { + for (ITypeBinding javaIntersectedType : javaTypeBinding.getTypeBounds()) { ParserRuleContext stsIntersectedType = translateTypeBinding(javaIntersectedType); stsIntersectionType.addChild(stsIntersectedType).setParent(stsIntersectionType); } @@ -293,8 +293,8 @@ public class NodeBuilder extends NodeBuilderBase { } // All other types should be named - just emit TypeReferenceContext - TypeReferenceContext stsTypeRef = typeReference(javaType.getQualifiedName()); - addEmptyTypeArgumentsToRawType(stsTypeRef, javaType); + TypeReferenceContext stsTypeRef = typeReference(javaTypeBinding.getQualifiedName()); + addEmptyTypeArgumentsToRawType(stsTypeRef, javaTypeBinding); return stsTypeRef; } diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java index 24b6afae7..193484034 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java @@ -218,6 +218,7 @@ public class NodeBuilderBase { TypeReferenceContext stsTypeReference = new TypeReferenceContext(null, 0); TypeReferencePartContext stsTypeRefPart = typeReferencePart(typeName); stsTypeReference.addChild(stsTypeRefPart).setParent(stsTypeReference); + //stsTypeReference.javaObjectType = typeName; return stsTypeReference; } @@ -367,6 +368,7 @@ public class NodeBuilderBase { public static void addArgument(CallExpressionContext stsCallExpr, SingleExpressionContext stsArg) { ArgumentsContext stsArgs = stsCallExpr.arguments(); + if (stsArgs != null) { ExpressionSequenceContext stsExprSeq = stsArgs.expressionSequence(); if (stsExprSeq != null) { @@ -383,6 +385,21 @@ public class NodeBuilderBase { if (stsTypeRef != null) { stsThisExpression.addChild(stsTypeRef).setParent(stsThisExpression); } + + stsThisExpression.addChild(terminalNode(StaticTSParser.This)); + + return stsSingleExpr; + } + + public static SingleExpressionContext superExpression(TypeReferenceContext stsTypeRef) { + SingleExpressionContext stsSingleExpr = new SingleExpressionContext(null, 0); + SuperExpressionContext stsThisExpression = new SuperExpressionContext(stsSingleExpr); + stsSingleExpr.addChild(stsThisExpression).setParent(stsSingleExpr); + + if (stsTypeRef != null) { + stsThisExpression.addChild(stsTypeRef).setParent(stsThisExpression); + } + stsThisExpression.addChild(terminalNode(StaticTSParser.This)); return stsSingleExpr; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java old mode 100755 new mode 100644 index 87309989b..87d1b652a --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java @@ -1,8 +1,6 @@ package com.ohos.migrator.staticTS.parser; -import com.ohos.migrator.staticTS.writer.StaticTSWriter; import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ParseTreeVisitor; import org.antlr.v4.runtime.tree.TerminalNode; import java.util.LinkedList; @@ -12,6 +10,14 @@ public class StaticTSContextBase extends ParserRuleContext { private List leadingComments; private List trailingComments; + // The fields used by the API mapper: + public String javaPackage = null; + public String javaObjectType = null; + public String javaObjectTypeArgs = null; + public String javaName = null; + public String javaMethodArgs = null; + public String javaMethodTypeArgs = null; + public StaticTSContextBase() { } public StaticTSContextBase(ParserRuleContext parent, int invokingStateNumber) { diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 424289de1..13d34f331 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -896,6 +896,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { } // importDeclaration: Import qualifiedName (Dot Multiply)? SemiColon? + // importDeclaration: Import qualifiedName ((As Identifier) | (Dot Multiply))? SemiColon? // notLineTerminator public Void visitImportDeclaration(ImportDeclarationContext stsImportDeclaration) { doNeededIndent(); writeLeadingComments(stsImportDeclaration); diff --git a/migrator/test/java-mapper/CallExpressionRules1.java b/migrator/test/java-mapper/CallExpressionRules1.java new file mode 100644 index 000000000..94b557827 --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules1.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +import java.util.ArrayList; +import java.util.List; + +class CallExpressiontRules1 { + public static void Test() { + List lst = new ArrayList(); + lst.add(1); + lst.add(2); + + for (int i = 0; i < lst.size(); i++) { + System.out.print(lst.get(i)); + } + + //System.out.println(lst.get(0)); + + Number d[] = lst.toArray(new Number[0]); + + System.out.println(d); + } +} \ No newline at end of file diff --git a/migrator/test/java-mapper/CallExpressionRules1.java.sts b/migrator/test/java-mapper/CallExpressionRules1.java.sts new file mode 100644 index 000000000..6cd6b5f72 --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules1.java.sts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import std.math; +import java.util.ArrayList; +import java.util.List; +open class CallExpressiontRules1 { + public static Test(): void { + let lst : List = new ArrayList(); + lst.add(1); + lst.add(2); + for (let i : int = 0; i < lst.size(); i++) { + System.out.print(lst.get(i)); + } +//System.out.println(lst.get(0)); + let d : Number = lst.toArray(new Number[0]); + System.out.println(d); + } +} + diff --git a/migrator/test/java-mapper/CallExpressionRules2.java b/migrator/test/java-mapper/CallExpressionRules2.java new file mode 100644 index 000000000..a5af29061 --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules2.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +import java.util.ArrayList; +import java.util.List; + +class CallExpressiontRules1 { + public static void Test() { + List lst = new ArrayList(); + lst.add(1); + lst.add(2); + + lst.set(0, "test value"); + +// Number d[] = lst.toArray(new Number[0]); +// +// System.out.println(d); + } +} \ No newline at end of file diff --git a/migrator/test/java-mapper/CallExpressionRules2.java.sts b/migrator/test/java-mapper/CallExpressionRules2.java.sts new file mode 100644 index 000000000..1db9105c6 --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules2.java.sts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import java.util.ArrayList; +import java.util.List; +open class CallExpressiontRules1 { + public static Test(): void { + let lst : List<> = new ArrayList<>(); + lst.add(1); + lst.add(2); + lst.set("test value", 0); + } +// Number d[] = lst.toArray(new Number[0]); +// +// System.out.println(d); +} + diff --git a/migrator/test/java-mapper/CallExpressionRules3.java b/migrator/test/java-mapper/CallExpressionRules3.java new file mode 100644 index 000000000..c22034223 --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules3.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +class CallExpressiontRules3 { + public static void CallExpressiontRules3() { + int exp_f = Math.getExponent(3.f); + int exp_d = Math.getExponent(4.); + } +} \ No newline at end of file diff --git a/migrator/test/java-mapper/CallExpressionRules3.java.sts b/migrator/test/java-mapper/CallExpressionRules3.java.sts new file mode 100644 index 000000000..b21b76a3d --- /dev/null +++ b/migrator/test/java-mapper/CallExpressionRules3.java.sts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import std.math; +open class CallExpressiontRules3 { + public static CallExpressiontRules3(): void { + let exp_f : int = Math.getExponent(3.); + let exp_d : int = Math.getExponent(4.); + } +} + diff --git a/migrator/test/java-mapper/ImportRules1.java b/migrator/test/java-mapper/ImportRules1.java new file mode 100644 index 000000000..5282ee5d3 --- /dev/null +++ b/migrator/test/java-mapper/ImportRules1.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +import java.util.Collection; +import java.util.ArrayList; +import java.util.Arrays; // +import java.util.Set; // +import java.util.HashSet; + +class ImportRules1 { + public static void Test() { + int[] array = null; + + int sum = 0; + for (int num : array) + sum += num; + + sum = 0; + Collection list = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + sum += i; + } + + Set set = new HashSet(); + set.add("a"); + set.add("b"); + + int[] c = Arrays.copyOf(array); + } +} \ No newline at end of file diff --git a/migrator/test/java-mapper/ImportRules1.java.sts b/migrator/test/java-mapper/ImportRules1.java.sts new file mode 100644 index 000000000..b7b9d1fb4 --- /dev/null +++ b/migrator/test/java-mapper/ImportRules1.java.sts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import java.util.Collection; +import java.util.ArrayList; +import std.array.sort.*; +import std.array.methods.*; +import std.containers.Set; +import java.util.HashSet; +open class ImportRules1 { + public static Test(): void { + let array : int[] = null; + let sum : int = 0; + for (let num : int of array)sum += num; + sum = 0; + let list : Collection = new ArrayList(); + for (let i : int = 0; i < list.size(); i++) { + sum += i; + } + let set : Set<> = new HashSet(); + set.add("a"); + set.add("b"); + let c : int[] = Arrays.copyOf(array); + } +} diff --git a/migrator/test/java-mapper/TypeReference1.java b/migrator/test/java-mapper/TypeReference1.java new file mode 100644 index 000000000..c9b4b5a3e --- /dev/null +++ b/migrator/test/java-mapper/TypeReference1.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +class TypeReference1 { + private static void foo(Integer i) { + if (i > 0) + System.out.print(i); + } + + public static void TypeReference1() { + foo(2); + foo(-1); + } +} \ No newline at end of file diff --git a/migrator/test/java-mapper/TypeReference1.java.sts b/migrator/test/java-mapper/TypeReference1.java.sts new file mode 100644 index 000000000..76f84e4fe --- /dev/null +++ b/migrator/test/java-mapper/TypeReference1.java.sts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import std.math; +open class TypeReference1 { + private static foo(i : Int): void { + if (i > 0) System.out.print(i); + } + public static TypeReference1(): void { + foo(2); + foo(-1); + } +} + diff --git a/migrator/test/java/array_creation.java.sts b/migrator/test/java/array_creation.java.sts index f71941dc6..bbba8b303 100644 --- a/migrator/test/java/array_creation.java.sts +++ b/migrator/test/java/array_creation.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; export open class array_creation { private const b1 : byte[] = new byte[8]; private const b2 : byte[][] = new byte[8][]; diff --git a/migrator/test/java/array_type.java.sts b/migrator/test/java/array_type.java.sts index a6718858e..f44a7787f 100644 --- a/migrator/test/java/array_type.java.sts +++ b/migrator/test/java/array_type.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class array_type { private a : int[] ; protected f : float[][][] ; diff --git a/migrator/test/java/assert.java.sts b/migrator/test/java/assert.java.sts index 72da57f5e..395610eda 100644 --- a/migrator/test/java/assert.java.sts +++ b/migrator/test/java/assert.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class test_assert { open test(x : int): void { assert x > 10; diff --git a/migrator/test/java/assignments.java.sts b/migrator/test/java/assignments.java.sts index ca14db364..eba5e23fb 100644 --- a/migrator/test/java/assignments.java.sts +++ b/migrator/test/java/assignments.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class AssignmentsTest { a : int ; b : int ; diff --git a/migrator/test/java/binary_operations.java.sts b/migrator/test/java/binary_operations.java.sts index c2a67f15c..994dcffdf 100644 --- a/migrator/test/java/binary_operations.java.sts +++ b/migrator/test/java/binary_operations.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class binary_operations { private sum1 : int = 3 + 2; private sum2 : int = 3 + 2 - 4 + 1; diff --git a/migrator/test/java/class_instance_creation.java.sts b/migrator/test/java/class_instance_creation.java.sts index 2bfd07f88..3f4587de5 100644 --- a/migrator/test/java/class_instance_creation.java.sts +++ b/migrator/test/java/class_instance_creation.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class class_instance_creation { constructor(i : int) { } diff --git a/migrator/test/java/class_instance_initializer.java.sts b/migrator/test/java/class_instance_initializer.java.sts index 1d66c6cf9..35a7abb6c 100644 --- a/migrator/test/java/class_instance_initializer.java.sts +++ b/migrator/test/java/class_instance_initializer.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class A { a : int = 1; b : int = 3; diff --git a/migrator/test/java/class_static_initializer.java.sts b/migrator/test/java/class_static_initializer.java.sts index c1bc35b8a..114ff0299 100644 --- a/migrator/test/java/class_static_initializer.java.sts +++ b/migrator/test/java/class_static_initializer.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class MyClass { static a : int = 1; static { diff --git a/migrator/test/java/conditional_expression.java.sts b/migrator/test/java/conditional_expression.java.sts index 432ed0b68..28077682a 100644 --- a/migrator/test/java/conditional_expression.java.sts +++ b/migrator/test/java/conditional_expression.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.tests.java; +import std.math; open class ConditionalExpression { public open Test(): void { let value1 : int = 1; diff --git a/migrator/test/java/constructor_test.java.sts b/migrator/test/java/constructor_test.java.sts index f4a251eab..08a890b19 100644 --- a/migrator/test/java/constructor_test.java.sts +++ b/migrator/test/java/constructor_test.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; export open class constructor_test { public constructor() { this(0); diff --git a/migrator/test/java/do_statement.java.sts b/migrator/test/java/do_statement.java.sts index 180672704..acc416b7f 100644 --- a/migrator/test/java/do_statement.java.sts +++ b/migrator/test/java/do_statement.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class do_statement { public static Test(): void { const Flag : boolean = true; diff --git a/migrator/test/java/empty_class.java.sts b/migrator/test/java/empty_class.java.sts index 5f90094f9..52b34d2be 100644 --- a/migrator/test/java/empty_class.java.sts +++ b/migrator/test/java/empty_class.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class empty_class { } diff --git a/migrator/test/java/empty_statement.java.sts b/migrator/test/java/empty_statement.java.sts index 4423bbee9..389b152ab 100644 --- a/migrator/test/java/empty_statement.java.sts +++ b/migrator/test/java/empty_statement.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class empty_statement { a : int ; public open Test(): void { diff --git a/migrator/test/java/enhanced_for_statement.java.sts b/migrator/test/java/enhanced_for_statement.java.sts index 11e272855..212f9a586 100644 --- a/migrator/test/java/enhanced_for_statement.java.sts +++ b/migrator/test/java/enhanced_for_statement.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; import java.util.Collection; import java.util.ArrayList; open class EnhancedForStatements { diff --git a/migrator/test/java/enum_with_class_behavior.java.sts b/migrator/test/java/enum_with_class_behavior.java.sts index 367f7e1de..37178fd7e 100644 --- a/migrator/test/java/enum_with_class_behavior.java.sts +++ b/migrator/test/java/enum_with_class_behavior.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; // Enum implements an interface. // Constants with class body (anonymous class declaration). interface IOperation { diff --git a/migrator/test/java/field_decl.java.sts b/migrator/test/java/field_decl.java.sts index 87ed5bfcc..47fe2a6bb 100644 --- a/migrator/test/java/field_decl.java.sts +++ b/migrator/test/java/field_decl.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class field_decl { private a : int ; protected b : char ; diff --git a/migrator/test/java/final_empty_class.java.sts b/migrator/test/java/final_empty_class.java.sts index 0b13e1db4..dc3fcb579 100644 --- a/migrator/test/java/final_empty_class.java.sts +++ b/migrator/test/java/final_empty_class.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export class final_empty_class { } diff --git a/migrator/test/java/for_statement.java.sts b/migrator/test/java/for_statement.java.sts index c1c6e6c92..c4fb95c16 100644 --- a/migrator/test/java/for_statement.java.sts +++ b/migrator/test/java/for_statement.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class ForStatements { public static Test(): void { for (; ; ) break; diff --git a/migrator/test/java/generic_class_1.java.sts b/migrator/test/java/generic_class_1.java.sts index f398b2cf8..53ea213f2 100644 --- a/migrator/test/java/generic_class_1.java.sts +++ b/migrator/test/java/generic_class_1.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; // Java specification Example 8.1.2-1. Mutually Recursive Type Variable Bounds: interface ConvertibleTo { convert(): T ; diff --git a/migrator/test/java/generic_class_2.java.sts b/migrator/test/java/generic_class_2.java.sts index b3b7db21d..78e04c0f1 100644 --- a/migrator/test/java/generic_class_2.java.sts +++ b/migrator/test/java/generic_class_2.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; // Java specification Example 8.1.2-2. Nested Generic Classes open class Seq { head : T ; diff --git a/migrator/test/java/generic_class_3.java.sts b/migrator/test/java/generic_class_3.java.sts index 4fa4facde..e5ec40d32 100644 --- a/migrator/test/java/generic_class_3.java.sts +++ b/migrator/test/java/generic_class_3.java.sts @@ -15,22 +15,23 @@ package com.ohos.migrator.test.java; +import std.math; interface Fun { apply(arg : T): R ; } open class C { - open size(): Integer { + open size(): Int { return 0; } - open size(arg : Object): Integer { + open size(arg : Object): Int { return 1; } - open size(arg : C): Integer { + open size(arg : C): Int { return 2; } static open class H { - open size(): Integer { + open size(): Int { return 3; } } diff --git a/migrator/test/java/generic_class_4.java.sts b/migrator/test/java/generic_class_4.java.sts index cf2e51d96..6ca52dec2 100644 --- a/migrator/test/java/generic_class_4.java.sts +++ b/migrator/test/java/generic_class_4.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class test_generic { open choose(b : boolean, c1 : Class, c2 : Class): Class { return b ? c1 : c2; diff --git a/migrator/test/java/generic_interface_1.java.sts b/migrator/test/java/generic_interface_1.java.sts index 6888eb8f3..160fb9273 100644 --- a/migrator/test/java/generic_interface_1.java.sts +++ b/migrator/test/java/generic_interface_1.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; // Java specification Example 9.8-3. Generic Functional Interfaces interface I { m(c : Class<>): Object ; diff --git a/migrator/test/java/generic_interface_2.java.sts b/migrator/test/java/generic_interface_2.java.sts index 39cf74cd9..5a84f80fe 100644 --- a/migrator/test/java/generic_interface_2.java.sts +++ b/migrator/test/java/generic_interface_2.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; // Java specification Example 9.9-2. Generic Function Types interface G1 { m(): Object throws ; diff --git a/migrator/test/java/if.java.sts b/migrator/test/java/if.java.sts index 1eef9e767..4197fd188 100644 --- a/migrator/test/java/if.java.sts +++ b/migrator/test/java/if.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class IfTest { public open Test(): void { let t : boolean = true; diff --git a/migrator/test/java/inferred_types.java.sts b/migrator/test/java/inferred_types.java.sts index c1e33975f..383759048 100644 --- a/migrator/test/java/inferred_types.java.sts +++ b/migrator/test/java/inferred_types.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; import java.util.List; open class Main { // Java language allows to omit return/parameter types for lambda expression. diff --git a/migrator/test/java/inheritance.java.sts b/migrator/test/java/inheritance.java.sts index b069d5614..91125e1f7 100644 --- a/migrator/test/java/inheritance.java.sts +++ b/migrator/test/java/inheritance.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; interface interface_a { } diff --git a/migrator/test/java/interface_nested.java.sts b/migrator/test/java/interface_nested.java.sts index 088e675be..5897b5f0b 100644 --- a/migrator/test/java/interface_nested.java.sts +++ b/migrator/test/java/interface_nested.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; import java.util.List; import java.io.*; interface Test { diff --git a/migrator/test/java/interface_public.java.sts b/migrator/test/java/interface_public.java.sts index 06409cf69..81aaaba8d 100644 --- a/migrator/test/java/interface_public.java.sts +++ b/migrator/test/java/interface_public.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; import java.util.List; import java.io.*; export interface interface_public { diff --git a/migrator/test/java/intersection-type.java.sts b/migrator/test/java/intersection-type.java.sts index dea5be549..f6248b2cd 100755 --- a/migrator/test/java/intersection-type.java.sts +++ b/migrator/test/java/intersection-type.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class intersection_type { public open bar(arg : auxilliary): void { let r : Runnable = arg as (Runnable & Something); diff --git a/migrator/test/java/labeled.java.sts b/migrator/test/java/labeled.java.sts index 657fe642e..26dd43cef 100644 --- a/migrator/test/java/labeled.java.sts +++ b/migrator/test/java/labeled.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class LabeledTest { a : int ; public open Test(): void { diff --git a/migrator/test/java/lambda_expr.java.sts b/migrator/test/java/lambda_expr.java.sts index 604fe6764..556e10698 100644 --- a/migrator/test/java/lambda_expr.java.sts +++ b/migrator/test/java/lambda_expr.java.sts @@ -12,8 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.ohos.migrator.tests.java; +package com.ohos.migrator.tests.java; +import std.math; open class Main { interface I1 { M(): void ; diff --git a/migrator/test/java/literals.java.sts b/migrator/test/java/literals.java.sts index ac56696e0..536536934 100755 --- a/migrator/test/java/literals.java.sts +++ b/migrator/test/java/literals.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class literals { open test(): void { // integer literals diff --git a/migrator/test/java/method_empty.java.sts b/migrator/test/java/method_empty.java.sts index 3f026008f..75f9a5f72 100644 --- a/migrator/test/java/method_empty.java.sts +++ b/migrator/test/java/method_empty.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; open class A { public open foo(): void { } diff --git a/migrator/test/java/method_full.java.sts b/migrator/test/java/method_full.java.sts index 0cf0b6554..5f8aafe8a 100644 --- a/migrator/test/java/method_full.java.sts +++ b/migrator/test/java/method_full.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; abstract class method_full { open foo(): void { } diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index a2b0bacd5..9b6a4f8f7 100755 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; open class SuperClass { open foo(): void { System.out.println("Hi"); diff --git a/migrator/test/java/method_references.java.sts b/migrator/test/java/method_references.java.sts index 096e71baf..5d89804de 100644 --- a/migrator/test/java/method_references.java.sts +++ b/migrator/test/java/method_references.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; open class MethodReferencesExamples { interface Function0 { apply(): T ; @@ -130,8 +131,8 @@ open class MethodReferencesExamples { intArray = myApp.factory((__migrator_lambda_param_1 : int[]): int[] =>__migrator_lambda_param_1.clone(), intArray); } public static arrayCreationReferences(): void { - let arrayFactory1 : ArrayFactory = (__migrator_lambda_param_1 : int): Integer[] =>new Integer[__migrator_lambda_param_1]; - let newArray : Integer[] = arrayFactory1.createArray(5); + let arrayFactory1 : ArrayFactory = (__migrator_lambda_param_1 : int): Int[] =>new Int[__migrator_lambda_param_1]; + let newArray : Int[] = arrayFactory1.createArray(5); let arrayFactory2 : ArrayFactory2 = (__migrator_lambda_param_1 : int): String[][] =>new String[__migrator_lambda_param_1][]; let newArray2 : String[][] = arrayFactory2.createArray(10); let arrayFactory3 : ArrayFactory3 = (__migrator_lambda_param_1 : int): Double[][][] =>new Double[__migrator_lambda_param_1][][]; diff --git a/migrator/test/java/named_types.java.sts b/migrator/test/java/named_types.java.sts index 6557fd482..c64b8249e 100644 --- a/migrator/test/java/named_types.java.sts +++ b/migrator/test/java/named_types.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; import java.util.List; import java.lang.annotation.*; open class named_types { diff --git a/migrator/test/java/npe_in_ctor_declaration.java.sts b/migrator/test/java/npe_in_ctor_declaration.java.sts index a1e8b232b..adad2e4ff 100644 --- a/migrator/test/java/npe_in_ctor_declaration.java.sts +++ b/migrator/test/java/npe_in_ctor_declaration.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class npe_in_ctor_declaration { /* Untranslated constructor declaration: native npe_in_ctor_declaration(); diff --git a/migrator/test/java/npe_in_method_declaration.java.sts b/migrator/test/java/npe_in_method_declaration.java.sts index f317fe41b..1eb5116e1 100644 --- a/migrator/test/java/npe_in_method_declaration.java.sts +++ b/migrator/test/java/npe_in_method_declaration.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class npe_in_method_header { /* Untranslated method declaration: void TestID(){ diff --git a/migrator/test/java/npe_in_method_reference.java.sts b/migrator/test/java/npe_in_method_reference.java.sts index 53e872f45..8d22dc7ba 100644 --- a/migrator/test/java/npe_in_method_reference.java.sts +++ b/migrator/test/java/npe_in_method_reference.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.tests.java; +import std.math; interface Action { run(): void ; } diff --git a/migrator/test/java/npe_in_type_argument.java.sts b/migrator/test/java/npe_in_type_argument.java.sts index 81d66ca0d..49d2c602f 100755 --- a/migrator/test/java/npe_in_type_argument.java.sts +++ b/migrator/test/java/npe_in_type_argument.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class A { } diff --git a/migrator/test/java/npe_in_type_parameter_bound.java.sts b/migrator/test/java/npe_in_type_parameter_bound.java.sts index c2e6955aa..c0570deec 100644 --- a/migrator/test/java/npe_in_type_parameter_bound.java.sts +++ b/migrator/test/java/npe_in_type_parameter_bound.java.sts @@ -15,5 +15,6 @@ package com.ohos.migrator.test.java; +import std.math; open class npe_in_type_parameter_bound { } diff --git a/migrator/test/java/npe_in_wildcard_bound.java.sts b/migrator/test/java/npe_in_wildcard_bound.java.sts index f54c0d697..47c9a7b1d 100644 --- a/migrator/test/java/npe_in_wildcard_bound.java.sts +++ b/migrator/test/java/npe_in_wildcard_bound.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class npe_in_wildcard_bound { open test(): Class { return null; diff --git a/migrator/test/java/super_expression.java.sts b/migrator/test/java/super_expression.java.sts index 660ed7736..e43e2f6f2 100644 --- a/migrator/test/java/super_expression.java.sts +++ b/migrator/test/java/super_expression.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; interface I { x : int = 0; } diff --git a/migrator/test/java/switch_statement.java.sts b/migrator/test/java/switch_statement.java.sts index c76cfc3d9..e927c8b8e 100644 --- a/migrator/test/java/switch_statement.java.sts +++ b/migrator/test/java/switch_statement.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class switch_statement { public static ReturnFromSwitch(id : int): String { switch (id) { diff --git a/migrator/test/java/synchronized_blocks.java.sts b/migrator/test/java/synchronized_blocks.java.sts index 9116b4b75..e6e9e6fe9 100644 --- a/migrator/test/java/synchronized_blocks.java.sts +++ b/migrator/test/java/synchronized_blocks.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class synchronized_blocks { public static main(args : String[]): void { let t : synchronized_blocks = new synchronized_blocks(); diff --git a/migrator/test/java/synchronized_methods.java.sts b/migrator/test/java/synchronized_methods.java.sts index b0de0936a..ef24d6dd8 100644 --- a/migrator/test/java/synchronized_methods.java.sts +++ b/migrator/test/java/synchronized_methods.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class synchronized_methods { count : int ; open bump(): void { diff --git a/migrator/test/java/test_enum.java.sts b/migrator/test/java/test_enum.java.sts index 3b8400154..ddf98574a 100644 --- a/migrator/test/java/test_enum.java.sts +++ b/migrator/test/java/test_enum.java.sts @@ -13,6 +13,8 @@ * limitations under the License. */ package com.ohos.migrator.test.java; + +import std.math; // Empty enum export class test_enum extends Enum { public static values(): test_enum[] { diff --git a/migrator/test/java/test_interface.java.sts b/migrator/test/java/test_interface.java.sts index 4027c2fdb..311f2a37d 100644 --- a/migrator/test/java/test_interface.java.sts +++ b/migrator/test/java/test_interface.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; import java.util.List; import java.io.*; interface test_interface { diff --git a/migrator/test/java/this_expression.java.sts b/migrator/test/java/this_expression.java.sts index f5d942f63..a01510582 100644 --- a/migrator/test/java/this_expression.java.sts +++ b/migrator/test/java/this_expression.java.sts @@ -15,6 +15,7 @@ package com.ohos.migrator.test.java; +import std.math; open class this_expression { v : int[] ; diff --git a/migrator/test/java/throw_statement.java.sts b/migrator/test/java/throw_statement.java.sts index 12020ddb5..e673c3d51 100644 --- a/migrator/test/java/throw_statement.java.sts +++ b/migrator/test/java/throw_statement.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class throw_statement { private const i : int = 0x7fff; public open class Panic extends RuntimeException { diff --git a/migrator/test/java/throws_test.java.sts b/migrator/test/java/throws_test.java.sts index d5134b3b6..5c73842ea 100644 --- a/migrator/test/java/throws_test.java.sts +++ b/migrator/test/java/throws_test.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.tests.java; +import std.math; open class MyException extends Exception { constructor() { } @@ -63,14 +64,14 @@ open class SubClass2 extends SubClass1 { } public override foo(): void { - super.foo(); + try super.foo(); } public open bar(): void throws { - super.foo(); + try super.foo(); throw new AnotherException(); } public override toto(): void throws { - super.toto(); + try super.toto(); } } diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index 61ee0a7a4..ecebf76b0 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class BlewIt extends Exception { constructor() { } diff --git a/migrator/test/java/try_with_resources.java.sts b/migrator/test/java/try_with_resources.java.sts index d296081d1..f07bf0a74 100644 --- a/migrator/test/java/try_with_resources.java.sts +++ b/migrator/test/java/try_with_resources.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; diff --git a/migrator/test/java/type_cast.java.sts b/migrator/test/java/type_cast.java.sts index 5eb5377cb..bbe39afb3 100644 --- a/migrator/test/java/type_cast.java.sts +++ b/migrator/test/java/type_cast.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class type_cast { private i1 : int = 34; private d : double = 3.7; diff --git a/migrator/test/java/unary_operations.java.sts b/migrator/test/java/unary_operations.java.sts index 2b5ca885c..3094a0274 100644 --- a/migrator/test/java/unary_operations.java.sts +++ b/migrator/test/java/unary_operations.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; export open class unary_operations { private a : int = 3; private pref1 : int = +a; diff --git a/migrator/test/java/var_declare.java.sts b/migrator/test/java/var_declare.java.sts index 3f0a69f1b..9fbe4c795 100644 --- a/migrator/test/java/var_declare.java.sts +++ b/migrator/test/java/var_declare.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class VarDeclareTest { public open Test(): void { let a : int ; diff --git a/migrator/test/java/while_statement.java.sts b/migrator/test/java/while_statement.java.sts index 53b82645a..82b72ad25 100644 --- a/migrator/test/java/while_statement.java.sts +++ b/migrator/test/java/while_statement.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; open class while_statement { public static Test(): void { const Flag : boolean = true; -- Gitee From 139aff8e1b5cba91377f1ba51d39435654c331ff Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Wed, 16 Nov 2022 12:40:16 +0300 Subject: [PATCH 02/15] A special targed 'test_java_api' is added to the build script to run API mapping tests. Change-Id: Ia8d1807ab910593020e71ac6dd73e803dbbb7532 Signed-off-by: Alexander Pavlyuk --- migrator/build.xml | 67 ++++++++++++++ migrator/config/java-api-mapper.xml | 28 +++--- .../src/com/ohos/migrator/TestRunner.java | 2 +- .../ohos/migrator/java/JavaTransformer.java | 92 +++++++------------ .../ohos/migrator/java/JavaTranspiler.java | 2 - .../java-mapper/CallExpressionRules2.java.sts | 3 +- migrator/test/java-mapper/ImportRules1.java | 2 +- .../test/java-mapper/ImportRules1.java.sts | 3 +- 8 files changed, 122 insertions(+), 77 deletions(-) diff --git a/migrator/build.xml b/migrator/build.xml index c0163b9ca..d51980800 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -217,6 +217,73 @@ ${test.err} + + + + + + + + + + + + + + + + + One or several tests have failed! + STDERR: + ${test.err} + + + + + + + + + + + + + + + + + + + + + + + + + One or several tests have failed! + STDERR: + ${test.err} + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/migrator/src/com/ohos/migrator/TestRunner.java b/migrator/src/com/ohos/migrator/TestRunner.java index 69e59aad6..55281ae54 100644 --- a/migrator/src/com/ohos/migrator/TestRunner.java +++ b/migrator/src/com/ohos/migrator/TestRunner.java @@ -28,6 +28,7 @@ public class TestRunner { static { testExtensions.put("java", Main.JAVA_EXT); + testExtensions.put("java-mapper", Main.JAVA_EXT); testExtensions.put("kotlin", Main.KOTLIN_EXT); testExtensions.put("staticTS", Main.STS_EXT); } @@ -35,7 +36,6 @@ public class TestRunner { public static void main(String[] args) { assert(args.length == 1); - String ext = testExtensions.get(args[0]); File testDir = new File("test", args[0]); File testResultDir = new File(testDir, "results"); diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 1b40cf21c..9977197e3 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -2941,12 +2941,27 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // ) @Override public boolean visit(ConstructorInvocation javaCtorInvocation) { - IMethodBinding javaCtorBinding = javaCtorInvocation.resolveConstructorBinding(); + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.This), javaCtorInvocation.typeArguments(), + null, javaCtorInvocation.arguments(), javaCtorInvocation.resolveConstructorBinding(), + javaCtorInvocation); + + return false; + } + + // NOTE: If ctor called can throw exceptions, prepend 'try' keyword to result. + private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, + Expression javaCtorExpr, List javaArgs, + IMethodBinding javaCtorBinding, ASTNode javaCtorInvocation) { boolean isThrowingCall = false; ConstructorCallContext stsConstructorCall = new ConstructorCallContext(stsCurrent, 0); + ITypeBinding javaClassType = null; + if (javaCtorExpr != null) { + javaClassType = javaCtorExpr.resolveTypeBinding(); + } + if (javaCtorBinding != null) { isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; if(isThrowingCall && checkThrownExceptionSet(javaCtorInvocation)) @@ -2954,16 +2969,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsConstructorCall.javaMethodArgs = buildSignature(javaCtorBinding.getParameterTypes()); - //ITypeBinding javaClassType = javaCtorInvocation.getExpression().resolveTypeBinding(); - ITypeBinding javaClassType = javaCtorBinding.getDeclaringClass(); - stsConstructorCall.javaObjectType = javaClassType.getQualifiedName(); - //stsConstructorCall.javaObjectType = javaCtorBinding.getDeclaringClass().getQualifiedName(); - stsConstructorCall.javaObjectTypeArgs = buildSignature(javaClassType.getTypeArguments()); + if (javaCtorExpr == null) { + javaClassType = javaCtorBinding.getDeclaringClass(); + } } else { reportError("Failed to resolve constructor call", javaCtorInvocation); } + if (javaClassType != null) { + stsConstructorCall.javaObjectType = javaClassType.getQualifiedName(); + stsConstructorCall.javaObjectTypeArgs = buildSignature(javaClassType.getTypeArguments()); + } + pushCurrent(stsConstructorCall); // Add 'try' keyword if this is a throwing call. @@ -2971,17 +2989,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.This)); + if (javaCtorExpr != null) { + javaCtorExpr.accept(this); + } + + stsCurrent.addChild(stsThisOrSuper); - translateTypeArguments(javaCtorInvocation.typeArguments()); - stsConstructorCall.javaMethodTypeArgs = buildSignature(javaCtorInvocation.typeArguments()); + translateTypeArguments(javaTypeArgs); + stsConstructorCall.javaMethodTypeArgs = buildSignature(javaTypeArgs); - translateArguments(javaCtorInvocation.arguments()); + translateArguments(javaArgs); popCurrent(); // ConstructorCallContext stmtTransformed.add(javaCtorInvocation); - return false; } private void reportError(String message, ASTNode node) { @@ -2999,53 +3020,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | (singleExpression . )? super typeArguments? arguments SemiColon @Override public boolean visit(SuperConstructorInvocation javaSuperCtorInvocation) { - boolean isThrowingCall = false; - ConstructorCallContext stsConstructorCall = new ConstructorCallContext(stsCurrent, 0); - - IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); - if (javaCtorBinding != null) { - isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; - if(isThrowingCall && checkThrownExceptionSet(javaSuperCtorInvocation)) - addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); - - stsConstructorCall.javaMethodArgs = buildSignature(javaCtorBinding.getParameterTypes()); - Expression javaExpression = javaSuperCtorInvocation.getExpression(); - - if (javaExpression != null) { - ITypeBinding javaClassType = javaExpression.resolveTypeBinding(); - if (javaClassType != null) { - stsConstructorCall.javaObjectType = javaClassType.getQualifiedName(); - //stsConstructorCall.javaObjectType = javaCtorBinding.getDeclaringClass().getQualifiedName(); - stsConstructorCall.javaObjectTypeArgs = buildSignature(javaClassType.getTypeArguments()); - } - } - } - else { - reportError("Failed to report constructor call", javaSuperCtorInvocation); - } - - pushCurrent(stsConstructorCall); - - // Add 'try' keyword if this is a throwing call. - if (isThrowingCall) { - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); - } - - Expression javaCtorExpr = javaSuperCtorInvocation.getExpression(); - if (javaCtorExpr != null) { - javaCtorExpr.accept(this); - } - - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Super)); - - translateTypeArguments(javaSuperCtorInvocation.typeArguments()); - stsConstructorCall.javaMethodTypeArgs = buildSignature(javaSuperCtorInvocation.typeArguments()); - - translateArguments(javaSuperCtorInvocation.arguments()); - - popCurrent(); // ConstructorCallContext + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.Super), javaSuperCtorInvocation.typeArguments(), + javaSuperCtorInvocation.getExpression(), javaSuperCtorInvocation.arguments(), + javaSuperCtorInvocation.resolveConstructorBinding(), javaSuperCtorInvocation); - stmtTransformed.add(javaSuperCtorInvocation); return false; } diff --git a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java index 0c15954c7..bed402cdd 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java +++ b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java @@ -97,8 +97,6 @@ public class JavaTranspiler extends AbstractTranspiler { try { File path = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); File configDir = new File(path, "config"); - //String dir = new File(".").getAbsolutePath(); - //File configDir = new File(dir, "config"); File f = new File(configDir, "java-api-mapper.xml"); String rulesFilePath = f.getPath(); JavaApiMapper mapper = JavaApiMapper.readRules(rulesFilePath); diff --git a/migrator/test/java-mapper/CallExpressionRules2.java.sts b/migrator/test/java-mapper/CallExpressionRules2.java.sts index 1db9105c6..94338300f 100644 --- a/migrator/test/java-mapper/CallExpressionRules2.java.sts +++ b/migrator/test/java-mapper/CallExpressionRules2.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; import java.util.ArrayList; import java.util.List; open class CallExpressiontRules1 { @@ -21,7 +22,7 @@ open class CallExpressiontRules1 { let lst : List<> = new ArrayList<>(); lst.add(1); lst.add(2); - lst.set("test value", 0); + lst.set(0, "test value"); } // Number d[] = lst.toArray(new Number[0]); // diff --git a/migrator/test/java-mapper/ImportRules1.java b/migrator/test/java-mapper/ImportRules1.java index 5282ee5d3..eac157cee 100644 --- a/migrator/test/java-mapper/ImportRules1.java +++ b/migrator/test/java-mapper/ImportRules1.java @@ -39,6 +39,6 @@ class ImportRules1 { set.add("a"); set.add("b"); - int[] c = Arrays.copyOf(array); + int[] c = Arrays.copyOf(array, array.length); } } \ No newline at end of file diff --git a/migrator/test/java-mapper/ImportRules1.java.sts b/migrator/test/java-mapper/ImportRules1.java.sts index b7b9d1fb4..327c369f3 100644 --- a/migrator/test/java-mapper/ImportRules1.java.sts +++ b/migrator/test/java-mapper/ImportRules1.java.sts @@ -14,6 +14,7 @@ */ package com.ohos.migrator.test.java; +import std.math; import java.util.Collection; import java.util.ArrayList; import std.array.sort.*; @@ -33,6 +34,6 @@ open class ImportRules1 { let set : Set<> = new HashSet(); set.add("a"); set.add("b"); - let c : int[] = Arrays.copyOf(array); + let c : int[] = Arrays.copyOf(array, array.length); } } -- Gitee From 1662bedf2f327df1c5e316fe652b941f229915a4 Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Mon, 19 Sep 2022 12:26:40 +0300 Subject: [PATCH 03/15] Java API to ArkTS API mapping implementation. Change-Id: I9972202c6b0e452c71f099bfb7db15ec909a5611 Signed-off-by: Alexander Pavlyuk --- .../ohos/migrator/java/JavaTranspiler.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java index bed402cdd..f7ad0436e 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java +++ b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java @@ -91,6 +91,25 @@ public class JavaTranspiler extends AbstractTranspiler { return JavaTransformer.getTransformationRate() * 100.; } + private String exceptionMessage(Exception e) { + String msg = e.getMessage(); + if (msg == null) { + StackTraceElement[] stackTraceElements = e.getStackTrace(); + assert stackTraceElements != null; + int n = Math.min(10, stackTraceElements.length); // Don't write to long stack trace. + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + StackTraceElement ste = stackTraceElements[i]; + sb.append(ste.toString()).append("\n"); + } + + msg = sb.toString(); + } + + return msg; + } + @Override public void migrateAPI(CompilationUnitContext arktsCU) { @@ -103,10 +122,10 @@ public class JavaTranspiler extends AbstractTranspiler { mapper.visitCompilationUnit(arktsCU); } catch (FileNotFoundException | URISyntaxException e) { - Main.addError(ResultCode.InputError, "Fail to find the API mapper rules file. \n" + e.getMessage()); + Main.addError(ResultCode.InputError, "Fail to find the API mapper rules file. \n" + exceptionMessage(e)); } catch (XMLStreamException e) { - Main.addError(ResultCode.ParseError, "Fail to parse the API mapper rules file. \n" + e.getMessage()); + Main.addError(ResultCode.InputError, "Fail to parse the API mapper rules file. \n" + exceptionMessage(e)); } } } -- Gitee From 620400058099febe3c835504cccc8fc762a4867a Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Tue, 1 Nov 2022 14:18:36 +0300 Subject: [PATCH 04/15] TypeScript translator prototype. Change-Id: Ia4fdbe7eaf291faa59e4ace232fbb43044aecfa0 Signed-off-by: Evgeniy Okolnov --- migrator/.gitignore | 1 + migrator/typescript/README.md | 29 ++++++++ migrator/typescript/package-lock.json | 46 ++++++++++++ migrator/typescript/package.json | 10 +++ .../typescript/src/TypeScriptTransformer.ts | 73 +++++++++++++++++++ .../typescript/src/TypeScriptTranspiler.ts | 56 ++++++++++++++ migrator/typescript/tsconfig.json | 13 ++++ 7 files changed, 228 insertions(+) create mode 100644 migrator/typescript/README.md create mode 100644 migrator/typescript/package-lock.json create mode 100644 migrator/typescript/package.json create mode 100644 migrator/typescript/src/TypeScriptTransformer.ts create mode 100644 migrator/typescript/src/TypeScriptTranspiler.ts create mode 100644 migrator/typescript/tsconfig.json diff --git a/migrator/.gitignore b/migrator/.gitignore index dd4b81cb7..dbd1f889b 100644 --- a/migrator/.gitignore +++ b/migrator/.gitignore @@ -15,3 +15,4 @@ StaticTS*Listener.java StaticTS*Visitor.java StaticTSLexer.java StaticTSParser.java +node_modules \ No newline at end of file diff --git a/migrator/typescript/README.md b/migrator/typescript/README.md new file mode 100644 index 000000000..ac5912bd2 --- /dev/null +++ b/migrator/typescript/README.md @@ -0,0 +1,29 @@ +# TypeScript Translator +Translator from TypeScript to StaticTS, written on TypeScript and using TSC API. + +## Prerequisits + +### Visual Studio Code +For development, it's recommended to use VS Code, as it has a full built-in support for TypeScript language. + +### NodeJS and NPM +In order to build and run TypeScript translator, you need to install NodeJS and NPM. It is recommended using a **Node version manager** to install Node and NPM ([nvm](https://github.com/nvm-sh/nvm) for Linux, [nvm-windows](https://github.com/coreybutler/nvm-windows) for windows). You can also follow the [official guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). + +### TypeScript Compiler +The translator itself is written on TypeScript, therefore you need to install TypeScript Compiler in order to build the project: +```bash +npm install -g typescript +``` +See https://www.npmjs.com/package/typescript for more details. + +## Building + +1. `cd` to `migrator/typescript` +2. Run `npm install` to install all project dependencies (need only once per change in dependencies). +3. Run `tsc` to compile project sources. The result JavaScript code is located in `build` directory + +## Running +Run the following command from the same directory: +```bash +node build\TypeScriptTranspiler.js [input_files] +``` \ No newline at end of file diff --git a/migrator/typescript/package-lock.json b/migrator/typescript/package-lock.json new file mode 100644 index 000000000..a2650a35d --- /dev/null +++ b/migrator/typescript/package-lock.json @@ -0,0 +1,46 @@ +{ + "name": "ts-transpiler", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "ts-transpiler", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.7", + "typescript": "^4.8.4" + } + }, + "node_modules/@types/node": { + "version": "18.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.7.tgz", + "integrity": "sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==" + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "@types/node": { + "version": "18.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.7.tgz", + "integrity": "sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==" + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" + } + } +} diff --git a/migrator/typescript/package.json b/migrator/typescript/package.json new file mode 100644 index 000000000..31ccce9f3 --- /dev/null +++ b/migrator/typescript/package.json @@ -0,0 +1,10 @@ +{ + "name": "ts-transpiler", + "version": "1.0.0", + "private": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.7", + "typescript": "^4.8.4" + } +} \ No newline at end of file diff --git a/migrator/typescript/src/TypeScriptTransformer.ts b/migrator/typescript/src/TypeScriptTransformer.ts new file mode 100644 index 000000000..72a017a4a --- /dev/null +++ b/migrator/typescript/src/TypeScriptTransformer.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; + +type VisitFunction = (tsNode: T) => STSNode; +type VisitorTable = { [key: number]: VisitFunction }; + +// Dummy classes (for result output). Remove later +export class STSNode {} +export class STSCompilationUnit extends STSNode { } + +export class TypeScriptTransformer { + tsTypeChecker: ts.TypeChecker; + + constructor(private tsSourceFile: ts.SourceFile, private tsProgram: ts.Program) { + this.tsTypeChecker = tsProgram.getTypeChecker(); + } + + public transform(): STSCompilationUnit { + return this.visitSourceFile(this.tsSourceFile); + } + + readonly visitorTable : VisitorTable = { + [ts.SyntaxKind.SourceFile]: this.visitSourceFile, + [ts.SyntaxKind.ClassDeclaration]: this.visitClassDeclaration, + [ts.SyntaxKind.FunctionDeclaration]: this.visitFunctionDeclaration + } + + /** + * Calls corresponding visit function for specified node. + * @param tsNode The node to be visited + */ + visitNode(tsNode: ts.Node) { + let visitFn = this.visitorTable[tsNode.kind]; + + if (visitFn) { + visitFn(tsNode); + } else { + // Print untranslated node? + } + } + + visitSourceFile(tsSourceFile: ts.SourceFile): STSCompilationUnit { + for(const tsNode of tsSourceFile.statements) { + this.visitNode(tsNode); + } + + return new STSCompilationUnit(); + } + + visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): STSNode { + console.log(`Class: ${tsClassDecl.name.text}`) + return null; + } + + visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): STSNode { + console.log(`Function: ${tsFunDecl.name.text}`) + return null; + } +} \ No newline at end of file diff --git a/migrator/typescript/src/TypeScriptTranspiler.ts b/migrator/typescript/src/TypeScriptTranspiler.ts new file mode 100644 index 000000000..8098cb0ec --- /dev/null +++ b/migrator/typescript/src/TypeScriptTranspiler.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; +import { STSCompilationUnit, TypeScriptTransformer } from "./TypeScriptTransformer" + +function compile(fileNames: string[], options: ts.CompilerOptions): ts.Program { + let program = ts.createProgram(fileNames, options); + + // Log errors + let diagnostics = ts.getPreEmitDiagnostics(program); + diagnostics.forEach(diagnostic => { + if (diagnostic.file) { + let { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); + let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } else { + console.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); + } + }); + + return program; +} + +function transpile() { + const inputFiles = process.argv.slice(2); + + const tsProgram = compile(inputFiles, { + noEmitOnError: true, + noImplicitAny: true, + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.CommonJS + }); + + // Retrieve AST for input files. + let tsSrcFiles = inputFiles.map((val, idx, array) => tsProgram.getSourceFile(val)); + + for(let tsSrcFile of tsSrcFiles) { + let transformer = new TypeScriptTransformer(tsSrcFile, tsProgram); + let stsCompUnit = transformer.transform(); + } +} + +transpile(); \ No newline at end of file diff --git a/migrator/typescript/tsconfig.json b/migrator/typescript/tsconfig.json new file mode 100644 index 000000000..fdfad7303 --- /dev/null +++ b/migrator/typescript/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "CommonJS", + "target": "ES6", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "outDir": "build", + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} \ No newline at end of file -- Gitee From 0ab69e86b2dc1e71edb0468b33cdb79c8063fd67 Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Tue, 8 Nov 2022 00:41:07 +0300 Subject: [PATCH 05/15] Generate STS parser/lexer from ANTLR grammar for Typescript module. Build Typescript module with Ant (using build.xml) Change-Id: I20bbc5b426029df2feec90db5004ab517825e747 Signed-off-by: Evgeniy Okolnov --- migrator/README.md | 2 + migrator/build.xml | 30 ++++++++- .../staticTS/parser/StaticTSParser.g4 | 15 ++--- .../staticTS/parser/StaticTSParserBase.java | 5 ++ migrator/typescript/.gitignore | 3 + migrator/typescript/README.md | 22 +++++-- migrator/typescript/package-lock.json | 33 +++++++++- migrator/typescript/package.json | 15 ++++- .../scripts/fix-generated-parser.mjs | 52 +++++++++++++++ .../typescript/src/staticts/DummyContext.ts | 23 +++++++ .../src/staticts/StaticTSContextBase.ts | 61 +++++++++++++++++ .../src/staticts/StaticTSLexerBase.ts | 64 ++++++++++++++++++ .../src/staticts/StaticTSParserBase.ts | 66 +++++++++++++++++++ .../typescript/src/staticts/tsconfig.json | 10 +++ .../{ => transpiler}/TypeScriptTransformer.ts | 18 +++-- .../{ => transpiler}/TypeScriptTranspiler.ts | 6 +- .../typescript/src/transpiler/tsconfig.json | 14 ++++ migrator/typescript/tsconfig-base.json | 11 ++++ migrator/typescript/tsconfig-generated.json | 16 +++++ migrator/typescript/tsconfig.json | 8 +-- 20 files changed, 433 insertions(+), 41 deletions(-) create mode 100644 migrator/typescript/.gitignore create mode 100644 migrator/typescript/scripts/fix-generated-parser.mjs create mode 100644 migrator/typescript/src/staticts/DummyContext.ts create mode 100644 migrator/typescript/src/staticts/StaticTSContextBase.ts create mode 100644 migrator/typescript/src/staticts/StaticTSLexerBase.ts create mode 100644 migrator/typescript/src/staticts/StaticTSParserBase.ts create mode 100644 migrator/typescript/src/staticts/tsconfig.json rename migrator/typescript/src/{ => transpiler}/TypeScriptTransformer.ts (79%) rename migrator/typescript/src/{ => transpiler}/TypeScriptTranspiler.ts (90%) create mode 100644 migrator/typescript/src/transpiler/tsconfig.json create mode 100644 migrator/typescript/tsconfig-base.json create mode 100644 migrator/typescript/tsconfig-generated.json diff --git a/migrator/README.md b/migrator/README.md index 3034dcd0a..ec1ab15d3 100644 --- a/migrator/README.md +++ b/migrator/README.md @@ -10,6 +10,8 @@ This project is using the **Apache Ant** tool for building. You can download bin You also need to use **Java 8** (or newer) to build the project. +The TypeScript translator is written on TypeScript and requires NodeJS to build the project and run the translator. For details, see the [typescript](typescript) page. + ### Steps to build The build supports two main targets: **clean** and **build**: diff --git a/migrator/build.xml b/migrator/build.xml index d51980800..3d3dc7dcc 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -33,6 +33,9 @@ + + + @@ -62,7 +65,11 @@ - + + + + + @@ -75,7 +82,7 @@ - + @@ -105,7 +112,24 @@ - + + + + + + + + + + + + + + + + + + diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index b9cfeb563..1e94361fe 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -50,13 +50,6 @@ options { contextSuperClass=StaticTSContextBase; } -@members { - // These are context-dependent keywords, i.e. those that - // can't be used as identifiers only in specific contexts - public static final String IN = "in"; // keyword in type argument and type parameter contexts - public static final String OUT = "out"; // keyword in type argument and type parameter contexts -} - compilationUnit : packageDeclaration? importDeclaration* topDeclaration* EOF ; @@ -274,7 +267,7 @@ predefinedType ; arrayType - : (predefinedType | typeReference) {notLineTerminator()}? (OpenBracket CloseBracket)+ + : (predefinedType | typeReference) {this.notLineTerminator()}? (OpenBracket CloseBracket)+ ; typeReference @@ -295,7 +288,7 @@ typeParameterList ; typeParameter - : ({ this.next(IN) || this.next(OUT) }? Identifier)? Identifier constraint? + : ({ this.next(StaticTSParser.IN) || this.next(StaticTSParser.OUT) }? Identifier)? Identifier constraint? ; constraint @@ -317,8 +310,8 @@ typeArgument ; wildcardType - : { this.next(IN) }? Identifier typeReference - | { this.next(OUT) }? Identifier typeReference? + : { this.next(StaticTSParser.IN) }? Identifier typeReference + | { this.next(StaticTSParser.OUT) }? Identifier typeReference? ; // Statements diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParserBase.java b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParserBase.java index 2426e9c10..748dff08c 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParserBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParserBase.java @@ -23,6 +23,11 @@ import org.antlr.v4.runtime.*; */ public abstract class StaticTSParserBase extends Parser { + // These are context-dependent keywords, i.e. those that + // can't be used as identifiers only in specific contexts + public static final String IN = "in"; // keyword in type argument and type parameter contexts + public static final String OUT = "out"; // keyword in type argument and type parameter contexts + public StaticTSParserBase(TokenStream input) { super(input); } diff --git a/migrator/typescript/.gitignore b/migrator/typescript/.gitignore new file mode 100644 index 000000000..63c28855a --- /dev/null +++ b/migrator/typescript/.gitignore @@ -0,0 +1,3 @@ +generated +node_modules +*.tsbuildinfo \ No newline at end of file diff --git a/migrator/typescript/README.md b/migrator/typescript/README.md index ac5912bd2..ea2f4d78a 100644 --- a/migrator/typescript/README.md +++ b/migrator/typescript/README.md @@ -4,26 +4,34 @@ Translator from TypeScript to StaticTS, written on TypeScript and using TSC API. ## Prerequisits ### Visual Studio Code -For development, it's recommended to use VS Code, as it has a full built-in support for TypeScript language. +For development, it's recommended to use `VS Code`, as it has a full built-in support for TypeScript language. ### NodeJS and NPM -In order to build and run TypeScript translator, you need to install NodeJS and NPM. It is recommended using a **Node version manager** to install Node and NPM ([nvm](https://github.com/nvm-sh/nvm) for Linux, [nvm-windows](https://github.com/coreybutler/nvm-windows) for windows). You can also follow the [official guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). +In order to build and run TypeScript translator, you need to install `NodeJS` and `NPM`. It is recommended using a `Node version manager` to install Node and NPM ([nvm](https://github.com/nvm-sh/nvm) for Linux; [nvm-windows](https://github.com/coreybutler/nvm-windows) for windows - v1.1.9 is the most stable). You can also follow the [official guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). ### TypeScript Compiler -The translator itself is written on TypeScript, therefore you need to install TypeScript Compiler in order to build the project: +The translator itself is written on TypeScript, therefore you need to use a TSC in order to build the project. The build script uses the TypeScript compiler downloaded as a local project dependency, but you can also install TypeScript Compiler globally and use it to compile the sources separately (see the [Intermediate build steps](#intermediate-build-steps) below): ```bash npm install -g typescript ``` See https://www.npmjs.com/package/typescript for more details. ## Building +All commands below are run from `migrator/typescript`. -1. `cd` to `migrator/typescript` -2. Run `npm install` to install all project dependencies (need only once per change in dependencies). -3. Run `tsc` to compile project sources. The result JavaScript code is located in `build` directory +### Full build +- `npm install` - installs/updates project dependencies and compiles the project sources. +- `npm run build` - builds the project, but skips checking the project dependencies (at the `node_modules` folder). + +### Intermediate build steps +If you want to build only certain part of the typescript module, use the following commands: +- `npm run antlr4ts` - generates StaticTS parser/lexer using ANTLR grammar. +- `npm run tsc` (or just `tsc` if using **global** tsc) - compiles project sources. + +Compiled JavaScript code is located at `build/javascript` directory. ## Running Run the following command from the same directory: ```bash -node build\TypeScriptTranspiler.js [input_files] +node build\javascript\src\transpiler\TypeScriptTranspiler.js [input_files] ``` \ No newline at end of file diff --git a/migrator/typescript/package-lock.json b/migrator/typescript/package-lock.json index a2650a35d..4e5b2394a 100644 --- a/migrator/typescript/package-lock.json +++ b/migrator/typescript/package-lock.json @@ -9,8 +9,12 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@types/node": "^18.11.7", - "typescript": "^4.8.4" + "@types/node": "18.11.7", + "antlr4ts": "0.5.0-alpha.4", + "typescript": "4.8.4" + }, + "devDependencies": { + "antlr4ts-cli": "0.5.0-alpha.4" } }, "node_modules/@types/node": { @@ -18,6 +22,20 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.7.tgz", "integrity": "sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==" }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==" + }, + "node_modules/antlr4ts-cli": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts-cli/-/antlr4ts-cli-0.5.0-alpha.4.tgz", + "integrity": "sha512-lVPVBTA2CVHRYILSKilL6Jd4hAumhSZZWA7UbQNQrmaSSj7dPmmYaN4bOmZG79cOy0lS00i4LY68JZZjZMWVrw==", + "dev": true, + "bin": { + "antlr4ts": "antlr4ts" + } + }, "node_modules/typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -37,6 +55,17 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.7.tgz", "integrity": "sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==" }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==" + }, + "antlr4ts-cli": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts-cli/-/antlr4ts-cli-0.5.0-alpha.4.tgz", + "integrity": "sha512-lVPVBTA2CVHRYILSKilL6Jd4hAumhSZZWA7UbQNQrmaSSj7dPmmYaN4bOmZG79cOy0lS00i4LY68JZZjZMWVrw==", + "dev": true + }, "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", diff --git a/migrator/typescript/package.json b/migrator/typescript/package.json index 31ccce9f3..ee7a7bcbe 100644 --- a/migrator/typescript/package.json +++ b/migrator/typescript/package.json @@ -3,8 +3,19 @@ "version": "1.0.0", "private": true, "license": "Apache-2.0", + "scripts": { + "antlr4ts": "antlr4ts -no-listener -no-visitor -o build/typescript -Xexact-output-dir ..\\src\\com\\ohos\\migrator\\staticTS\\parser\\StaticTSLexer.g4 ..\\src\\com\\ohos\\migrator\\staticTS\\parser\\StaticTSParser.g4", + "postantlr4ts": "node scripts/fix-generated-parser.mjs build/typescript", + "tsc": "tsc", + "build": "npm run antlr4ts && npm run tsc", + "prepare": "npm run build" + }, "dependencies": { - "@types/node": "^18.11.7", - "typescript": "^4.8.4" + "@types/node": "18.11.7", + "antlr4ts": "0.5.0-alpha.4", + "typescript": "4.8.4" + }, + "devDependencies": { + "antlr4ts-cli": "0.5.0-alpha.4" } } \ No newline at end of file diff --git a/migrator/typescript/scripts/fix-generated-parser.mjs b/migrator/typescript/scripts/fix-generated-parser.mjs new file mode 100644 index 000000000..6e7cd47af --- /dev/null +++ b/migrator/typescript/scripts/fix-generated-parser.mjs @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This script is intended to fix lexer and parser files generated + * by 'antlr4ts' by adding missing imports for base classes. +*/ + +import { openSync, readFileSync, writeSync, closeSync } from "fs"; +import { EOL } from "os"; + +function appendText(file, textToAppend) { + var error; + try { + var data = readFileSync(file); // Read existing contents into data + var fd = openSync(file, 'w+'); + var buffer = Buffer.from(textToAppend + EOL); + + writeSync(fd, buffer, 0, buffer.length, 0); // Write new data + writeSync(fd, data, 0, data.length, buffer.length); // Append old data + } catch (e) { + error = e; + } finally { + closeSync(fd); + + if (error) { + console.error(error); + process.exit(1); + } + } +} + +var base_dir = process.argv[2]; + +var lexer_imports = 'import { StaticTSLexerBase } from "../../src/staticts/StaticTSLexerBase"' +appendText(`${base_dir}/StaticTSLexer.ts`, lexer_imports); + +var parser_imports = `import { StaticTSParserBase } from "../../src/staticts/StaticTSParserBase" +import { StaticTSContextBase } from "../../src/staticts/StaticTSContextBase"` +appendText(`${base_dir}/StaticTSParser.ts`, parser_imports); diff --git a/migrator/typescript/src/staticts/DummyContext.ts b/migrator/typescript/src/staticts/DummyContext.ts new file mode 100644 index 000000000..1a6dcb531 --- /dev/null +++ b/migrator/typescript/src/staticts/DummyContext.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ParserRuleContext } from 'antlr4ts' +import { StaticTSContextBase } from './StaticTSContextBase'; + +export class DummyContext extends StaticTSContextBase { + constructor(parent: ParserRuleContext, invokingStateNumber: number) { + super(parent, invokingStateNumber); + } +} diff --git a/migrator/typescript/src/staticts/StaticTSContextBase.ts b/migrator/typescript/src/staticts/StaticTSContextBase.ts new file mode 100644 index 000000000..cceb5c0e1 --- /dev/null +++ b/migrator/typescript/src/staticts/StaticTSContextBase.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ParserRuleContext, Token } from 'antlr4ts' +import { ParseTree, TerminalNode } from 'antlr4ts/tree' +import { StaticTSParser } from '../../build/typescript/StaticTSParser' + +export class StaticTSContextBase extends ParserRuleContext { + private leadingComments: TerminalNode[]; + private trailingComments: TerminalNode[]; + + constructor(parent: ParserRuleContext | undefined, invokingStateNumber: number) { + super(parent, invokingStateNumber); + } + + addLeadingComment(stsComment: TerminalNode): void { + if (!this.leadingComments) this.leadingComments = []; + this.leadingComments.push(stsComment); + } + + addTrailingComment(stsComment: TerminalNode): void { + if (!this.trailingComments) this.trailingComments = []; + this.trailingComments.push(stsComment); + } + + setLeadingComments(stsComments: TerminalNode[]): void { + this.leadingComments = stsComments; + } + + setTrailingComments(stsComments: TerminalNode[]): void { + this.trailingComments = stsComments; + } + + getLeadingComments(): TerminalNode[] { + return this.leadingComments; + } + + getTrailingComments(): TerminalNode[] { + return this.trailingComments; + } + + hasLeadingComments(): boolean { + return this.leadingComments && this.leadingComments.length != 0; + } + + hasTrailingComments(): boolean { + return this.trailingComments && this.trailingComments.length != 0; + } +} diff --git a/migrator/typescript/src/staticts/StaticTSLexerBase.ts b/migrator/typescript/src/staticts/StaticTSLexerBase.ts new file mode 100644 index 000000000..7351627e5 --- /dev/null +++ b/migrator/typescript/src/staticts/StaticTSLexerBase.ts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Lexer, Token, Vocabulary } from "antlr4ts" + +/** + * All lexer methods that used in grammar (IsStrictMode) + * should start with Upper Case Char similar to Lexer rules. + */ +export class StaticTSLexerBase extends Lexer { + + constructor(input: any) { + super(input); + } + + get ruleNames(): string[] { + return null; + } + get grammarFileName(): string { + return ""; + } + get vocabulary(): Vocabulary { + return null; + } + get channelNames(): string[] { + return null + } + get modeNames(): string[] { + return null; + } + + getStrictDefault(): boolean { + return false; + } + setUseStrictDefault(value: boolean): void { + } + public IsStrictMode(): boolean { + return false; + } + public IsInTemplateString(): boolean { + return false; + } + public nextToken(): Token { + return null; + } + protected ProcessOpenBrace(): void { + } + protected ProcessCloseBrace(): void { + } + protected ProcessStringLiteral(): void { + } +} diff --git a/migrator/typescript/src/staticts/StaticTSParserBase.ts b/migrator/typescript/src/staticts/StaticTSParserBase.ts new file mode 100644 index 000000000..0482e5144 --- /dev/null +++ b/migrator/typescript/src/staticts/StaticTSParserBase.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Parser, TokenStream, Vocabulary } from "antlr4ts" + +/** + * All parser methods that used in grammar (p, prev, notLineTerminator, etc.) + * should start with lower case char similar to parser rules. + */ +export class StaticTSParserBase extends Parser { + + // These are context-dependent keywords, i.e. those that + // can't be used as identifiers only in specific contexts + public static IN = "in"; // keyword in type argument and type parameter contexts + public static OUT = "out"; // keyword in type argument and type parameter contexts + + constructor(input: TokenStream) { + super(input); + } + + get ruleNames(): string[] { + return null; + } + get grammarFileName(): string { + return ""; + } + get vocabulary(): Vocabulary { + return null; + } + protected p(str: string): boolean { + return false; + } + protected prev(str: string): boolean { + return false; + } + protected n(str: string): boolean { + return false; + } + protected next(str: string): boolean { + return false; + } + protected notLineTerminator(): boolean { + return false; + } + protected notOpenBraceAndNotFunction(): boolean { + return false; + } + protected closeBrace(): boolean { + return false; + } + protected lineTerminatorAhead(): boolean { + return false; + } +} diff --git a/migrator/typescript/src/staticts/tsconfig.json b/migrator/typescript/src/staticts/tsconfig.json new file mode 100644 index 000000000..fd8390abf --- /dev/null +++ b/migrator/typescript/src/staticts/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig-base.json", + + "compilerOptions": { + "composite": true, + "outDir": "../../build" + }, + + "include": ["*"], +} \ No newline at end of file diff --git a/migrator/typescript/src/TypeScriptTransformer.ts b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts similarity index 79% rename from migrator/typescript/src/TypeScriptTransformer.ts rename to migrator/typescript/src/transpiler/TypeScriptTransformer.ts index 72a017a4a..31207e790 100644 --- a/migrator/typescript/src/TypeScriptTransformer.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts @@ -14,14 +14,12 @@ */ import * as ts from "typescript"; +import { StaticTSContextBase } from "../staticts/StaticTSContextBase"; +import * as sts from "../../build/typescript/StaticTSParser"; -type VisitFunction = (tsNode: T) => STSNode; +type VisitFunction = (tsNode: T) => StaticTSContextBase; type VisitorTable = { [key: number]: VisitFunction }; -// Dummy classes (for result output). Remove later -export class STSNode {} -export class STSCompilationUnit extends STSNode { } - export class TypeScriptTransformer { tsTypeChecker: ts.TypeChecker; @@ -29,7 +27,7 @@ export class TypeScriptTransformer { this.tsTypeChecker = tsProgram.getTypeChecker(); } - public transform(): STSCompilationUnit { + public transform(): sts.CompilationUnitContext { return this.visitSourceFile(this.tsSourceFile); } @@ -53,20 +51,20 @@ export class TypeScriptTransformer { } } - visitSourceFile(tsSourceFile: ts.SourceFile): STSCompilationUnit { + visitSourceFile(tsSourceFile: ts.SourceFile): sts.CompilationUnitContext { for(const tsNode of tsSourceFile.statements) { this.visitNode(tsNode); } - return new STSCompilationUnit(); + return new sts.CompilationUnitContext(null, 0); } - visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): STSNode { + visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): StaticTSContextBase { console.log(`Class: ${tsClassDecl.name.text}`) return null; } - visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): STSNode { + visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): StaticTSContextBase { console.log(`Function: ${tsFunDecl.name.text}`) return null; } diff --git a/migrator/typescript/src/TypeScriptTranspiler.ts b/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts similarity index 90% rename from migrator/typescript/src/TypeScriptTranspiler.ts rename to migrator/typescript/src/transpiler/TypeScriptTranspiler.ts index 8098cb0ec..0d4a9b6ad 100644 --- a/migrator/typescript/src/TypeScriptTranspiler.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts @@ -14,7 +14,8 @@ */ import * as ts from "typescript"; -import { STSCompilationUnit, TypeScriptTransformer } from "./TypeScriptTransformer" +import { TypeScriptTransformer } from "./TypeScriptTransformer"; +import { CompilationUnitContext } from "./StaticTSParser"; function compile(fileNames: string[], options: ts.CompilerOptions): ts.Program { let program = ts.createProgram(fileNames, options); @@ -41,7 +42,8 @@ function transpile() { noEmitOnError: true, noImplicitAny: true, target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.CommonJS + module: ts.ModuleKind.CommonJS, + //skipLibCheck: true }); // Retrieve AST for input files. diff --git a/migrator/typescript/src/transpiler/tsconfig.json b/migrator/typescript/src/transpiler/tsconfig.json new file mode 100644 index 000000000..2bbfae998 --- /dev/null +++ b/migrator/typescript/src/transpiler/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig-base.json", + + "compilerOptions": { + "outDir": "../../build" + }, + + "references": [ + { "path": "../staticts" }, + { "path": "../../tsconfig-generated.json" } + ], + + "include": ["*"], +} \ No newline at end of file diff --git a/migrator/typescript/tsconfig-base.json b/migrator/typescript/tsconfig-base.json new file mode 100644 index 000000000..b665f5e8f --- /dev/null +++ b/migrator/typescript/tsconfig-base.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "CommonJS", + "target": "ES6", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "rootDirs": ["src/transpiler", "src/staticts", "generated"] + } +} \ No newline at end of file diff --git a/migrator/typescript/tsconfig-generated.json b/migrator/typescript/tsconfig-generated.json new file mode 100644 index 000000000..47e2f06d5 --- /dev/null +++ b/migrator/typescript/tsconfig-generated.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig-base.json", + + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "build/tsconfig-generated.tsbuildinfo", + "outDir": "build", + "rootDir": "generated" + }, + + "references": [ + { "path": "src/staticts" } + ], + + "include": ["generated/**/*"], +} \ No newline at end of file diff --git a/migrator/typescript/tsconfig.json b/migrator/typescript/tsconfig.json index fdfad7303..51e8a321f 100644 --- a/migrator/typescript/tsconfig.json +++ b/migrator/typescript/tsconfig.json @@ -5,9 +5,9 @@ "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, - "outDir": "build", - "sourceMap": true + "sourceMap": true, + "outDir": "build/javascript" }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + + "include": ["build/typescript/**/*", "src/**/*"], } \ No newline at end of file -- Gitee From 8af95d7ad3c9479cc75bf48712acedb753554c17 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Tue, 8 Nov 2022 15:19:35 +0300 Subject: [PATCH 06/15] Dump STS AST produced by TS translator to XML file. Signed-off-by: Mikhail Velikanov --- .../src/staticts/StaticTSContextBase.ts | 49 +++++++++++++++++++ .../typescript/src/staticts/tsconfig.json | 10 ---- .../src/transpiler/TypeScriptTransformer.ts | 42 +++++++++++++--- .../src/transpiler/TypeScriptTranspiler.ts | 8 ++- .../typescript/src/transpiler/tsconfig.json | 14 ------ migrator/typescript/test/empty_class.ts | 2 + migrator/typescript/tsconfig-base.json | 11 ----- migrator/typescript/tsconfig-generated.json | 16 ------ 8 files changed, 91 insertions(+), 61 deletions(-) delete mode 100644 migrator/typescript/src/staticts/tsconfig.json delete mode 100644 migrator/typescript/src/transpiler/tsconfig.json create mode 100644 migrator/typescript/test/empty_class.ts delete mode 100644 migrator/typescript/tsconfig-base.json delete mode 100644 migrator/typescript/tsconfig-generated.json diff --git a/migrator/typescript/src/staticts/StaticTSContextBase.ts b/migrator/typescript/src/staticts/StaticTSContextBase.ts index cceb5c0e1..5a7a754eb 100644 --- a/migrator/typescript/src/staticts/StaticTSContextBase.ts +++ b/migrator/typescript/src/staticts/StaticTSContextBase.ts @@ -58,4 +58,53 @@ export class StaticTSContextBase extends ParserRuleContext { hasTrailingComments(): boolean { return this.trailingComments && this.trailingComments.length != 0; } + + private static indent : number; + + toXML() : string { + // Reset indent before recursing into AST + StaticTSContextBase.indent = 0; + let header : string = "\n"; + return header + this.toXMLImpl(); + } + + private toXMLImpl() : string { + let nodeName : string = this.constructor.name; + let xmlIndent : string = " ".repeat(4*StaticTSContextBase.indent); + + // If current node has no children, return one-line XML tag; + // otherwise create opening XML and proceed to child nodes. + let result : string = xmlIndent + "<" + nodeName; + if (this.childCount === 0) { + return result + "/>\n"; + } + + result += ">\n"; + + // Increase indent and process children. + ++StaticTSContextBase.indent; + for (let i = 0; i < this.childCount; ++i) { + let childNode : ParseTree = this.getChild(i); + + if (childNode instanceof StaticTSContextBase) { + result += (childNode as StaticTSContextBase).toXMLImpl(); + } + else if (childNode instanceof TerminalNode) { + // Can't recurse into TerminalNode as it doesn't extend + // the current class, so process terminals in place. + let token : Token = (childNode as TerminalNode).symbol; + let kind : string = StaticTSParser.VOCABULARY.getSymbolicName(token.type); + result += xmlIndent + " ".repeat(4) + "\n"; + + return result; + } } diff --git a/migrator/typescript/src/staticts/tsconfig.json b/migrator/typescript/src/staticts/tsconfig.json deleted file mode 100644 index fd8390abf..000000000 --- a/migrator/typescript/src/staticts/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig-base.json", - - "compilerOptions": { - "composite": true, - "outDir": "../../build" - }, - - "include": ["*"], -} \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts index 31207e790..7cf5dc933 100644 --- a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import { CommonToken } from "antlr4ts"; +import { TerminalNode } from "antlr4ts/tree"; import * as ts from "typescript"; import { StaticTSContextBase } from "../staticts/StaticTSContextBase"; import * as sts from "../../build/typescript/StaticTSParser"; @@ -41,31 +43,55 @@ export class TypeScriptTransformer { * Calls corresponding visit function for specified node. * @param tsNode The node to be visited */ - visitNode(tsNode: ts.Node) { + visitNode(tsNode: ts.Node): StaticTSContextBase { let visitFn = this.visitorTable[tsNode.kind]; if (visitFn) { - visitFn(tsNode); + return visitFn(tsNode); } else { + return null; // Print untranslated node? } } visitSourceFile(tsSourceFile: ts.SourceFile): sts.CompilationUnitContext { + let stsCU = new sts.CompilationUnitContext(null, 0); for(const tsNode of tsSourceFile.statements) { - this.visitNode(tsNode); + let stsChildNode = this.visitNode(tsNode); + if (stsChildNode !== null) { + let stsTopDecl = new sts.TopDeclarationContext(stsCU, 0); + stsTopDecl.addChild(stsChildNode); + stsCU.addChild(stsTopDecl); + } } - return new sts.CompilationUnitContext(null, 0); + return stsCU; } - visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): StaticTSContextBase { - console.log(`Class: ${tsClassDecl.name.text}`) - return null; + visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): sts.ClassDeclarationContext { + let stsClassDecl = new sts.ClassDeclarationContext(null, 0); + let tsClassName : string = tsClassDecl.name.getText(); + stsClassDecl.addChild(createToken(sts.StaticTSParser.Class)); + stsClassDecl.addChild(createIdentifier(tsClassName)); + stsClassDecl.addChild(new sts.ClassBodyContext(stsClassDecl, 0)); + return stsClassDecl; } - visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): StaticTSContextBase { + visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): sts.FunctionDeclarationContext { console.log(`Function: ${tsFunDecl.name.text}`) return null; } +} + +function createIdentifier(name : string) : TerminalNode { + return createToken(sts.StaticTSParser.Identifier, name); +} + +function createToken(tokenKind : number, tokenName? : string) : TerminalNode { + if (tokenName == undefined) tokenName = stsTokenName(tokenKind); + return new TerminalNode(new CommonToken(tokenKind, tokenName)); +} + +function stsTokenName(tokenKind : number) : string { + return sts.StaticTSParser.VOCABULARY.getLiteralName(tokenKind); } \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts b/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts index 0d4a9b6ad..7b9c05cbd 100644 --- a/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTranspiler.ts @@ -14,8 +14,8 @@ */ import * as ts from "typescript"; +import { writeFileSync } from "fs"; import { TypeScriptTransformer } from "./TypeScriptTransformer"; -import { CompilationUnitContext } from "./StaticTSParser"; function compile(fileNames: string[], options: ts.CompilerOptions): ts.Program { let program = ts.createProgram(fileNames, options); @@ -51,7 +51,11 @@ function transpile() { for(let tsSrcFile of tsSrcFiles) { let transformer = new TypeScriptTransformer(tsSrcFile, tsProgram); - let stsCompUnit = transformer.transform(); + let stsCompUnit = transformer.transform(); + + let xmlString = stsCompUnit.toXML(); + let xmlFile = tsSrcFile.fileName + ".xml"; + writeFileSync(xmlFile, xmlString); } } diff --git a/migrator/typescript/src/transpiler/tsconfig.json b/migrator/typescript/src/transpiler/tsconfig.json deleted file mode 100644 index 2bbfae998..000000000 --- a/migrator/typescript/src/transpiler/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig-base.json", - - "compilerOptions": { - "outDir": "../../build" - }, - - "references": [ - { "path": "../staticts" }, - { "path": "../../tsconfig-generated.json" } - ], - - "include": ["*"], -} \ No newline at end of file diff --git a/migrator/typescript/test/empty_class.ts b/migrator/typescript/test/empty_class.ts new file mode 100644 index 000000000..2e2439c32 --- /dev/null +++ b/migrator/typescript/test/empty_class.ts @@ -0,0 +1,2 @@ +class A { +} diff --git a/migrator/typescript/tsconfig-base.json b/migrator/typescript/tsconfig-base.json deleted file mode 100644 index b665f5e8f..000000000 --- a/migrator/typescript/tsconfig-base.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "module": "CommonJS", - "target": "ES6", - "noImplicitAny": true, - "removeComments": true, - "preserveConstEnums": true, - "sourceMap": true, - "rootDirs": ["src/transpiler", "src/staticts", "generated"] - } -} \ No newline at end of file diff --git a/migrator/typescript/tsconfig-generated.json b/migrator/typescript/tsconfig-generated.json deleted file mode 100644 index 47e2f06d5..000000000 --- a/migrator/typescript/tsconfig-generated.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "./tsconfig-base.json", - - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": "build/tsconfig-generated.tsbuildinfo", - "outDir": "build", - "rootDir": "generated" - }, - - "references": [ - { "path": "src/staticts" } - ], - - "include": ["generated/**/*"], -} \ No newline at end of file -- Gitee From 4566fc6e4623aad890547f2d41f6d9d31888c5a9 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Wed, 9 Nov 2022 15:03:20 +0300 Subject: [PATCH 07/15] Hook TypeScript transpiler to migrator infrastructure. Also update migrator version. Signed-off-by: Mikhail Velikanov --- migrator/build.xml | 2 +- migrator/src/com/ohos/migrator/Main.java | 28 ++++++++-- .../migrator/kotlin/KotlinTranspiler.java | 3 +- .../com/ohos/migrator/ts/TSTranspiler.java | 51 +++++++++++++++++++ .../src/com/ohos/migrator/util/FileUtils.java | 9 ++++ 5 files changed, 87 insertions(+), 6 deletions(-) create mode 100755 migrator/src/com/ohos/migrator/ts/TSTranspiler.java diff --git a/migrator/build.xml b/migrator/build.xml index 3d3dc7dcc..583570a72 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -17,7 +17,7 @@ Migration Tool - + diff --git a/migrator/src/com/ohos/migrator/Main.java b/migrator/src/com/ohos/migrator/Main.java index d5aaeafeb..83011081e 100644 --- a/migrator/src/com/ohos/migrator/Main.java +++ b/migrator/src/com/ohos/migrator/Main.java @@ -18,6 +18,7 @@ package com.ohos.migrator; import com.ohos.migrator.java.JavaTranspiler; import com.ohos.migrator.kotlin.KotlinTranspiler; import com.ohos.migrator.staticTS.StaticTSSyntaxChecker; +import com.ohos.migrator.ts.TSTranspiler; import org.apache.commons.cli.*; import java.io.File; @@ -31,12 +32,13 @@ import java.util.List; public class Main { static final String TOOL_NAME = "migrator"; - static final String VERSION_STRING = "version 0.1"; + static final String VERSION_STRING = "version 1.0"; static final String OPTION_VALUE_SEPARATOR = ","; static final String JAVA_EXT = ".java"; static final String KOTLIN_EXT = ".kt"; static final String LIB_EXT = ".jar"; static final String STS_EXT = ".sts"; + static final String TS_EXT = ".ts"; static List errorList = new ArrayList<>(); static boolean verboseMode = false; static boolean strictMode = false; @@ -135,6 +137,7 @@ public class Main { List javaSources = new ArrayList<>(); List kotlinSources = new ArrayList<>(); List stsSources = new ArrayList<>(); + List tsSources = new ArrayList<>(); // fill sources lists for (String s : sourceFileNames) { @@ -145,13 +148,18 @@ public class Main { } String fileName = f.getName().toLowerCase(); - if(fileName.endsWith(JAVA_EXT)) { + if (fileName.endsWith(JAVA_EXT)) { javaSources.add(f); - } else if(fileName.endsWith(KOTLIN_EXT)) { + } + else if (fileName.endsWith(KOTLIN_EXT)) { kotlinSources.add(f); - } else if(fileName.endsWith(STS_EXT)) { + } + else if (fileName.endsWith(STS_EXT)) { stsSources.add(f); } + else if (fileName.endsWith(TS_EXT)) { + tsSources.add(f); + } else { System.err.println("Source file " + f + " is not supported"); } @@ -218,6 +226,18 @@ public class Main { ++numLanguages; } + if (!tsSources.isEmpty()) { + System.out.println("Transpiling " + tsSources.size() + " TypeScript files."); + + TSTranspiler tsTranspiler = new TSTranspiler(tsSources, outDir); + resultCode = ResultCode.majorValue(tsTranspiler.transpile(), resultCode); + outFiles.addAll(tsTranspiler.getOutFiles()); + errorList.addAll(tsTranspiler.getErrorList()); + + if (convRateMode) convRate += tsTranspiler.getConversionRate(); + ++numLanguages; + } + if (resultCode == ResultCode.OK) System.out.println("Transpilation OK."); if (convRateMode) { diff --git a/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java b/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java index a9087d65d..b4f7aa87a 100644 --- a/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java +++ b/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java @@ -23,6 +23,7 @@ import com.ohos.migrator.staticTS.parser.StaticTSParser.CompilationUnitContext; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; +import com.ohos.migrator.util.FileUtils; import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys; import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport; @@ -136,7 +137,7 @@ public class KotlinTranspiler extends AbstractTranspiler { // directory as the application jar. File[] jarFiles = null; try { - File libDir = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile(); + File libDir = FileUtils.getMigratorJarPath().getParentFile(); jarFiles = libDir.listFiles(file -> isBuiltinKotlinJar(getManifestImplementationTitle(file))); } catch (URISyntaxException e1) {} diff --git a/migrator/src/com/ohos/migrator/ts/TSTranspiler.java b/migrator/src/com/ohos/migrator/ts/TSTranspiler.java new file mode 100755 index 000000000..93f2f76de --- /dev/null +++ b/migrator/src/com/ohos/migrator/ts/TSTranspiler.java @@ -0,0 +1,51 @@ +package com.ohos.migrator.ts; + +import com.ohos.migrator.AbstractTranspiler; +import com.ohos.migrator.ResultCode; +import com.ohos.migrator.TranspileException; +import com.ohos.migrator.Transpiler; +import com.ohos.migrator.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +public class TSTranspiler extends AbstractTranspiler { + + private static String XML_EXT = ".xml"; + private static String tsTranspilerJS = "typescript/build/javascript/src/transpiler/TypeScriptTranspiler.js"; + + public TSTranspiler(List src, String outDir) { + super(src, null, outDir); + } + + @Override + protected void transpileFile(File srcFile) throws TranspileException { + try { + String baseDir = FileUtils.getMigratorJarPath().getParent(); + String tsTranspilerPath = new File(baseDir, tsTranspilerJS).getPath(); + + Process p = new ProcessBuilder("node", tsTranspilerPath, srcFile.getPath()).start(); + int exitCode = p.waitFor(); + if (exitCode != 0) { + // TODO: Add stderr contents here! + throw new TranspileException(ResultCode.TranspileError, "TS Transpiler exited abnormally"); + } + + File xmlFile = new File(srcFile.getPath() + XML_EXT); + if (xmlFile.exists()) { + // Convert xmlFile to STS + } + } + catch (URISyntaxException use) { + throw new TranspileException(ResultCode.CmdLineError, use); + } + catch (IOException ioe) { + throw new TranspileException(ResultCode.InputError, ioe); + } + catch (InterruptedException ie) { + throw new TranspileException(ResultCode.TranspileError, ie); + } + } +} diff --git a/migrator/src/com/ohos/migrator/util/FileUtils.java b/migrator/src/com/ohos/migrator/util/FileUtils.java index 5a02aef51..e773a3ac2 100644 --- a/migrator/src/com/ohos/migrator/util/FileUtils.java +++ b/migrator/src/com/ohos/migrator/util/FileUtils.java @@ -15,7 +15,11 @@ package com.ohos.migrator.util; +import com.ohos.migrator.Main; + import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; @@ -86,4 +90,9 @@ public class FileUtils { System.err.println("Failed to copy file " + file.getPath()); } } + + public static File getMigratorJarPath() throws URISyntaxException { + URI mainClassURI = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI(); + return new File(mainClassURI).getParentFile(); + } } -- Gitee From cddf25b78717218f9064a6bf89c58bac98cff244 Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Wed, 9 Nov 2022 21:16:48 +0300 Subject: [PATCH 08/15] Run tests with Migrator's JAR file. Change-Id: I9136156783b1c6779a9b9c3546e813378b7fe2e1 Signed-off-by: Evgeniy Okolnov --- migrator/build.xml | 204 ++++-------------- .../migrator/kotlin/KotlinTranspiler.java | 3 +- .../src/com/ohos/migrator/util/FileUtils.java | 6 +- migrator/test/kotlin/global_functions.kt.sts | 6 +- migrator/test/kotlin/imports.kt.sts | 6 +- 5 files changed, 58 insertions(+), 167 deletions(-) diff --git a/migrator/build.xml b/migrator/build.xml index 583570a72..ea6066d49 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -13,7 +13,7 @@ * limitations under the License. --> - + Migration Tool @@ -34,7 +34,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -177,167 +177,55 @@ - - - - - - - - - - - - - - - -One or several tests have failed! -STDERR: -${test.err} - - - - - - - + + + + + + + + + + + + + + + + + + One or several tests have failed! + STDERR: + ${test.err} + + + + + + + + - - - - - - - - - - - - - - - - -One or several tests have failed! -STDERR: -${test.err} - - - - - - + + - - - - - - - - - - - - - - - - - One or several tests have failed! - STDERR: - ${test.err} - - - - - - + + - - - - - - - - - - - - - - - - - One or several tests have failed! - STDERR: - ${test.err} - - - - - - + + - - - - - - - - - - - - - - - - - - One or several tests have failed! - STDERR: - ${test.err} - - - - - - + + isBuiltinKotlinJar(getManifestImplementationTitle(file))); + jarFiles = FileUtils.getMigratorLibDir().listFiles(file -> isBuiltinKotlinJar(getManifestImplementationTitle(file))); } catch (URISyntaxException e1) {} diff --git a/migrator/src/com/ohos/migrator/util/FileUtils.java b/migrator/src/com/ohos/migrator/util/FileUtils.java index e773a3ac2..82d8b291c 100644 --- a/migrator/src/com/ohos/migrator/util/FileUtils.java +++ b/migrator/src/com/ohos/migrator/util/FileUtils.java @@ -93,6 +93,10 @@ public class FileUtils { public static File getMigratorJarPath() throws URISyntaxException { URI mainClassURI = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI(); - return new File(mainClassURI).getParentFile(); + return new File(mainClassURI); + } + + public static File getMigratorLibDir() throws URISyntaxException { + return getMigratorJarPath().getParentFile(); } } diff --git a/migrator/test/kotlin/global_functions.kt.sts b/migrator/test/kotlin/global_functions.kt.sts index a7efad805..830fcbee7 100644 --- a/migrator/test/kotlin/global_functions.kt.sts +++ b/migrator/test/kotlin/global_functions.kt.sts @@ -18,10 +18,10 @@ package com.ohos.migrator.test.kotlin; export function main(): kotlin.Unit { } export function doubleNum(x : Int): Int { - return __untranslated_expression(/* x * 2 */); + return __untranslated_expression( /* x * 2 */); } -function sum(... x: Int ): __UnknownType__ { - return __untranslated_expression(/* x.sum() */); +function sum(... x: Int ): kotlin.Int { + return __untranslated_expression( /* x.sum() */); } function doNothing(): kotlin.Unit { } diff --git a/migrator/test/kotlin/imports.kt.sts b/migrator/test/kotlin/imports.kt.sts index 5a75e8f44..77c78ca61 100644 --- a/migrator/test/kotlin/imports.kt.sts +++ b/migrator/test/kotlin/imports.kt.sts @@ -19,7 +19,7 @@ import kotlin.random.Random; import kotlin.math.*; import kotlin.reflect.KClass as Class; export function main(): kotlin.Unit { - __untranslated_statement(/* println(PI) */); - let rnd : Random = __untranslated_expression(/* Random(5) */); + __untranslated_statement( /* println(PI) */); + let rnd : Random = __untranslated_expression( /* Random(5) */); let kk : Class ; -} \ No newline at end of file +} -- Gitee From 8719fd4c8bdee8c9446634156cfa06b791b6799a Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 11 Nov 2022 12:58:00 +0300 Subject: [PATCH 09/15] Convert XML file written by TS translator to STS AST and feed it to StaticTSWriter. Also added missing copyright comments to a couple of source files. Signed-off-by: Mikhail Velikanov --- .../com/ohos/migrator/staticTS/XMLReader.java | 202 ++++++++++++++++++ .../staticTS/parser/DummyContext.java | 14 ++ .../staticTS/parser/StaticTSContextBase.java | 15 ++ .../com/ohos/migrator/ts/TSTranspiler.java | 46 +++- 4 files changed, 271 insertions(+), 6 deletions(-) create mode 100755 migrator/src/com/ohos/migrator/staticTS/XMLReader.java diff --git a/migrator/src/com/ohos/migrator/staticTS/XMLReader.java b/migrator/src/com/ohos/migrator/staticTS/XMLReader.java new file mode 100755 index 000000000..27b117ebb --- /dev/null +++ b/migrator/src/com/ohos/migrator/staticTS/XMLReader.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.staticTS; + +import com.ohos.migrator.Main; +import com.ohos.migrator.ResultCode; +import com.ohos.migrator.staticTS.parser.StaticTSContextBase; +import com.ohos.migrator.staticTS.parser.StaticTSParser; +import com.ohos.migrator.staticTS.parser.StaticTSParser.*; +import org.antlr.v4.runtime.tree.TerminalNode; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.Stack; +public class XMLReader { + private File xmlFile; + private Stack nodeStack = new Stack<>(); + private static final QName terminalKindAttr = new QName("kind"); + private static final QName terminalTextAttr = new QName("text"); + private static final String classNamePrefix = StaticTSParser.class.getName(); + + private static final String terminalNodeName = "TerminalNode"; + + private static final String terminalIdentKind = "Identifier"; + + public XMLReader(File xmlFile) { + this.xmlFile = xmlFile; + } + + public CompilationUnitContext read() throws XMLStreamException, IOException { + FileInputStream fis = new FileInputStream(xmlFile); + XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + XMLEventReader xmlReader = xmlInputFactory.createXMLEventReader(fis); + + CompilationUnitContext result = null; + try { + while (xmlReader.hasNext()) { + XMLEvent event = xmlReader.nextEvent(); + + try { + StaticTSContextBase lastNode = nodeStack.empty() ? null : nodeStack.peek(); + + if (event.isStartElement()) { + StartElement startElement = event.asStartElement(); + String tagName = startElement.getName().getLocalPart(); + + if (terminalNodeName.equals(tagName)) { + // Create the terminal and add it to the last node in the stack. + // Ignore if node stack is empty or terminal is invalid. + if (lastNode != null) { + TerminalNode terminal = createTerminal(startElement); + if (terminal != null) + lastNode.addChild(terminal); + else + reportError("Invalid XML tag emitted by TS transpiler", startElement); + } + + continue; + } + + // These two calls work as a filter. If current tag doesn't correspond to + // an AST node, they will throw, and the tag will be ignored as the result. + Class tagClass = Class.forName(classNamePrefix + "$" + tagName); + Class nodeClass = + tagClass.asSubclass(StaticTSContextBase.class); + + // Create node object and push it onto node stack. + // Also add it to AST if it exists (i.e., lastNode not null). + StaticTSContextBase node = createNode(nodeClass, lastNode); + + if (node != null) { + if (lastNode != null) + lastNode.addChild(node).setParent(lastNode); + + nodeStack.push(node); + } + else + reportError("Failed to create AST node for XML tag emitted by TS transpiler", startElement); + } + else if (event.isEndElement()) { + EndElement endElement = event.asEndElement(); + String tagName = endElement.getName().getLocalPart(); + + // Terminals are never added into nodeStack + // (see above) so just ignore them here. + if (terminalNodeName.equals(tagName)) continue; + + // Check that node stack is not empty and closing tag name matches + // type of the last node in stack before popping it off. The latter + // test takes care of the tags we skipped above due to exceptions. + if (lastNode != null && lastNode.getClass().getSimpleName().equals(tagName)) { + StaticTSContextBase node = nodeStack.pop(); + + // Bail out when we see closing tag for CompilationUnitContext. + if (node.getRuleIndex() == StaticTSParser.RULE_compilationUnit) { + result = (CompilationUnitContext) node; + break; + } + } + } + } catch (Exception e) { + // Report error and swallow exception to ignore the tag and continue iterating + reportError("Ignoring unexpected XML tag emitted by TS transpiler", event); + } + } + } + finally { + // Close resources, most importantly the FileInputStream + // object, to allow further manipulations with XML file, + // e.g., deleting it (see TSTranspiler.transpileFile method) + fis.close(); + xmlReader.close(); + } + + return result; + } + + private TerminalNode createTerminal(StartElement startElement) { + // Sanity check. + if (!terminalNodeName.equals(startElement.getName().getLocalPart())) + return null; + + Attribute kindAttr = startElement.getAttributeByName(terminalKindAttr); + if (kindAttr == null) return null; + + String attrName = kindAttr.getValue(); + if (attrName == null || attrName.isEmpty()) return null; + + if (terminalIdentKind.equals(attrName)) { + Attribute textAttr = startElement.getAttributeByName(terminalTextAttr); + if (textAttr == null) return null; + + String text = textAttr.getValue(); + if (text == null || text.isEmpty()) return null; + + return NodeBuilderBase.terminalIdentifier(text); + } + + for (int i = 1; i < StaticTSParser.VOCABULARY.getMaxTokenType(); ++i) { + if (attrName.equals(StaticTSParser.VOCABULARY.getSymbolicName(i))) + return NodeBuilderBase.terminalNode(i); + } + + return null; + } + + // NOTE: We don't care about specific exception types this function + // can throw as we catch and process them all the same way. + private StaticTSContextBase createNode(Class nodeClass, + StaticTSContextBase parent) throws Exception { + // Pick up node ctor with one or two parameters. + // AntLR guarantees that all rule-based node classes + // have at least ctor that satisfies this condition. + Constructor nodeCtor = null; + for (Constructor ctor : nodeClass.getConstructors()) { + int numParams = ctor.getParameterCount(); + if (numParams > 0 && numParams < 3) { + nodeCtor = ctor; + break; + } + } + + // This check should never be true! + if (nodeCtor == null) return null; + + // Construct arguments array and invoke selected ctor. + Object[] ctorArgs = nodeCtor.getParameterCount() > 1 ? + new Object[] { parent, 0 } : + new Object[] { parent }; + + return (StaticTSContextBase)nodeCtor.newInstance(ctorArgs); + } + + private void reportError(String message, XMLEvent xmlEvent) { + Main.addError(ResultCode.TranspileError, message + " at " + + xmlFile.getPath() + ":" + xmlEvent.getLocation().getLineNumber()); + } +} diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/DummyContext.java b/migrator/src/com/ohos/migrator/staticTS/parser/DummyContext.java index 01c35e47b..dc3104e0a 100755 --- a/migrator/src/com/ohos/migrator/staticTS/parser/DummyContext.java +++ b/migrator/src/com/ohos/migrator/staticTS/parser/DummyContext.java @@ -1,3 +1,17 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.ohos.migrator.staticTS.parser; import com.ohos.migrator.staticTS.writer.StaticTSWriter; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java index 87d1b652a..6401e23a0 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSContextBase.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.ohos.migrator.staticTS.parser; import org.antlr.v4.runtime.ParserRuleContext; diff --git a/migrator/src/com/ohos/migrator/ts/TSTranspiler.java b/migrator/src/com/ohos/migrator/ts/TSTranspiler.java index 93f2f76de..82c334a16 100755 --- a/migrator/src/com/ohos/migrator/ts/TSTranspiler.java +++ b/migrator/src/com/ohos/migrator/ts/TSTranspiler.java @@ -1,9 +1,25 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.ohos.migrator.ts; import com.ohos.migrator.AbstractTranspiler; import com.ohos.migrator.ResultCode; import com.ohos.migrator.TranspileException; -import com.ohos.migrator.Transpiler; +import com.ohos.migrator.staticTS.XMLReader; +import com.ohos.migrator.staticTS.parser.StaticTSParser.*; import com.ohos.migrator.util.FileUtils; import java.io.File; @@ -16,27 +32,45 @@ public class TSTranspiler extends AbstractTranspiler { private static String XML_EXT = ".xml"; private static String tsTranspilerJS = "typescript/build/javascript/src/transpiler/TypeScriptTranspiler.js"; - public TSTranspiler(List src, String outDir) { + private boolean keepXML; + public TSTranspiler(List src, String outDir, boolean keepXML) { super(src, null, outDir); + this.keepXML = keepXML; } @Override protected void transpileFile(File srcFile) throws TranspileException { try { - String baseDir = FileUtils.getMigratorJarPath().getParent(); + String baseDir = FileUtils.getMigratorJarPath().getParentFile().getParent(); String tsTranspilerPath = new File(baseDir, tsTranspilerJS).getPath(); + // Run TS translator and wait for it to exit. Process p = new ProcessBuilder("node", tsTranspilerPath, srcFile.getPath()).start(); int exitCode = p.waitFor(); if (exitCode != 0) { - // TODO: Add stderr contents here! - throw new TranspileException(ResultCode.TranspileError, "TS Transpiler exited abnormally"); + String stderr = p.getErrorStream().toString(); + throw new TranspileException(ResultCode.TranspileError, "TS transpiler exited abnormally.\nSTDERR:\n" + stderr); } + // Pick up XML file created by TS translator and process it. File xmlFile = new File(srcFile.getPath() + XML_EXT); if (xmlFile.exists()) { - // Convert xmlFile to STS + // Wipe out XML file created by TS translator + // unless specifically instructed by user not to. + if (!keepXML) xmlFile.deleteOnExit(); + + try { + XMLReader xmlReader = new XMLReader(xmlFile); + CompilationUnitContext stsCU = xmlReader.read(); + write(stsCU, srcFile); + } + catch (Exception e) { + throw new TranspileException(ResultCode.TranspileError, e); + } } + else + throw new TranspileException(ResultCode.TranspileError, "TS transpiler failed for " + + srcFile.getPath() + ": No XML output."); } catch (URISyntaxException use) { throw new TranspileException(ResultCode.CmdLineError, use); -- Gitee From d5acec198fa4714a0ca3c8aef5060654c1fa1a62 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 11 Nov 2022 16:58:53 +0300 Subject: [PATCH 10/15] Enable tests for TS migration. Make sure test results comparison can run properly regardless of whether comments migration is implemented or not. Don't rebuild TS code when Java and Kotlin tests are run, as they don't depend on it. Signed-off-by: Mikhail Velikanov --- migrator/build.xml | 32 +++++++++++++++---- migrator/src/com/ohos/migrator/Main.java | 5 +-- .../src/com/ohos/migrator/TestRunner.java | 19 ++++++++--- .../src/com/ohos/migrator/util/FileUtils.java | 9 ++++-- migrator/test/ts/empty_class.ts | 17 ++++++++++ migrator/test/ts/empty_class.ts.sts | 17 ++++++++++ migrator/typescript/test/empty_class.ts | 2 -- 7 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 migrator/test/ts/empty_class.ts create mode 100644 migrator/test/ts/empty_class.ts.sts delete mode 100644 migrator/typescript/test/empty_class.ts diff --git a/migrator/build.xml b/migrator/build.xml index ea6066d49..06c3124b4 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -129,7 +129,9 @@ - + + + @@ -139,7 +141,7 @@ - + @@ -160,7 +162,7 @@ - + @@ -212,22 +214,30 @@ - + - + - + - + + + + + + + + + @@ -235,4 +245,12 @@ + + + + + + + diff --git a/migrator/src/com/ohos/migrator/Main.java b/migrator/src/com/ohos/migrator/Main.java index 83011081e..d6d897bb5 100644 --- a/migrator/src/com/ohos/migrator/Main.java +++ b/migrator/src/com/ohos/migrator/Main.java @@ -92,7 +92,8 @@ public class Main { options.addOption(new Option("T","check-sts-syntax",false,"Check syntactical correctness of StaticTS sources")); options.addOption(new Option("R", "conversion-rate", false, "Report conversion rate")); options.addOption(new Option("noxrefs", "noxrefs", false, "Don't resolve cross-references in the input source files")); - options.addOption(new Option("verbose","verbose",false,"Prints extended diagnostic messages")); + options.addOption(new Option("verbose","verbose",false,"Report extended diagnostic info")); + options.addOption(new Option("k", "keep-temp-files", false, "Keep temporary files created by migrator")); options.addOption(new Option("v","version",false,"Version information")); CommandLineParser parser = new DefaultParser(); @@ -229,7 +230,7 @@ public class Main { if (!tsSources.isEmpty()) { System.out.println("Transpiling " + tsSources.size() + " TypeScript files."); - TSTranspiler tsTranspiler = new TSTranspiler(tsSources, outDir); + TSTranspiler tsTranspiler = new TSTranspiler(tsSources, outDir, cmd.hasOption("k")); resultCode = ResultCode.majorValue(tsTranspiler.transpile(), resultCode); outFiles.addAll(tsTranspiler.getOutFiles()); errorList.addAll(tsTranspiler.getErrorList()); diff --git a/migrator/src/com/ohos/migrator/TestRunner.java b/migrator/src/com/ohos/migrator/TestRunner.java index 55281ae54..cf31671bd 100644 --- a/migrator/src/com/ohos/migrator/TestRunner.java +++ b/migrator/src/com/ohos/migrator/TestRunner.java @@ -19,11 +19,13 @@ import com.ohos.migrator.util.FileUtils; import java.io.*; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class TestRunner { private static final Map testExtensions = new HashMap<>(); - + private static final Set langsWithCommentsMigration = new HashSet<>(); private static boolean hasComparisonFailures = false; static { @@ -31,13 +33,22 @@ public class TestRunner { testExtensions.put("java-mapper", Main.JAVA_EXT); testExtensions.put("kotlin", Main.KOTLIN_EXT); testExtensions.put("staticTS", Main.STS_EXT); + testExtensions.put("ts", Main.TS_EXT); + + // NOTE: Add languages here when comments + // migration is implemented for them! + langsWithCommentsMigration.add("java"); } + private static boolean usesOffset(String lang) { + return !langsWithCommentsMigration.contains(lang); + } public static void main(String[] args) { assert(args.length == 1); - String ext = testExtensions.get(args[0]); - File testDir = new File("test", args[0]); + String lang = args[0]; + String ext = testExtensions.get(lang); + File testDir = new File("test", lang); File testResultDir = new File(testDir, "results"); if (testDir.exists() && testDir.isDirectory()) { String[] testFiles = testDir.list((dir, name) -> name.endsWith(ext)); @@ -70,7 +81,7 @@ public class TestRunner { File expectedFile = new File(testDir, testFile + Main.STS_EXT); // Set a flag if comparison fails but keep comparing to report all failures. - if (!FileUtils.textuallyEqual(resultFile, expectedFile)) { + if (!FileUtils.textuallyEqual(resultFile, expectedFile, usesOffset(lang))) { ++failed; System.err.println("Resulting and expected STS files differ for test " + testFile); hasComparisonFailures = true; diff --git a/migrator/src/com/ohos/migrator/util/FileUtils.java b/migrator/src/com/ohos/migrator/util/FileUtils.java index 82d8b291c..13780dc83 100644 --- a/migrator/src/com/ohos/migrator/util/FileUtils.java +++ b/migrator/src/com/ohos/migrator/util/FileUtils.java @@ -45,15 +45,18 @@ public class FileUtils { } } - public static boolean textuallyEqual(File resultFile, File expectedFile) { + private static final int offset = 14; + public static boolean textuallyEqual(File resultFile, File expectedFile, boolean useOffset) { String[] resultText = readFile(resultFile); String[] expectedText = readFile(expectedFile); - if (resultText.length != expectedText.length) + int expectedLen = useOffset ? expectedText.length-offset : expectedText.length; + if (resultText.length != expectedLen) return false; for (int i = 0; i < resultText.length; ++i) { - if (!resultText[i].equals(expectedText[i])) + int expectedInd = useOffset ? i+offset : i; + if (!resultText[i].equals(expectedText[expectedInd])) return false; } diff --git a/migrator/test/ts/empty_class.ts b/migrator/test/ts/empty_class.ts new file mode 100644 index 000000000..c8c6efa6c --- /dev/null +++ b/migrator/test/ts/empty_class.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class empty { +} diff --git a/migrator/test/ts/empty_class.ts.sts b/migrator/test/ts/empty_class.ts.sts new file mode 100644 index 000000000..ebfb0fdac --- /dev/null +++ b/migrator/test/ts/empty_class.ts.sts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class empty { +} diff --git a/migrator/typescript/test/empty_class.ts b/migrator/typescript/test/empty_class.ts deleted file mode 100644 index 2e2439c32..000000000 --- a/migrator/typescript/test/empty_class.ts +++ /dev/null @@ -1,2 +0,0 @@ -class A { -} -- Gitee From 94525750d7595eed347e9f69917fc81294e313b4 Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Tue, 15 Nov 2022 19:52:30 +0300 Subject: [PATCH 11/15] TypeScript: Translation of simple function, primitive and named types. Change-Id: I36b7ad0717b06d7ec0078387df71291099d530a1 Signed-off-by: Evgeniy Okolnov --- migrator/test/ts/empty_function.ts | 21 +++ migrator/test/ts/empty_function.ts.sts | 22 +++ .../src/staticts/StaticTSContextBase.ts | 2 + .../typescript/src/transpiler/NodeBuilder.ts | 121 +++++++++++++++ .../src/transpiler/TranslationUtils.ts | 20 +++ .../src/transpiler/TypeScriptTransformer.ts | 138 +++++++++++++++--- migrator/typescript/tsconfig.json | 2 + 7 files changed, 309 insertions(+), 17 deletions(-) create mode 100644 migrator/test/ts/empty_function.ts create mode 100644 migrator/test/ts/empty_function.ts.sts create mode 100644 migrator/typescript/src/transpiler/NodeBuilder.ts create mode 100644 migrator/typescript/src/transpiler/TranslationUtils.ts diff --git a/migrator/test/ts/empty_function.ts b/migrator/test/ts/empty_function.ts new file mode 100644 index 000000000..b3546d4f6 --- /dev/null +++ b/migrator/test/ts/empty_function.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class MyClass { +} + +function foo() {} + +function bar(a: boolean, b: number, c: MyClass): void {} \ No newline at end of file diff --git a/migrator/test/ts/empty_function.ts.sts b/migrator/test/ts/empty_function.ts.sts new file mode 100644 index 000000000..241869c6a --- /dev/null +++ b/migrator/test/ts/empty_function.ts.sts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class MyClass { +} + +function foo(): __UnknownType__ { +} +function bar(a : boolean, b : double, c : MyClass): void { +} diff --git a/migrator/typescript/src/staticts/StaticTSContextBase.ts b/migrator/typescript/src/staticts/StaticTSContextBase.ts index 5a7a754eb..99ce6ea52 100644 --- a/migrator/typescript/src/staticts/StaticTSContextBase.ts +++ b/migrator/typescript/src/staticts/StaticTSContextBase.ts @@ -101,6 +101,8 @@ export class StaticTSContextBase extends ParserRuleContext { result += "/>\n"; } } + // Decrease indent after processing children. + --StaticTSContextBase.indent; // Add closing XML tag. result += xmlIndent + "\n"; diff --git a/migrator/typescript/src/transpiler/NodeBuilder.ts b/migrator/typescript/src/transpiler/NodeBuilder.ts new file mode 100644 index 000000000..cc72c4478 --- /dev/null +++ b/migrator/typescript/src/transpiler/NodeBuilder.ts @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonToken, ParserRuleContext } from "antlr4ts"; +import { TerminalNode } from "antlr4ts/tree"; +import * as sts from "../../build/typescript/StaticTSParser"; +import * as ts from "typescript"; + +export const UNKNOWN_TYPE_NAME = "__UnknownType__"; + +export type STSTypeContext = sts.TypeReferenceContext | sts.ArrayTypeContext | sts.PredefinedTypeContext; + +export function terminalIdentifier(name: string): TerminalNode { + return terminalNode(sts.StaticTSParser.Identifier, name); +} + +export function terminalNode(tokenKind: number, tokenName?: string): TerminalNode { + if (!tokenName) tokenName = stsTokenName(tokenKind); + return new TerminalNode(new CommonToken(tokenKind, tokenName)); +} + +export function stsTokenName(tokenKind: number): string { + return sts.StaticTSParser.VOCABULARY.getLiteralName(tokenKind); +} + +export function entityNameToString(fqName: ts.EntityName): string { + if (ts.isIdentifier(fqName)) { + return fqName.text; + } + else { + return entityNameToString(fqName.left) + "." + fqName.right.text; + } +} + +export function qualifiedName(fqName: ts.EntityName | string): sts.QualifiedNameContext { + let stsQualifiedName = new sts.QualifiedNameContext(null, 0); + if (typeof(fqName) === 'string') { + stsQualifiedName.addChild(terminalIdentifier(fqName)); + } + else { + stsQualifiedName.addChild(terminalIdentifier(entityNameToString(fqName))); + } + return stsQualifiedName; +} + +export function typeReference(typeName: ts.EntityName | string): sts.TypeReferenceContext { + let stsTypeRef = new sts.TypeReferenceContext(null, 0); + let stsTypeRefPart = typeReferencePart(typeName); + stsTypeRef.addChild(stsTypeRefPart); + return stsTypeRef; +} + +export function typeReferencePart(typeName: ts.EntityName | string): sts.TypeReferencePartContext { + let stsTypeRefPart = new sts.TypeReferencePartContext(null, 0); + stsTypeRefPart.addChild(qualifiedName(typeName)); + return stsTypeRefPart; +} + +export function unknownTypeReference(): sts.TypeReferenceContext { + let stsTypeRef = typeReference(UNKNOWN_TYPE_NAME); + return stsTypeRef; +} + +export function typeAnnotation(stsType: STSTypeContext | string): sts.TypeAnnotationContext { + if (typeof (stsType) === 'string') { + let stsTypeRef = typeReference(stsType); + return typeAnnotation(stsTypeRef); + } + else { + let stsTypeAnno = new sts.TypeAnnotationContext(null, 0); + let stsPrimaryType = new sts.PrimaryTypeContext(stsTypeAnno, 0); + stsPrimaryType.addChild(stsType); + stsTypeAnno.addChild(stsPrimaryType); + return stsTypeAnno; + } +} + +export function unknownTypeAnnotation(): sts.TypeAnnotationContext { + return typeAnnotation(UNKNOWN_TYPE_NAME); +} + +function stsPredefinedTypeCode(tsTypeKind: ts.SyntaxKind): number { + let stsTypeCode = -1; + + if (tsTypeKind === ts.SyntaxKind.BooleanKeyword) + stsTypeCode = sts.StaticTSParser.Boolean; + else if (tsTypeKind === ts.SyntaxKind.NumberKeyword) + stsTypeCode = sts.StaticTSParser.Double; // number type corresponds to double + else if (tsTypeKind === ts.SyntaxKind.BigIntKeyword) + stsTypeCode = sts.StaticTSParser.Long; // TODO: BigInt doesn't have maximum limit + else if (tsTypeKind === ts.SyntaxKind.StringKeyword) + stsTypeCode = sts.StaticTSParser.String; + else if (tsTypeKind === ts.SyntaxKind.VoidKeyword) + stsTypeCode = sts.StaticTSParser.Void; + //else TODO: Report an error + + return stsTypeCode; +} + +export function predefinedType(tsType: ts.TypeNode): sts.PredefinedTypeContext | sts.TypeReferenceContext { + let stsPredefinedType = new sts.PredefinedTypeContext(null, 0); + let stsTokenKind = stsPredefinedTypeCode(tsType.kind); + + // Return UNKNOWN_TYPE for unrecognized primitive type + if (stsTokenKind === -1) return unknownTypeReference(); + + stsPredefinedType.addChild(terminalNode(stsTokenKind)); + return stsPredefinedType; +} \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/TranslationUtils.ts b/migrator/typescript/src/transpiler/TranslationUtils.ts new file mode 100644 index 000000000..0110ee385 --- /dev/null +++ b/migrator/typescript/src/transpiler/TranslationUtils.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; + +export function isFunctionBlock(tsNode: ts.Node): boolean { + return tsNode && tsNode.kind === ts.SyntaxKind.Block && ts.isFunctionLike(tsNode.parent); +} diff --git a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts index 7cf5dc933..b41a3d6fd 100644 --- a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts @@ -18,6 +18,8 @@ import { TerminalNode } from "antlr4ts/tree"; import * as ts from "typescript"; import { StaticTSContextBase } from "../staticts/StaticTSContextBase"; import * as sts from "../../build/typescript/StaticTSParser"; +import * as TranslationUtils from "./TranslationUtils"; +import * as NodeBuilder from "./NodeBuilder"; type VisitFunction = (tsNode: T) => StaticTSContextBase; type VisitorTable = { [key: number]: VisitFunction }; @@ -36,7 +38,10 @@ export class TypeScriptTransformer { readonly visitorTable : VisitorTable = { [ts.SyntaxKind.SourceFile]: this.visitSourceFile, [ts.SyntaxKind.ClassDeclaration]: this.visitClassDeclaration, - [ts.SyntaxKind.FunctionDeclaration]: this.visitFunctionDeclaration + [ts.SyntaxKind.FunctionDeclaration]: this.visitFunctionDeclaration, + [ts.SyntaxKind.Parameter]: this.visitParameter, + [ts.SyntaxKind.Block]: this.visitBlock, + [ts.SyntaxKind.TypeReference]: this.visitTypeReference } /** @@ -47,7 +52,11 @@ export class TypeScriptTransformer { let visitFn = this.visitorTable[tsNode.kind]; if (visitFn) { - return visitFn(tsNode); + // Since we call certain 'visit' function as a callback, the 'this' + // inside 'visit' function won't refer to the instance context, and + // instead it will be 'undefined'. We need to explicitly bind 'this' + // to the method call. For this purpose, use the 'Function.call' API. + return visitFn.call(this, tsNode); } else { return null; // Print untranslated node? @@ -58,7 +67,7 @@ export class TypeScriptTransformer { let stsCU = new sts.CompilationUnitContext(null, 0); for(const tsNode of tsSourceFile.statements) { let stsChildNode = this.visitNode(tsNode); - if (stsChildNode !== null) { + if (stsChildNode) { let stsTopDecl = new sts.TopDeclarationContext(stsCU, 0); stsTopDecl.addChild(stsChildNode); stsCU.addChild(stsTopDecl); @@ -71,27 +80,122 @@ export class TypeScriptTransformer { visitClassDeclaration(tsClassDecl: ts.ClassDeclaration): sts.ClassDeclarationContext { let stsClassDecl = new sts.ClassDeclarationContext(null, 0); let tsClassName : string = tsClassDecl.name.getText(); - stsClassDecl.addChild(createToken(sts.StaticTSParser.Class)); - stsClassDecl.addChild(createIdentifier(tsClassName)); + stsClassDecl.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Class)); + stsClassDecl.addChild(NodeBuilder.terminalIdentifier(tsClassName)); stsClassDecl.addChild(new sts.ClassBodyContext(stsClassDecl, 0)); return stsClassDecl; } visitFunctionDeclaration(tsFunDecl: ts.FunctionDeclaration): sts.FunctionDeclarationContext { - console.log(`Function: ${tsFunDecl.name.text}`) - return null; + let stsFunDecl = new sts.FunctionDeclarationContext(null, 0); + stsFunDecl.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Function)); + stsFunDecl.addChild(NodeBuilder.terminalIdentifier(tsFunDecl.name.text)); + stsFunDecl.addChild(this.translateSignature(tsFunDecl)); + + if (tsFunDecl.body) { + stsFunDecl.addChild(this.visitNode(tsFunDecl.body)); + } + + return stsFunDecl; + } + + translateSignature(tsFunLikeDecl: ts.FunctionLikeDeclarationBase): sts.SignatureContext { + let stsSignature = new sts.SignatureContext(null, 0); + + // TODO: Translate type parameters. + + let tsParameters = tsFunLikeDecl.parameters; + if (tsParameters && tsParameters.length > 0) { + let stsParameterList = new sts.ParameterListContext(null, 0); + for (const tsParameter of tsParameters) { + let stsParam = this.visitNode(tsParameter); + stsParameterList.addChild(stsParam); + } + stsSignature.addChild(stsParameterList); + } + + let stsTypeRef : NodeBuilder.STSTypeContext; + let tsRetType = tsFunLikeDecl.type; + if (tsRetType) { + stsTypeRef = this.translateType(tsRetType); + } else { + // TODO: Check the return type with TypeChecker. + stsTypeRef = NodeBuilder.unknownTypeReference(); + } + + stsSignature.addChild(NodeBuilder.typeAnnotation(stsTypeRef)); + + return stsSignature; + } + + visitParameter(tsParameter: ts.ParameterDeclaration): StaticTSContextBase { + let stsParam = new sts.ParameterContext(null, 0); + + let tsParamName = tsParameter.name; + if (ts.isIdentifier(tsParamName)) { + stsParam.addChild(NodeBuilder.terminalIdentifier(tsParamName.text)); + + let stsTypeRef : NodeBuilder.STSTypeContext; + let tsParamType = tsParameter.type; + if (tsParamType) { + stsTypeRef = this.translateType(tsParamType); + } else { + // TODO: Check the parameter type with TypeChecker. + stsTypeRef = NodeBuilder.unknownTypeReference(); + } + + stsParam.addChild(NodeBuilder.typeAnnotation(stsTypeRef)); + } else { + // TODO: Translate destructuring parameter. + } + + return stsParam; } -} -function createIdentifier(name : string) : TerminalNode { - return createToken(sts.StaticTSParser.Identifier, name); -} + visitBlock(tsBlock: ts.Block): StaticTSContextBase { + let stsBlock = new sts.BlockContext(null, 0); -function createToken(tokenKind : number, tokenName? : string) : TerminalNode { - if (tokenName == undefined) tokenName = stsTokenName(tokenKind); - return new TerminalNode(new CommonToken(tokenKind, tokenName)); -} + for (const tsStmt of tsBlock.statements) { + // TODO: Translate statements. + } -function stsTokenName(tokenKind : number) : string { - return sts.StaticTSParser.VOCABULARY.getLiteralName(tokenKind); + if (!TranslationUtils.isFunctionBlock(tsBlock)) { + // Block itself is a statement. Wrap it up with Statement context. + let stsBlockStmt = new sts.StatementContext(stsBlock, 0); + stsBlockStmt.addChild(stsBlock); + return stsBlockStmt; + } + + return stsBlock; + } + + translateType(tsType: ts.TypeNode): NodeBuilder.STSTypeContext { + switch (tsType.kind) { + case ts.SyntaxKind.NumberKeyword: + case ts.SyntaxKind.BooleanKeyword: + case ts.SyntaxKind.BigIntKeyword: + case ts.SyntaxKind.StringKeyword: + case ts.SyntaxKind.VoidKeyword: + return NodeBuilder.predefinedType(tsType); + case ts.SyntaxKind.AnyKeyword: + case ts.SyntaxKind.ObjectKeyword: + case ts.SyntaxKind.SymbolKeyword: + case ts.SyntaxKind.IntrinsicKeyword: + case ts.SyntaxKind.NeverKeyword: + case ts.SyntaxKind.UndefinedKeyword: + case ts.SyntaxKind.UnknownKeyword: + // TODO: for now, return __UnknownType__ for all of these type kinds. + return NodeBuilder.unknownTypeReference(); + default: + return (this.visitNode(tsType) as sts.TypeReferenceContext | sts.ArrayTypeContext); + } + } + + visitTypeReference(tsTypeRef: ts.TypeReferenceNode): sts.TypeReferenceContext { + let stsTypeRef = new sts.TypeReferenceContext(null, 0); + let stsTypeRefPart = NodeBuilder.typeReferencePart(tsTypeRef.typeName); + stsTypeRef.addChild(stsTypeRefPart); + // TODO: translate type arguments. + return stsTypeRef; + } } \ No newline at end of file diff --git a/migrator/typescript/tsconfig.json b/migrator/typescript/tsconfig.json index 51e8a321f..3a4babf51 100644 --- a/migrator/typescript/tsconfig.json +++ b/migrator/typescript/tsconfig.json @@ -3,6 +3,8 @@ "module": "CommonJS", "target": "ES6", "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, "removeComments": true, "preserveConstEnums": true, "sourceMap": true, -- Gitee From 28924d65e9399c502976868ff612e8fdd71b11ca Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Thu, 17 Nov 2022 09:48:54 +0100 Subject: [PATCH 12/15] Initial ets development Change-Id: I2e9d10735859a6e5ddfa304b7ff4a23b13113d31 Signed-off-by: Csaba Osztrogonac --- .gitignore | 6 + BUILD.gn | 214 +- CMakeLists.txt | 238 +- README.md | 29 +- aot/main.cpp | 25 +- aot/options.cpp | 12 +- aot/options.h | 14 +- binder/ASBinder.cpp | 19 + binder/ASBinder.h | 46 + binder/ETSBinder.cpp | 740 ++ binder/ETSBinder.h | 140 + binder/JSBinder.cpp | 19 + binder/JSBinder.h | 34 + binder/TSBinder.cpp | 19 + binder/TSBinder.h | 44 + binder/TypedBinder.cpp | 77 + binder/TypedBinder.h | 36 + binder/binder.cpp | 371 +- binder/binder.h | 178 +- binder/declaration.h | 49 +- binder/recordTable.cpp | 106 + binder/recordTable.h | 216 + binder/scope.cpp | 253 +- binder/scope.h | 298 +- binder/variable.cpp | 2 + binder/variable.h | 23 +- binder/variableFlags.h | 109 +- checker/ASchecker.cpp | 32 + checker/ASchecker.h | 45 + checker/ETSchecker.cpp | 248 + checker/ETSchecker.h | 322 + checker/JSchecker.cpp | 35 + .../checkerContext.h => checker/JSchecker.h | 45 +- checker/TSchecker.cpp | 51 + typescript/checker.h => checker/TSchecker.h | 327 +- .../typeRelation.cpp => checker/checker.cpp | 88 +- checker/checker.h | 268 + .../core => checker}/checkerContext.cpp | 0 checker/checkerContext.h | 97 + checker/ets/aliveAnalyzer.cpp | 422 + checker/ets/aliveAnalyzer.h | 87 + checker/ets/arithmetic.cpp | 349 + checker/ets/arithmetic.h | 224 + checker/ets/baseAnalyzer.cpp | 86 + checker/ets/baseAnalyzer.h | 99 + checker/ets/boxingConverter.cpp | 76 + checker/ets/boxingConverter.h | 48 + checker/ets/function.cpp | 634 ++ checker/ets/helpers.cpp | 998 ++ checker/ets/narrowingConverter.cpp | 19 + checker/ets/narrowingConverter.h | 123 + checker/ets/narrowingWideningConverter.cpp | 19 + checker/ets/narrowingWideningConverter.h | 37 + checker/ets/object.cpp | 1039 ++ checker/ets/primitiveWrappers.cpp | 19 + checker/ets/primitiveWrappers.h | 58 + checker/ets/typeConverter.cpp | 53 + checker/ets/typeConverter.h | 43 + checker/ets/typeCreation.cpp | 306 + checker/ets/typeRelationContext.cpp | 130 + checker/ets/typeRelationContext.h | 192 + checker/ets/unboxingConverter.cpp | 55 + checker/ets/unboxingConverter.h | 44 + checker/ets/wideningConverter.cpp | 19 + checker/ets/wideningConverter.h | 201 + .../ts}/binaryLikeExpression.cpp | 29 +- .../ts}/destructuringContext.cpp | 31 +- .../ts}/destructuringContext.h | 44 +- {typescript/core => checker/ts}/function.cpp | 199 +- {typescript/core => checker/ts}/helpers.cpp | 132 +- {typescript/core => checker/ts}/object.cpp | 110 +- .../core => checker/ts}/typeCreation.cpp | 78 +- .../ts}/typeElaborationContext.cpp | 8 +- .../ts}/typeElaborationContext.h | 18 +- {typescript/core => checker/ts}/util.cpp | 53 +- checker/types/ets/byteType.cpp | 60 + checker/types/ets/byteType.h | 54 + checker/types/ets/charType.cpp | 61 + checker/types/ets/charType.h | 54 + checker/types/ets/doubleType.cpp | 52 + checker/types/ets/doubleType.h | 54 + checker/types/ets/etsArrayType.cpp | 74 + checker/types/ets/etsArrayType.h | 50 + checker/types/ets/etsBooleanType.cpp | 51 + checker/types/ets/etsBooleanType.h | 53 + checker/types/ets/etsFunctionType.cpp | 128 + checker/types/ets/etsFunctionType.h | 96 + checker/types/ets/etsObjectType.cpp | 462 + checker/types/ets/etsObjectType.h | 410 + checker/types/ets/etsStringType.cpp | 40 + checker/types/ets/etsStringType.h | 63 + checker/types/ets/etsTypeParameter.cpp | 33 + checker/types/ets/etsTypeParameter.h | 64 + checker/types/ets/etsTypeReference.cpp | 85 + checker/types/ets/etsTypeReference.h | 69 + checker/types/ets/etsVoidType.cpp | 33 + .../types/ets/etsVoidType.h | 47 +- checker/types/ets/floatType.cpp | 61 + checker/types/ets/floatType.h | 54 + checker/types/ets/intType.cpp | 61 + checker/types/ets/intType.h | 54 + checker/types/ets/longType.cpp | 61 + checker/types/ets/longType.h | 54 + checker/types/ets/shortType.cpp | 61 + checker/types/ets/shortType.h | 54 + checker/types/ets/types.h | 37 + checker/types/ets/wildcardType.cpp | 38 + checker/types/ets/wildcardType.h | 38 + .../types/globalTypesHolder.cpp | 344 +- .../types/globalTypesHolder.h | 123 +- {typescript => checker}/types/signature.cpp | 27 +- {typescript => checker}/types/signature.h | 99 +- .../types => checker/types/ts}/anyType.cpp | 0 .../types => checker/types/ts}/anyType.h | 8 +- .../types => checker/types/ts}/arrayType.cpp | 2 +- .../types => checker/types/ts}/arrayType.h | 6 +- .../types/ts}/bigintLiteralType.cpp | 0 .../types/ts}/bigintLiteralType.h | 6 +- .../types => checker/types/ts}/bigintType.cpp | 0 .../types => checker/types/ts}/bigintType.h | 6 +- .../types/ts}/booleanLiteralType.cpp | 0 .../types/ts}/booleanLiteralType.h | 6 +- .../types/ts}/booleanType.cpp | 0 .../types => checker/types/ts}/booleanType.h | 6 +- .../types/ts}/constructorType.cpp | 2 +- .../types/ts}/constructorType.h | 4 +- .../types => checker/types/ts}/elementFlags.h | 14 +- .../types/ts}/enumLiteralType.cpp | 2 +- .../types/ts}/enumLiteralType.h | 6 +- .../types => checker/types/ts}/enumType.cpp | 0 .../types => checker/types/ts}/enumType.h | 6 +- .../types/ts}/functionType.cpp | 2 +- .../types => checker/types/ts}/functionType.h | 4 +- .../types => checker/types/ts}/indexInfo.cpp | 0 .../types => checker/types/ts}/indexInfo.h | 6 +- .../types/ts}/interfaceType.cpp | 4 +- .../types/ts}/interfaceType.h | 4 +- .../types => checker/types/ts}/neverType.cpp | 0 .../types => checker/types/ts}/neverType.h | 6 +- .../types/ts}/nonPrimitiveType.cpp | 0 .../types/ts}/nonPrimitiveType.h | 6 +- .../types => checker/types/ts}/nullType.cpp | 0 .../types => checker/types/ts}/nullType.h | 6 +- .../types/ts}/numberLiteralType.cpp | 2 +- .../types/ts}/numberLiteralType.h | 6 +- .../types => checker/types/ts}/numberType.cpp | 2 +- .../types => checker/types/ts}/numberType.h | 6 +- .../types/ts}/objectDescriptor.cpp | 4 +- .../types/ts}/objectDescriptor.h | 4 +- .../types/ts}/objectLiteralType.cpp | 6 +- .../types/ts}/objectLiteralType.h | 4 +- .../types => checker/types/ts}/objectType.cpp | 8 +- .../types => checker/types/ts}/objectType.h | 25 +- .../types/ts}/stringLiteralType.cpp | 0 .../types/ts}/stringLiteralType.h | 6 +- .../types => checker/types/ts}/stringType.cpp | 0 .../types => checker/types/ts}/stringType.h | 6 +- .../types => checker/types/ts}/tupleType.cpp | 4 +- .../types => checker/types/ts}/tupleType.h | 10 +- .../types/ts}/typeParameter.cpp | 0 .../types/ts}/typeParameter.h | 6 +- .../types/ts}/typeReference.cpp | 0 .../types/ts}/typeReference.h | 8 +- .../types => checker/types/ts}/types.h | 6 +- .../types/ts}/undefinedType.cpp | 0 .../types/ts}/undefinedType.h | 6 +- .../types => checker/types/ts}/unionType.cpp | 2 +- .../types => checker/types/ts}/unionType.h | 6 +- .../types/ts}/unknownType.cpp | 0 .../types => checker/types/ts}/unknownType.h | 6 +- .../types => checker/types/ts}/voidType.cpp | 0 .../types => checker/types/ts}/voidType.h | 6 +- {typescript => checker}/types/type.cpp | 28 +- {typescript => checker}/types/type.h | 50 +- {typescript => checker}/types/typeFacts.h | 54 +- {typescript => checker}/types/typeFlag.h | 107 +- checker/types/typeMapping.h | 68 + .../types/typeRelation.cpp | 40 +- {typescript => checker}/types/typeRelation.h | 164 +- compiler/base/catchTable.cpp | 4 +- compiler/base/catchTable.h | 6 +- compiler/base/condition.cpp | 80 + compiler/base/condition.h | 9 + compiler/base/destructuring.cpp | 10 +- compiler/base/literals.h | 4 +- compiler/base/lreference.cpp | 203 +- compiler/base/lreference.h | 116 +- compiler/base/optionalChain.cpp | 2 +- compiler/core/ETSGen.cpp | 1305 +++ compiler/core/ETSGen.h | 670 ++ compiler/core/ETSemitter.cpp | 645 ++ compiler/core/ETSemitter.h | 93 + compiler/core/ETSfunction.cpp | 221 + compiler/core/ETSfunction.h | 45 + compiler/core/JSemitter.cpp | 101 + compiler/core/JSemitter.h | 58 + compiler/core/codeGen.cpp | 198 + compiler/core/codeGen.h | 265 + compiler/core/compileJob.cpp | 49 + compiler/core/compileJob.h | 72 + compiler/core/compileQueue.cpp | 48 +- compiler/core/compileQueue.h | 34 +- compiler/core/compilerContext.cpp | 10 - compiler/core/compilerContext.h | 49 +- compiler/core/compilerImpl.cpp | 130 +- compiler/core/compilerImpl.h | 30 +- compiler/core/dynamicContext.cpp | 75 +- compiler/core/dynamicContext.h | 109 +- compiler/core/emitter.cpp | 127 +- compiler/core/emitter.h | 80 +- compiler/core/envScope.cpp | 7 +- compiler/core/envScope.h | 4 +- compiler/core/function.cpp | 8 +- compiler/core/labelTarget.cpp | 6 +- compiler/core/labelTarget.h | 4 +- compiler/core/pandagen.cpp | 715 +- compiler/core/pandagen.h | 196 +- compiler/core/programElement.cpp | 50 + compiler/core/programElement.h | 48 + compiler/core/regAllocator.cpp | 60 +- compiler/core/regAllocator.h | 28 +- compiler/core/regScope.cpp | 111 +- compiler/core/regScope.h | 11 +- compiler/core/regSpiller.cpp | 94 + compiler/core/regSpiller.h | 122 + compiler/core/switchBuilder.cpp | 57 - compiler/core/switchBuilder.h | 68 +- ...{inlineCache.cpp => targetTypeContext.cpp} | 23 +- compiler/core/targetTypeContext.h | 45 + compiler/core/{inlineCache.h => vReg.cpp} | 19 +- compiler/core/vReg.h | 148 + compiler/function/functionBuilder.cpp | 2 +- compiler/scripts/signatures.rb | 71 + compiler/scripts/signatures.yaml | 367 + compiler/templates/isa.h.erb | 9 +- compiler/templates/signatures.h.erb | 59 + es2panda.cpp | 39 +- es2panda.h | 31 +- ir/as/namedType.cpp | 13 +- ir/as/namedType.h | 11 +- ir/as/prefixAssertionExpression.cpp | 8 +- ir/as/prefixAssertionExpression.h | 9 +- ir/astDump.cpp | 35 +- ir/astDump.h | 35 +- ir/astNode.cpp | 42 + ir/astNode.h | 252 +- ir/astNodeMapping.h | 272 +- ir/base/catchClause.cpp | 56 +- ir/base/catchClause.h | 32 +- ir/base/classDefinition.cpp | 88 +- ir/base/classDefinition.h | 157 +- ir/base/classElement.cpp | 16 +- ir/base/classElement.h | 25 +- ir/base/classProperty.cpp | 56 +- ir/base/classProperty.h | 24 +- ir/base/classStaticBlock.cpp | 48 +- ir/base/classStaticBlock.h | 17 +- ir/base/decorator.cpp | 7 +- ir/base/decorator.h | 12 +- ir/base/metaProperty.cpp | 9 +- ir/base/metaProperty.h | 12 +- ir/base/methodDefinition.cpp | 82 +- ir/base/methodDefinition.h | 24 +- ir/base/property.cpp | 7 +- ir/base/property.h | 12 +- ir/base/scriptFunction.cpp | 17 +- ir/base/scriptFunction.h | 106 +- ir/base/spreadElement.cpp | 19 +- ir/base/spreadElement.h | 28 +- ir/base/templateElement.cpp | 7 +- ir/base/templateElement.h | 14 +- ir/{ts => base}/tsIndexSignature.cpp | 19 +- ir/{ts => base}/tsIndexSignature.h | 28 +- ir/{ts => base}/tsMethodSignature.cpp | 11 +- ir/{ts => base}/tsMethodSignature.h | 28 +- ir/{ts => base}/tsPropertySignature.cpp | 23 +- ir/{ts => base}/tsPropertySignature.h | 32 +- ir/{ts => base}/tsSignatureDeclaration.cpp | 19 +- ir/{ts => base}/tsSignatureDeclaration.h | 28 +- ir/ets/etsClassLiteral.cpp | 70 + ir/ets/etsClassLiteral.h | 39 + ir/ets/etsFunctionType.cpp | 124 + ir/ets/etsFunctionType.h | 98 + ir/ets/etsMethodReferenceExpression.cpp | 108 + ir/ets/etsMethodReferenceExpression.h | 122 + ir/ets/etsNewArrayInstanceExpression.cpp | 66 + ir/ets/etsNewArrayInstanceExpression.h | 46 + ir/ets/etsNewClassInstanceExpression.cpp | 98 + ir/ets/etsNewClassInstanceExpression.h | 75 + .../etsNewMultiDimArrayInstanceExpression.cpp | 66 + .../etsNewMultiDimArrayInstanceExpression.h | 61 + ir/ets/etsPackageDeclaration.cpp | 48 + ir/ets/etsPackageDeclaration.h | 41 + ir/ets/etsPrimitiveType.cpp | 97 + ir/ets/etsPrimitiveType.h | 47 + ir/ets/etsScript.cpp | 20 + ir/ets/etsScript.h | 49 + ir/ets/etsTryExpression.cpp | 51 + ir/ets/etsTryExpression.h | 39 + ir/ets/etsTypeReference.cpp | 85 + ir/ets/etsTypeReference.h | 49 + ir/ets/etsTypeReferencePart.cpp | 79 + ir/ets/etsTypeReferencePart.h | 73 + ir/ets/etsWildcardType.cpp | 69 + ir/ets/etsWildcardType.h | 72 + ir/expression.h | 44 +- ir/expressions/arrayExpression.cpp | 94 +- ir/expressions/arrayExpression.h | 41 +- ir/expressions/arrowFunctionExpression.cpp | 11 +- ir/expressions/arrowFunctionExpression.h | 12 +- ir/expressions/assignmentExpression.cpp | 104 +- ir/expressions/assignmentExpression.h | 24 +- ir/expressions/awaitExpression.cpp | 9 +- ir/expressions/awaitExpression.h | 12 +- ir/expressions/binaryExpression.cpp | 89 +- ir/expressions/binaryExpression.h | 27 +- ir/expressions/callExpression.cpp | 96 +- ir/expressions/callExpression.h | 38 +- ir/expressions/chainExpression.cpp | 13 +- ir/expressions/chainExpression.h | 14 +- ir/expressions/classExpression.cpp | 7 +- ir/expressions/classExpression.h | 12 +- ir/expressions/conditionalExpression.cpp | 46 +- ir/expressions/conditionalExpression.h | 14 +- ir/expressions/directEvalExpression.h | 4 - ir/expressions/functionExpression.cpp | 17 +- ir/expressions/functionExpression.h | 18 +- ir/expressions/identifier.cpp | 48 +- ir/expressions/identifier.h | 66 +- ir/expressions/importExpression.cpp | 7 +- ir/expressions/importExpression.h | 12 +- ir/expressions/literal.h | 9 - ir/expressions/literals/bigIntLiteral.cpp | 9 +- ir/expressions/literals/bigIntLiteral.h | 12 +- ir/expressions/literals/booleanLiteral.cpp | 17 +- ir/expressions/literals/booleanLiteral.h | 13 +- ir/expressions/literals/charLiteral.cpp | 50 + ir/expressions/literals/charLiteral.h | 50 + ir/expressions/literals/nullLiteral.cpp | 17 +- ir/expressions/literals/nullLiteral.h | 13 +- ir/expressions/literals/numberLiteral.cpp | 80 +- ir/expressions/literals/numberLiteral.h | 39 +- ir/expressions/literals/regExpLiteral.cpp | 9 +- ir/expressions/literals/regExpLiteral.h | 12 +- ir/expressions/literals/stringLiteral.cpp | 17 +- ir/expressions/literals/stringLiteral.h | 14 +- ir/expressions/memberExpression.cpp | 86 +- ir/expressions/memberExpression.h | 65 +- ir/expressions/newExpression.cpp | 15 +- ir/expressions/newExpression.h | 13 +- ir/expressions/objectExpression.cpp | 50 +- ir/expressions/objectExpression.h | 32 +- ir/expressions/omittedExpression.cpp | 9 +- ir/expressions/omittedExpression.h | 12 +- ir/expressions/sequenceExpression.cpp | 9 +- ir/expressions/sequenceExpression.h | 12 +- ir/expressions/superExpression.cpp | 18 +- ir/expressions/superExpression.h | 13 +- ir/expressions/taggedTemplateExpression.cpp | 13 +- ir/expressions/taggedTemplateExpression.h | 14 +- ir/expressions/templateLiteral.cpp | 9 +- ir/expressions/templateLiteral.h | 14 +- ir/expressions/thisExpression.cpp | 22 +- ir/expressions/thisExpression.h | 13 +- ir/expressions/unaryExpression.cpp | 76 +- ir/expressions/unaryExpression.h | 8 +- ir/expressions/updateExpression.cpp | 53 +- ir/expressions/updateExpression.h | 13 +- ir/expressions/yieldExpression.cpp | 9 +- ir/expressions/yieldExpression.h | 9 +- ir/irnode.cpp | 6 - ir/irnode.h | 35 +- ir/module/exportAllDeclaration.cpp | 7 +- ir/module/exportAllDeclaration.h | 12 +- ir/module/exportDefaultDeclaration.cpp | 7 +- ir/module/exportDefaultDeclaration.h | 17 +- ir/module/exportNamedDeclaration.cpp | 13 +- ir/module/exportNamedDeclaration.h | 27 +- ir/module/exportSpecifier.cpp | 7 +- ir/module/exportSpecifier.h | 12 +- ir/module/importDeclaration.cpp | 13 +- ir/module/importDeclaration.h | 13 +- ir/module/importDefaultSpecifier.cpp | 7 +- ir/module/importDefaultSpecifier.h | 12 +- ir/module/importNamespaceSpecifier.cpp | 7 +- ir/module/importNamespaceSpecifier.h | 12 +- ir/module/importSpecifier.cpp | 18 +- ir/module/importSpecifier.h | 29 +- ir/statement.h | 23 +- ir/statements/assertStatement.cpp | 105 + ir/statements/assertStatement.h | 57 + ir/statements/blockStatement.cpp | 26 +- ir/statements/blockStatement.h | 20 +- ir/statements/breakStatement.cpp | 25 +- ir/statements/breakStatement.h | 21 +- ir/statements/classDeclaration.cpp | 17 +- ir/statements/classDeclaration.h | 19 +- ir/statements/continueStatement.cpp | 25 +- ir/statements/continueStatement.h | 21 +- ir/statements/debuggerStatement.cpp | 7 +- ir/statements/debuggerStatement.h | 12 +- ir/statements/deferStatement.cpp | 49 + ir/statements/deferStatement.h | 45 + ir/statements/doWhileStatement.cpp | 57 +- ir/statements/doWhileStatement.h | 15 +- ir/statements/emptyStatement.cpp | 7 +- ir/statements/emptyStatement.h | 12 +- ir/statements/expressionStatement.cpp | 12 +- ir/statements/expressionStatement.h | 18 +- ir/statements/forInStatement.cpp | 17 +- ir/statements/forInStatement.h | 12 +- ir/statements/forOfStatement.cpp | 23 +- ir/statements/forOfStatement.h | 13 +- ir/statements/forUpdateStatement.cpp | 70 +- ir/statements/forUpdateStatement.h | 13 +- ir/statements/functionDeclaration.cpp | 20 +- ir/statements/functionDeclaration.h | 18 +- ir/statements/ifStatement.cpp | 53 +- ir/statements/ifStatement.h | 15 +- ir/statements/labelledStatement.cpp | 45 +- ir/statements/labelledStatement.h | 17 +- ir/statements/loopStatement.h | 18 +- ir/statements/panicStatement.cpp | 74 + ir/statements/panicStatement.h | 45 + ir/statements/returnStatement.cpp | 73 +- ir/statements/returnStatement.h | 20 +- ir/statements/switchCaseStatement.cpp | 7 +- ir/statements/switchCaseStatement.h | 19 +- ir/statements/switchStatement.cpp | 80 +- ir/statements/switchStatement.h | 15 +- ir/statements/throwStatement.cpp | 16 +- ir/statements/throwStatement.h | 15 +- ir/statements/trapStatement.cpp | 119 + ir/statements/trapStatement.h | 58 + ir/statements/tryStatement.cpp | 79 +- ir/statements/tryStatement.h | 8 +- ir/statements/variableDeclaration.cpp | 21 +- ir/statements/variableDeclaration.h | 13 +- ir/statements/variableDeclarator.cpp | 67 +- ir/statements/variableDeclarator.h | 19 +- ir/statements/whileStatement.cpp | 52 +- ir/statements/whileStatement.h | 15 +- ir/ts/tsAnyKeyword.cpp | 11 +- ir/ts/tsAnyKeyword.h | 14 +- ir/ts/tsArrayType.cpp | 21 +- ir/ts/tsArrayType.h | 21 +- ir/ts/tsAsExpression.cpp | 68 +- ir/ts/tsAsExpression.h | 28 +- ir/ts/tsBigintKeyword.cpp | 11 +- ir/ts/tsBigintKeyword.h | 14 +- ir/ts/tsBooleanKeyword.cpp | 11 +- ir/ts/tsBooleanKeyword.h | 14 +- ir/ts/tsClassImplements.cpp | 7 +- ir/ts/tsClassImplements.h | 26 +- ir/ts/tsConditionalType.cpp | 9 +- ir/ts/tsConditionalType.h | 14 +- ir/ts/tsConstructorType.cpp | 15 +- ir/ts/tsConstructorType.h | 20 +- ir/ts/tsEnumDeclaration.cpp | 39 +- ir/ts/tsEnumDeclaration.h | 45 +- ir/ts/tsEnumMember.cpp | 7 +- ir/ts/tsEnumMember.h | 12 +- ir/ts/tsExternalModuleReference.cpp | 7 +- ir/ts/tsExternalModuleReference.h | 12 +- ir/ts/tsFunctionType.cpp | 24 +- ir/ts/tsFunctionType.h | 21 +- ir/ts/tsImportEqualsDeclaration.cpp | 7 +- ir/ts/tsImportEqualsDeclaration.h | 12 +- ir/ts/tsImportType.cpp | 9 +- ir/ts/tsImportType.h | 14 +- ir/ts/tsIndexedAccessType.cpp | 23 +- ir/ts/tsIndexedAccessType.h | 24 +- ir/ts/tsInferType.cpp | 9 +- ir/ts/tsInferType.h | 14 +- ir/ts/tsInterfaceBody.cpp | 7 +- ir/ts/tsInterfaceBody.h | 28 +- ir/ts/tsInterfaceDeclaration.cpp | 26 +- ir/ts/tsInterfaceDeclaration.h | 63 +- ir/ts/tsInterfaceHeritage.cpp | 9 +- ir/ts/tsInterfaceHeritage.h | 23 +- ir/ts/tsIntersectionType.cpp | 16 +- ir/ts/tsIntersectionType.h | 15 +- ir/ts/tsLiteralType.cpp | 21 +- ir/ts/tsLiteralType.h | 14 +- ir/ts/tsMappedType.cpp | 10 +- ir/ts/tsMappedType.h | 20 +- ir/ts/tsModuleBlock.cpp | 7 +- ir/ts/tsModuleBlock.h | 12 +- ir/ts/tsModuleDeclaration.cpp | 7 +- ir/ts/tsModuleDeclaration.h | 12 +- ir/ts/tsNamedTupleMember.cpp | 7 +- ir/ts/tsNamedTupleMember.h | 29 +- ir/ts/tsNeverKeyword.cpp | 11 +- ir/ts/tsNeverKeyword.h | 14 +- ir/ts/tsNonNullExpression.cpp | 7 +- ir/ts/tsNonNullExpression.h | 12 +- ir/ts/tsNullKeyword.cpp | 11 +- ir/ts/tsNullKeyword.h | 14 +- ir/ts/tsNumberKeyword.cpp | 11 +- ir/ts/tsNumberKeyword.h | 14 +- ir/ts/tsObjectKeyword.cpp | 11 +- ir/ts/tsObjectKeyword.h | 14 +- ir/ts/tsParameterProperty.cpp | 7 +- ir/ts/tsParameterProperty.h | 12 +- ir/ts/tsParenthesizedType.cpp | 21 +- ir/ts/tsParenthesizedType.h | 18 +- ir/ts/tsQualifiedName.cpp | 77 +- ir/ts/tsQualifiedName.h | 22 +- ir/ts/tsStringKeyword.cpp | 11 +- ir/ts/tsStringKeyword.h | 14 +- ir/ts/tsThisType.cpp | 9 +- ir/ts/tsThisType.h | 14 +- ir/ts/tsTupleType.cpp | 34 +- ir/ts/tsTupleType.h | 20 +- ir/ts/tsTypeAliasDeclaration.cpp | 16 +- ir/ts/tsTypeAliasDeclaration.h | 25 +- ir/ts/tsTypeAssertion.cpp | 12 +- ir/ts/tsTypeAssertion.h | 24 +- ir/ts/tsTypeLiteral.cpp | 21 +- ir/ts/tsTypeLiteral.h | 20 +- ir/ts/tsTypeOperator.cpp | 9 +- ir/ts/tsTypeOperator.h | 20 +- ir/ts/tsTypeParameter.cpp | 8 +- ir/ts/tsTypeParameter.h | 27 +- ir/ts/tsTypeParameterDeclaration.cpp | 7 +- ir/ts/tsTypeParameterDeclaration.h | 12 +- ir/ts/tsTypeParameterInstantiation.cpp | 9 +- ir/ts/tsTypeParameterInstantiation.h | 20 +- ir/ts/tsTypePredicate.cpp | 10 +- ir/ts/tsTypePredicate.h | 20 +- ir/ts/tsTypeQuery.cpp | 21 +- ir/ts/tsTypeQuery.h | 14 +- ir/ts/tsTypeReference.cpp | 36 +- ir/ts/tsTypeReference.h | 16 +- ir/ts/tsUndefinedKeyword.cpp | 11 +- ir/ts/tsUndefinedKeyword.h | 14 +- ir/ts/tsUnionType.cpp | 23 +- ir/ts/tsUnionType.h | 20 +- ir/ts/tsUnknownKeyword.cpp | 11 +- ir/ts/tsUnknownKeyword.h | 14 +- ir/ts/tsVoidKeyword.cpp | 11 +- ir/ts/tsVoidKeyword.h | 14 +- ir/typeNode.h | 17 +- lexer/ASLexer.cpp | 26 + lexer/ASLexer.h | 37 + lexer/ETSLexer.cpp | 199 + lexer/ETSLexer.h | 54 + lexer/TSLexer.cpp | 26 + lexer/TSLexer.h | 37 + lexer/keywordString.h | 27 +- lexer/keywords.cpp | 74 + lexer/keywordsBase.h | 70 + lexer/keywordsUtil.cpp | 23 +- lexer/keywordsUtil.h | 70 +- lexer/lexer.cpp | 453 +- lexer/lexer.h | 297 +- lexer/regexp/regexp.h | 21 +- lexer/scripts/keywords.rb | 279 +- lexer/scripts/keywords.yaml | 481 + lexer/templates/keywords.h.erb | 119 +- lexer/token/letters.h | 14 +- lexer/token/number.cpp | 55 + lexer/token/number.h | 122 + lexer/token/sourceLocation.cpp | 9 +- lexer/token/sourceLocation.h | 1 + lexer/token/token.cpp | 39 +- lexer/token/token.h | 26 +- lexer/token/tokenType.h | 19 + parser/ASparser.cpp | 1727 +++ parser/ASparser.h | 100 + parser/ETSparser.cpp | 2803 +++++ parser/ETSparser.h | 224 + parser/JSparser.cpp | 19 + parser/JSparser.h | 31 + parser/TSparser.cpp | 2982 +++++ parser/TSparser.h | 154 + parser/TypedParser.cpp | 1521 +++ parser/TypedParser.h | 160 + parser/context/classPrivateContext.cpp | 9 +- parser/context/classPrivateContext.h | 3 +- parser/context/parserContext.h | 85 +- parser/expressionParser.cpp | 924 +- parser/parserFlags.h | 54 +- parser/parserImpl.cpp | 3655 +------ parser/parserImpl.h | 643 +- parser/program/program.cpp | 62 +- parser/program/program.h | 99 +- parser/statementParser.cpp | 1180 +- test/compiler/ets/FunctionType1-expected.txt | 800 ++ test/compiler/ets/FunctionType1.ets | 10 + test/compiler/ets/FunctionType2-expected.txt | 553 + test/compiler/ets/FunctionType2.ets | 9 + test/compiler/ets/FunctionType3-expected.txt | 582 + test/compiler/ets/FunctionType3.ets | 9 + ...ctMethodDeclaredInParentClass-expected.txt | 2536 +++++ .../abstractMethodDeclaredInParentClass.ets | 43 + ...actNewClassInstanceExpression-expected.txt | 1074 ++ .../abstractNewClassInstanceExpression.ets | 19 + .../boxingUnboxingExpressions-expected.txt | 6728 ++++++++++++ .../ets/boxingUnboxingExpressions.ets | 65 + test/compiler/ets/forUpdate-expected.txt | 425 + test/compiler/ets/forUpdate.ets | 6 + .../ets/forUpdateCharType-expected.txt | 552 + test/compiler/ets/forUpdateCharType.ets | 9 + .../ets/identifierReference1-expected.txt | 1879 ++++ test/compiler/ets/identifierReference1.ets | 35 + .../ets/identifierReference10-expected.txt | 722 ++ test/compiler/ets/identifierReference10.ets | 11 + .../ets/identifierReference11-expected.txt | 547 + test/compiler/ets/identifierReference11.ets | 9 + .../ets/identifierReference12-expected.txt | 740 ++ test/compiler/ets/identifierReference12.ets | 11 + .../ets/identifierReference13-expected.txt | 797 ++ test/compiler/ets/identifierReference13.ets | 11 + .../ets/identifierReference14-expected.txt | 947 ++ test/compiler/ets/identifierReference14.ets | 20 + .../ets/identifierReference15-expected.txt | 864 ++ test/compiler/ets/identifierReference15.ets | 21 + .../ets/identifierReference16-expected.txt | 1368 +++ test/compiler/ets/identifierReference16.ets | 31 + .../ets/identifierReference2-expected.txt | 195 + test/compiler/ets/identifierReference2.ets | 1 + .../ets/identifierReference3-expected.txt | 424 + test/compiler/ets/identifierReference3.ets | 7 + .../ets/identifierReference4-expected.txt | 678 ++ test/compiler/ets/identifierReference4.ets | 11 + .../ets/identifierReference5-expected.txt | 994 ++ test/compiler/ets/identifierReference5.ets | 18 + .../ets/identifierReference6-expected.txt | 547 + test/compiler/ets/identifierReference6.ets | 10 + .../ets/identifierReference7-expected.txt | 801 ++ test/compiler/ets/identifierReference7.ets | 14 + .../ets/identifierReference8-expected.txt | 467 + test/compiler/ets/identifierReference8.ets | 11 + .../ets/identifierReference9-expected.txt | 467 + test/compiler/ets/identifierReference9.ets | 11 + .../ets/infinityNarrowing-expected.txt | 650 ++ test/compiler/ets/infinityNarrowing.ets | 3 + .../interfaceMethodNotOverridden-expected.txt | 525 + .../ets/interfaceMethodNotOverridden.ets | 9 + .../ets/invalidInheritance1-expected.txt | 572 + test/compiler/ets/invalidInheritance1.ets | 9 + .../ets/invalidInheritance2-expected.txt | 750 ++ test/compiler/ets/invalidInheritance2.ets | 12 + .../ets/invalidInheritance3-expected.txt | 556 + test/compiler/ets/invalidInheritance3.ets | 8 + .../ets/invalidPrivateAcces-expected.txt | 980 ++ .../ets/invalidPrivateAccess1-expected.txt | 749 ++ test/compiler/ets/invalidPrivateAccess1.ets | 10 + .../ets/invalidPrivateAccess2-expected.txt | 594 + test/compiler/ets/invalidPrivateAccess2.ets | 11 + .../ets/invalidPrivateAccess3-expected.txt | 999 ++ test/compiler/ets/invalidPrivateAccess3.ets | 21 + .../ets/invalidPrivateAccess4-expected.txt | 522 + test/compiler/ets/invalidPrivateAccess4.ets | 9 + .../ets/invalidPrivateAccess5-expected.txt | 981 ++ test/compiler/ets/invalidPrivateAccess5.ets | 13 + .../ets/invalidPrivateAccess6-expected.txt | 1538 +++ test/compiler/ets/invalidPrivateAccess6.ets | 24 + ...odOverrideCovariantReturnType-expected.txt | 1922 ++++ .../ets/methodOverrideCovariantReturnType.ets | 31 + ...hodOverrideDifferentSignature-expected.txt | 1268 +++ .../ets/methodOverrideDifferentSignature.ets | 23 + ...methodOverrideWithoutModifier-expected.txt | 587 + .../ets/methodOverrideWithoutModifier.ets | 11 + .../ets/multipleMethodOverride-expected.txt | 1047 ++ test/compiler/ets/multipleMethodOverride.ets | 22 + .../compiler/ets/native_toplevel-expected.txt | 237 + test/compiler/ets/native_toplevel.ets | 1 + ...overrideModifierNotOverriding-expected.txt | 632 ++ .../ets/overrideModifierNotOverriding.ets | 11 + .../ets/privateMethodOverride-expected.txt | 587 + test/compiler/ets/privateMethodOverride.ets | 9 + ...staticInitializerInInnerClass-expected.txt | 686 ++ .../ets/staticInitializerInInnerClass.ets | 18 + ...perReferenceFromStaticContext-expected.txt | 593 + .../ets/superReferenceFromStaticContext.ets | 9 + ...tchStatementCorrectConversion-expected.txt | 906 ++ .../ets/switchStatementCorrectConversion.ets | 26 + .../switchStatementWrongBoxing-expected.txt | 576 + .../ets/switchStatementWrongBoxing.ets | 13 + ...hisReferenceFromStaticContext-expected.txt | 416 + .../ets/thisReferenceFromStaticContext.ets | 7 + ...VarReferenceFromStaticContext-expected.txt | 564 + .../ets/typeVarReferenceFromStaticContext.ets | 5 + .../voidTypeInBinaryOperation-expected.txt | 347 + .../ets/voidTypeInBinaryOperation.ets | 6 + .../parser/ets/AccessBinaryTrees-expected.txt | 4492 ++++++++ test/parser/ets/AccessBinaryTrees.ets | 81 + test/parser/ets/AccessFannkuch-expected.txt | 4831 ++++++++ test/parser/ets/AccessFannkuch.ets | 93 + test/parser/ets/AccessNBody-expected.txt | 1 + test/parser/ets/AccessNBody.ets | 221 + test/parser/ets/AccessNSieve-expected.txt | 2688 +++++ test/parser/ets/AccessNSieve.ets | 57 + .../ets/Bitops3BitBitsInByte-expected.txt | 2132 ++++ test/parser/ets/Bitops3BitBitsInByte.ets | 46 + test/parser/ets/BitopsBitsInByte-expected.txt | 1906 ++++ test/parser/ets/BitopsBitsInByte.ets | 49 + test/parser/ets/BitopsBitwiseAnd-expected.txt | 1062 ++ test/parser/ets/BitopsBitwiseAnd.ets | 34 + test/parser/ets/BitopsNSieveBits-expected.txt | 3308 ++++++ test/parser/ets/BitopsNSieveBits.ets | 61 + test/parser/ets/Boolean_bitwise-expected.txt | 494 + test/parser/ets/Boolean_bitwise.ets | 20 + .../ets/ControlFlowRecursive-expected.txt | 3247 ++++++ test/parser/ets/ControlFlowRecursive.ets | 61 + test/parser/ets/FunctionType-expected.txt | 706 ++ test/parser/ets/FunctionType.ets | 25 + test/parser/ets/MathCordic-expected.txt | 1 + test/parser/ets/MathCordic.ets | 91 + test/parser/ets/MathPartialSums-expected.txt | 4865 +++++++++ test/parser/ets/MathPartialSums.ets | 90 + test/parser/ets/MathSpectralNorm-expected.txt | 5643 ++++++++++ test/parser/ets/MathSpectralNorm.ets | 94 + test/parser/ets/Morph3d-expected.txt | 3395 ++++++ test/parser/ets/Morph3d.ets | 62 + test/parser/ets/StringBase64-expected.txt | 1 + test/parser/ets/StringBase64.ets | 124 + test/parser/ets/StringFasta-expected.txt | 9684 +++++++++++++++++ test/parser/ets/StringFasta.ets | 145 + test/parser/ets/anonymous_class-expected.txt | 569 + test/parser/ets/anonymous_class.ets | 21 + test/parser/ets/array-expected.txt | 657 ++ test/parser/ets/array.ets | 23 + test/parser/ets/array_type-expected.txt | 944 ++ test/parser/ets/array_type.ets | 28 + test/parser/ets/assert-expected.txt | 840 ++ test/parser/ets/assert.ets | 26 + test/parser/ets/assign-expected.txt | 324 + test/parser/ets/assign.ets | 21 + test/parser/ets/assign_bad-expected.txt | 1 + test/parser/ets/assign_bad.ets | 21 + test/parser/ets/assignments-expected.txt | 1410 +++ test/parser/ets/assignments.ets | 39 + test/parser/ets/binary_op-expected.txt | 2055 ++++ test/parser/ets/binary_op.ets | 42 + .../parser/ets/binary_operations-expected.txt | 2911 +++++ test/parser/ets/binary_operations.ets | 44 + test/parser/ets/blocks-expected.txt | 1 + test/parser/ets/blocks.ets | 24 + test/parser/ets/blocks_scopes-expected.txt | 1 + test/parser/ets/blocks_scopes.ets | 26 + test/parser/ets/boolean-expected.txt | 172 + test/parser/ets/boolean.ets | 17 + test/parser/ets/boolean_cond-expected.txt | 279 + test/parser/ets/boolean_cond.ets | 23 + test/parser/ets/boolean_default-expected.txt | 225 + test/parser/ets/boolean_default.ets | 21 + test/parser/ets/break-expected.txt | 1 + test/parser/ets/break.ets | 21 + .../calling_superclass_methods-expected.txt | 1 + .../parser/ets/calling_superclass_methods.ets | 26 + test/parser/ets/calls-expected.txt | 672 ++ test/parser/ets/calls.ets | 27 + test/parser/ets/cast_expressions-expected.txt | 344 + test/parser/ets/cast_expressions.ets | 20 + test/parser/ets/class_init-expected.txt | 401 + test/parser/ets/class_init.ets | 22 + test/parser/ets/class_instance-expected.txt | 467 + test/parser/ets/class_instance.ets | 21 + .../ets/class_instance_creation-expected.txt | 1079 ++ test/parser/ets/class_instance_creation.ets | 32 + .../class_instance_initializer-expected.txt | 2580 +++++ .../parser/ets/class_instance_initializer.ets | 68 + .../ets/class_property_access-expected.txt | 725 ++ test/parser/ets/class_property_access.ets | 26 + .../ets/class_static_initializer-expected.txt | 758 ++ test/parser/ets/class_static_initializer.ets | 29 + test/parser/ets/classes-expected.txt | 646 ++ test/parser/ets/classes.ets | 26 + test/parser/ets/comment_block-expected.txt | 58 + test/parser/ets/comment_block.ets | 34 + test/parser/ets/comment_line-expected.txt | 58 + test/parser/ets/comment_line.ets | 16 + test/parser/ets/const-expected.txt | 200 + test/parser/ets/const.ets | 17 + test/parser/ets/const_enum-expected.txt | 1 + test/parser/ets/const_enum.ets | 16 + test/parser/ets/constructor_test-expected.txt | 1141 ++ test/parser/ets/constructor_test.ets | 41 + test/parser/ets/constructors-expected.txt | 1176 ++ test/parser/ets/constructors.ets | 35 + test/parser/ets/continue-expected.txt | 1 + test/parser/ets/continue.ets | 21 + test/parser/ets/decl_infer-expected.txt | 559 + test/parser/ets/decl_infer.ets | 26 + test/parser/ets/defer-plus-expected.txt | 920 ++ test/parser/ets/defer-plus.ets | 32 + test/parser/ets/empty_class-expected.txt | 335 + test/parser/ets/empty_class.ets | 20 + test/parser/ets/empty_statement-expected.txt | 925 ++ test/parser/ets/empty_statement.ets | 34 + test/parser/ets/enum-expected.txt | 561 + test/parser/ets/enum.ets | 18 + .../ets/enum_with_class_behavior-expected.txt | 1239 +++ test/parser/ets/enum_with_class_behavior.ets | 37 + test/parser/ets/exports-expected.txt | 698 ++ test/parser/ets/exports.ets | 22 + test/parser/ets/field_decl-expected.txt | 846 ++ test/parser/ets/field_decl.ets | 29 + test/parser/ets/fields-expected.txt | 1 + test/parser/ets/fields.ets | 28 + .../parser/ets/final_empty_class-expected.txt | 335 + test/parser/ets/final_empty_class.ets | 20 + test/parser/ets/for_of-expected.txt | 1 + test/parser/ets/for_of.ets | 29 + test/parser/ets/for_with_break-expected.txt | 639 ++ test/parser/ets/for_with_break.ets | 26 + test/parser/ets/function-expected.txt | 1 + test/parser/ets/function.ets | 36 + test/parser/ets/function_decl-expected.txt | 278 + test/parser/ets/function_decl.ets | 16 + test/parser/ets/generic_function-expected.txt | 1 + test/parser/ets/generic_function.ets | 24 + test/parser/ets/generics_1-expected.txt | 1226 +++ test/parser/ets/generics_1.ets | 32 + test/parser/ets/identifier-expected.txt | 248 + test/parser/ets/identifier.ets | 20 + test/parser/ets/if-expected.txt | 2827 +++++ test/parser/ets/if.ets | 73 + test/parser/ets/ifs-expected.txt | 480 + test/parser/ets/ifs.ets | 26 + .../parser/ets/index_expressions-expected.txt | 407 + test/parser/ets/index_expressions.ets | 21 + test/parser/ets/inheritance-expected.txt | 1293 +++ test/parser/ets/inheritance.ets | 38 + test/parser/ets/instanceof-expected.txt | 365 + test/parser/ets/instanceof.ets | 22 + test/parser/ets/interface-expected.txt | 283 + test/parser/ets/interface.ets | 18 + test/parser/ets/interfaces-expected.txt | 671 ++ test/parser/ets/interfaces.ets | 27 + test/parser/ets/labeled-expected.txt | 883 ++ test/parser/ets/labeled.ets | 27 + test/parser/ets/lexer001-expected.txt | 1 + test/parser/ets/lexer001.ets | 16 + test/parser/ets/lexer002-expected.txt | 1 + test/parser/ets/lexer002.ets | 17 + test/parser/ets/literals-expected.txt | 1054 ++ test/parser/ets/literals.ets | 34 + .../ets/localClassIsPermitted-expected.txt | 1 + test/parser/ets/localClassIsPermitted.ets | 22 + test/parser/ets/loops-expected.txt | 2415 ++++ test/parser/ets/loops.ets | 65 + test/parser/ets/method_empty-expected.txt | 715 ++ test/parser/ets/method_empty.ets | 26 + test/parser/ets/method_full-expected.txt | 1434 +++ test/parser/ets/method_full.ets | 34 + test/parser/ets/methods-expected.txt | 1972 ++++ test/parser/ets/methods.ets | 41 + test/parser/ets/named_types-expected.txt | 1340 +++ test/parser/ets/named_types.ets | 34 + test/parser/ets/new_expressions-expected.txt | 404 + test/parser/ets/new_expressions.ets | 26 + test/parser/ets/null-expected.txt | 2304 ++++ test/parser/ets/null.ets | 48 + test/parser/ets/null_invalid-expected.txt | 110 + test/parser/ets/null_invalid.ets | 16 + test/parser/ets/object-expected.txt | 136 + test/parser/ets/object.ets | 16 + test/parser/ets/override_method-expected.txt | 643 ++ test/parser/ets/override_method.ets | 26 + test/parser/ets/panic-if-expected.txt | 1 + test/parser/ets/panic-if.ets | 20 + test/parser/ets/panic-statement-expected.txt | 318 + test/parser/ets/panic-statement.ets | 22 + .../parentheses_expression_value-expected.txt | 614 ++ .../ets/parentheses_expression_value.ets | 25 + ...redefined_non_primitive_types-expected.txt | 1 + .../ets/predefined_non_primitive_types.ets | 37 + test/parser/ets/predefined_types-expected.txt | 402 + test/parser/ets/predefined_types.ets | 26 + ...egression-target-type-context-expected.txt | 2034 ++++ .../ets/regression-target-type-context.ets | 42 + test/parser/ets/return-expected.txt | 1 + test/parser/ets/return.ets | 21 + test/parser/ets/scoped_decl-expected.txt | 356 + test/parser/ets/scoped_decl.ets | 21 + test/parser/ets/simple_types-expected.txt | 706 ++ test/parser/ets/simple_types.ets | 29 + .../ets/special_signatures-expected.txt | 1 + test/parser/ets/special_signatures.ets | 19 + test/parser/ets/string-expected.txt | 150 + test/parser/ets/string.ets | 16 + test/parser/ets/switch-expected.txt | 680 ++ test/parser/ets/switch.ets | 31 + test/parser/ets/switch2-expected.txt | 652 ++ test/parser/ets/switch2.ets | 31 + test/parser/ets/ternary-expected.txt | 282 + test/parser/ets/ternary.ets | 19 + test/parser/ets/test_enum-expected.txt | 2481 +++++ test/parser/ets/test_enum.ets | 55 + test/parser/ets/test_interface-expected.txt | 1101 ++ test/parser/ets/test_interface.ets | 29 + test/parser/ets/this_callee-expected.txt | 1065 ++ test/parser/ets/this_callee.ets | 32 + test/parser/ets/this_cmp_object-expected.txt | 552 + test/parser/ets/this_cmp_object.ets | 21 + .../ets/topLevelStaticClass-expected.txt | 1 + test/parser/ets/topLevelStaticClass.ets | 18 + test/parser/ets/trap-expected.txt | 1 + .../ets/trap-missing-catch-expected.txt | 1 + test/parser/ets/trap-missing-catch.ets | 21 + test/parser/ets/trap.ets | 25 + test/parser/ets/type_cast-expected.txt | 794 ++ test/parser/ets/type_cast.ets | 26 + test/parser/ets/type_references-expected.txt | 1 + test/parser/ets/type_references.ets | 19 + test/parser/ets/types_decls-expected.txt | 1 + test/parser/ets/types_decls.ets | 57 + test/parser/ets/unary_op-expected.txt | 554 + test/parser/ets/unary_op.ets | 23 + test/parser/ets/unary_operations-expected.txt | 1093 ++ test/parser/ets/unary_operations.ets | 30 + test/parser/ets/var_declare-expected.txt | 883 ++ test/parser/ets/var_declare.ets | 28 + test/parser/ets/void-expected.txt | 181 + test/parser/ets/void.ets | 18 + .../js/test-class-async-method-expected.txt | 5 +- .../js/test-class-definition-expected.txt | 2 - .../js/test-class-expression-expected.txt | 10 +- .../js/test-class-static-block-expected.txt | 10 +- .../js/test-class-static-block6-expected.txt | 2 +- .../js/test-function-decl-1-expected.txt | 587 + test/parser/js/test-function-decl-1.js | 31 + .../js/test-function-decl-2-expected.txt | 87 + test/parser/js/test-function-decl-2.js | 16 + .../js/test-member-expression-1-expected.txt | 2 +- .../parser/js/test-private-field-expected.txt | 10 +- test/parser/js/this-expression-expected.txt | 2 +- test/runtime/ets/AccessBinaryTrees.ets | 82 + test/runtime/ets/AccessFannkuch.ets | 93 + test/runtime/ets/AccessNBody.ets | 159 + test/runtime/ets/AccessNSieve.ets | 63 + test/runtime/ets/Bitops3BitBitsInByte.ets | 44 + test/runtime/ets/BitopsBitsInByte.ets | 49 + test/runtime/ets/BitopsBitwiseAnd.ets | 35 + test/runtime/ets/BitopsNSieveBits.ets | 63 + test/runtime/ets/ClassNewInstance.ets | 36 + test/runtime/ets/ControlFlowRecursive.ets | 61 + test/runtime/ets/FunctionType.ets | 46 + test/runtime/ets/MathCordic.ets | 82 + test/runtime/ets/MathPartialSums.ets | 88 + test/runtime/ets/MathSpectralNorm.ets | 94 + test/runtime/ets/Morph3d.ets | 63 + test/runtime/ets/StringBase64.ets | 92 + test/runtime/ets/StringFasta.ets | 123 + test/runtime/ets/array-expression.ets | 10 + test/runtime/ets/cast.ets | 103 + test/runtime/ets/char-type.ets | 52 + test/runtime/ets/class-init.ets | 50 + test/runtime/ets/class-init2.ets | 32 + test/runtime/ets/count.ets | 21 + test/runtime/ets/date-now.ets | 8 + test/runtime/ets/generics_1.ets | 41 + test/runtime/ets/instanceof.ets | 22 + test/runtime/ets/skippedTest.ets | 58 + test/runtime/ets/string-builder.ets | 30 + test/runtime/ets/unboxing.ets | 30 + typescript/checker.cpp | 95 - typescript/types/typeMapping.h | 53 - util/enumbitops.h | 102 +- util/helpers.cpp | 130 +- util/helpers.h | 30 +- util/ustring.cpp | 1 + util/ustring.h | 27 +- 967 files changed, 204991 insertions(+), 11224 deletions(-) create mode 100644 .gitignore create mode 100644 binder/ASBinder.cpp create mode 100644 binder/ASBinder.h create mode 100644 binder/ETSBinder.cpp create mode 100644 binder/ETSBinder.h create mode 100644 binder/JSBinder.cpp create mode 100644 binder/JSBinder.h create mode 100644 binder/TSBinder.cpp create mode 100644 binder/TSBinder.h create mode 100644 binder/TypedBinder.cpp create mode 100644 binder/TypedBinder.h create mode 100644 binder/recordTable.cpp create mode 100644 binder/recordTable.h create mode 100644 checker/ASchecker.cpp create mode 100644 checker/ASchecker.h create mode 100644 checker/ETSchecker.cpp create mode 100644 checker/ETSchecker.h create mode 100644 checker/JSchecker.cpp rename typescript/core/checkerContext.h => checker/JSchecker.h (48%) create mode 100644 checker/TSchecker.cpp rename typescript/checker.h => checker/TSchecker.h (45%) rename typescript/core/typeRelation.cpp => checker/checker.cpp (55%) create mode 100644 checker/checker.h rename {typescript/core => checker}/checkerContext.cpp (100%) create mode 100644 checker/checkerContext.h create mode 100644 checker/ets/aliveAnalyzer.cpp create mode 100644 checker/ets/aliveAnalyzer.h create mode 100644 checker/ets/arithmetic.cpp create mode 100644 checker/ets/arithmetic.h create mode 100644 checker/ets/baseAnalyzer.cpp create mode 100644 checker/ets/baseAnalyzer.h create mode 100644 checker/ets/boxingConverter.cpp create mode 100644 checker/ets/boxingConverter.h create mode 100644 checker/ets/function.cpp create mode 100644 checker/ets/helpers.cpp create mode 100644 checker/ets/narrowingConverter.cpp create mode 100644 checker/ets/narrowingConverter.h create mode 100644 checker/ets/narrowingWideningConverter.cpp create mode 100644 checker/ets/narrowingWideningConverter.h create mode 100644 checker/ets/object.cpp create mode 100644 checker/ets/primitiveWrappers.cpp create mode 100644 checker/ets/primitiveWrappers.h create mode 100644 checker/ets/typeConverter.cpp create mode 100644 checker/ets/typeConverter.h create mode 100644 checker/ets/typeCreation.cpp create mode 100644 checker/ets/typeRelationContext.cpp create mode 100644 checker/ets/typeRelationContext.h create mode 100644 checker/ets/unboxingConverter.cpp create mode 100644 checker/ets/unboxingConverter.h create mode 100644 checker/ets/wideningConverter.cpp create mode 100644 checker/ets/wideningConverter.h rename {typescript/core => checker/ts}/binaryLikeExpression.cpp (85%) rename {typescript/core => checker/ts}/destructuringContext.cpp (95%) rename {typescript/core => checker/ts}/destructuringContext.h (64%) rename {typescript/core => checker/ts}/function.cpp (76%) rename {typescript/core => checker/ts}/helpers.cpp (72%) rename {typescript/core => checker/ts}/object.cpp (78%) rename {typescript/core => checker/ts}/typeCreation.cpp (45%) rename {typescript/core => checker/ts}/typeElaborationContext.cpp (94%) rename {typescript/core => checker/ts}/typeElaborationContext.h (76%) rename {typescript/core => checker/ts}/util.cpp (76%) create mode 100644 checker/types/ets/byteType.cpp create mode 100644 checker/types/ets/byteType.h create mode 100644 checker/types/ets/charType.cpp create mode 100644 checker/types/ets/charType.h create mode 100644 checker/types/ets/doubleType.cpp create mode 100644 checker/types/ets/doubleType.h create mode 100644 checker/types/ets/etsArrayType.cpp create mode 100644 checker/types/ets/etsArrayType.h create mode 100644 checker/types/ets/etsBooleanType.cpp create mode 100644 checker/types/ets/etsBooleanType.h create mode 100644 checker/types/ets/etsFunctionType.cpp create mode 100644 checker/types/ets/etsFunctionType.h create mode 100644 checker/types/ets/etsObjectType.cpp create mode 100644 checker/types/ets/etsObjectType.h create mode 100644 checker/types/ets/etsStringType.cpp create mode 100644 checker/types/ets/etsStringType.h create mode 100644 checker/types/ets/etsTypeParameter.cpp create mode 100644 checker/types/ets/etsTypeParameter.h create mode 100644 checker/types/ets/etsTypeReference.cpp create mode 100644 checker/types/ets/etsTypeReference.h create mode 100644 checker/types/ets/etsVoidType.cpp rename lexer/templates/keywordsMap.h.erb => checker/types/ets/etsVoidType.h (42%) create mode 100644 checker/types/ets/floatType.cpp create mode 100644 checker/types/ets/floatType.h create mode 100644 checker/types/ets/intType.cpp create mode 100644 checker/types/ets/intType.h create mode 100644 checker/types/ets/longType.cpp create mode 100644 checker/types/ets/longType.h create mode 100644 checker/types/ets/shortType.cpp create mode 100644 checker/types/ets/shortType.h create mode 100644 checker/types/ets/types.h create mode 100644 checker/types/ets/wildcardType.cpp create mode 100644 checker/types/ets/wildcardType.h rename {typescript => checker}/types/globalTypesHolder.cpp (32%) rename {typescript => checker}/types/globalTypesHolder.h (35%) rename {typescript => checker}/types/signature.cpp (81%) rename {typescript => checker}/types/signature.h (57%) rename {typescript/types => checker/types/ts}/anyType.cpp (100%) rename {typescript/types => checker/types/ts}/anyType.h (87%) rename {typescript/types => checker/types/ts}/arrayType.cpp (96%) rename {typescript/types => checker/types/ts}/arrayType.h (89%) rename {typescript/types => checker/types/ts}/bigintLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/bigintLiteralType.h (89%) rename {typescript/types => checker/types/ts}/bigintType.cpp (100%) rename {typescript/types => checker/types/ts}/bigintType.h (87%) rename {typescript/types => checker/types/ts}/booleanLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/booleanLiteralType.h (88%) rename {typescript/types => checker/types/ts}/booleanType.cpp (100%) rename {typescript/types => checker/types/ts}/booleanType.h (87%) rename {typescript/types => checker/types/ts}/constructorType.cpp (95%) rename {typescript/types => checker/types/ts}/constructorType.h (90%) rename {typescript/types => checker/types/ts}/elementFlags.h (79%) rename {typescript/types => checker/types/ts}/enumLiteralType.cpp (96%) rename {typescript/types => checker/types/ts}/enumLiteralType.h (90%) rename {typescript/types => checker/types/ts}/enumType.cpp (100%) rename {typescript/types => checker/types/ts}/enumType.h (90%) rename {typescript/types => checker/types/ts}/functionType.cpp (96%) rename {typescript/types => checker/types/ts}/functionType.h (90%) rename {typescript/types => checker/types/ts}/indexInfo.cpp (100%) rename {typescript/types => checker/types/ts}/indexInfo.h (92%) rename {typescript/types => checker/types/ts}/interfaceType.cpp (98%) rename {typescript/types => checker/types/ts}/interfaceType.h (97%) rename {typescript/types => checker/types/ts}/neverType.cpp (100%) rename {typescript/types => checker/types/ts}/neverType.h (87%) rename {typescript/types => checker/types/ts}/nonPrimitiveType.cpp (100%) rename {typescript/types => checker/types/ts}/nonPrimitiveType.h (86%) rename {typescript/types => checker/types/ts}/nullType.cpp (100%) rename {typescript/types => checker/types/ts}/nullType.h (88%) rename {typescript/types => checker/types/ts}/numberLiteralType.cpp (96%) rename {typescript/types => checker/types/ts}/numberLiteralType.h (88%) rename {typescript/types => checker/types/ts}/numberType.cpp (96%) rename {typescript/types => checker/types/ts}/numberType.h (87%) rename {typescript/types => checker/types/ts}/objectDescriptor.cpp (93%) rename {typescript/types => checker/types/ts}/objectDescriptor.h (93%) rename {typescript/types => checker/types/ts}/objectLiteralType.cpp (94%) rename {typescript/types => checker/types/ts}/objectLiteralType.h (90%) rename {typescript/types => checker/types/ts}/objectType.cpp (97%) rename {typescript/types => checker/types/ts}/objectType.h (89%) rename {typescript/types => checker/types/ts}/stringLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/stringLiteralType.h (88%) rename {typescript/types => checker/types/ts}/stringType.cpp (100%) rename {typescript/types => checker/types/ts}/stringType.h (87%) rename {typescript/types => checker/types/ts}/tupleType.cpp (97%) rename {typescript/types => checker/types/ts}/tupleType.h (92%) rename {typescript/types => checker/types/ts}/typeParameter.cpp (100%) rename {typescript/types => checker/types/ts}/typeParameter.h (90%) rename {typescript/types => checker/types/ts}/typeReference.cpp (100%) rename {typescript/types => checker/types/ts}/typeReference.h (84%) rename {typescript/types => checker/types/ts}/types.h (89%) rename {typescript/types => checker/types/ts}/undefinedType.cpp (100%) rename {typescript/types => checker/types/ts}/undefinedType.h (87%) rename {typescript/types => checker/types/ts}/unionType.cpp (98%) rename {typescript/types => checker/types/ts}/unionType.h (96%) rename {typescript/types => checker/types/ts}/unknownType.cpp (100%) rename {typescript/types => checker/types/ts}/unknownType.h (87%) rename {typescript/types => checker/types/ts}/voidType.cpp (100%) rename {typescript/types => checker/types/ts}/voidType.h (87%) rename {typescript => checker}/types/type.cpp (63%) rename {typescript => checker}/types/type.h (72%) rename {typescript => checker}/types/typeFacts.h (75%) rename {typescript => checker}/types/typeFlag.h (33%) create mode 100644 checker/types/typeMapping.h rename {typescript => checker}/types/typeRelation.cpp (84%) rename {typescript => checker}/types/typeRelation.h (44%) create mode 100644 compiler/core/ETSGen.cpp create mode 100644 compiler/core/ETSGen.h create mode 100644 compiler/core/ETSemitter.cpp create mode 100644 compiler/core/ETSemitter.h create mode 100644 compiler/core/ETSfunction.cpp create mode 100644 compiler/core/ETSfunction.h create mode 100644 compiler/core/JSemitter.cpp create mode 100644 compiler/core/JSemitter.h create mode 100644 compiler/core/codeGen.cpp create mode 100644 compiler/core/codeGen.h create mode 100644 compiler/core/compileJob.cpp create mode 100644 compiler/core/compileJob.h create mode 100644 compiler/core/programElement.cpp create mode 100644 compiler/core/programElement.h create mode 100644 compiler/core/regSpiller.cpp create mode 100644 compiler/core/regSpiller.h rename compiler/core/{inlineCache.cpp => targetTypeContext.cpp} (62%) create mode 100644 compiler/core/targetTypeContext.h rename compiler/core/{inlineCache.h => vReg.cpp} (65%) create mode 100644 compiler/core/vReg.h create mode 100644 compiler/scripts/signatures.rb create mode 100644 compiler/scripts/signatures.yaml create mode 100644 compiler/templates/signatures.h.erb create mode 100644 ir/astNode.cpp rename ir/{ts => base}/tsIndexSignature.cpp (87%) rename ir/{ts => base}/tsIndexSignature.h (66%) rename ir/{ts => base}/tsMethodSignature.cpp (90%) rename ir/{ts => base}/tsMethodSignature.h (76%) rename ir/{ts => base}/tsPropertySignature.cpp (74%) rename ir/{ts => base}/tsPropertySignature.h (64%) rename ir/{ts => base}/tsSignatureDeclaration.cpp (89%) rename ir/{ts => base}/tsSignatureDeclaration.h (74%) create mode 100644 ir/ets/etsClassLiteral.cpp create mode 100644 ir/ets/etsClassLiteral.h create mode 100644 ir/ets/etsFunctionType.cpp create mode 100644 ir/ets/etsFunctionType.h create mode 100644 ir/ets/etsMethodReferenceExpression.cpp create mode 100644 ir/ets/etsMethodReferenceExpression.h create mode 100644 ir/ets/etsNewArrayInstanceExpression.cpp create mode 100644 ir/ets/etsNewArrayInstanceExpression.h create mode 100644 ir/ets/etsNewClassInstanceExpression.cpp create mode 100644 ir/ets/etsNewClassInstanceExpression.h create mode 100644 ir/ets/etsNewMultiDimArrayInstanceExpression.cpp create mode 100644 ir/ets/etsNewMultiDimArrayInstanceExpression.h create mode 100644 ir/ets/etsPackageDeclaration.cpp create mode 100644 ir/ets/etsPackageDeclaration.h create mode 100644 ir/ets/etsPrimitiveType.cpp create mode 100644 ir/ets/etsPrimitiveType.h create mode 100644 ir/ets/etsScript.cpp create mode 100644 ir/ets/etsScript.h create mode 100644 ir/ets/etsTryExpression.cpp create mode 100644 ir/ets/etsTryExpression.h create mode 100644 ir/ets/etsTypeReference.cpp create mode 100644 ir/ets/etsTypeReference.h create mode 100644 ir/ets/etsTypeReferencePart.cpp create mode 100644 ir/ets/etsTypeReferencePart.h create mode 100644 ir/ets/etsWildcardType.cpp create mode 100644 ir/ets/etsWildcardType.h create mode 100644 ir/expressions/literals/charLiteral.cpp create mode 100644 ir/expressions/literals/charLiteral.h create mode 100644 ir/statements/assertStatement.cpp create mode 100644 ir/statements/assertStatement.h create mode 100644 ir/statements/deferStatement.cpp create mode 100644 ir/statements/deferStatement.h create mode 100644 ir/statements/panicStatement.cpp create mode 100644 ir/statements/panicStatement.h create mode 100644 ir/statements/trapStatement.cpp create mode 100644 ir/statements/trapStatement.h create mode 100644 lexer/ASLexer.cpp create mode 100644 lexer/ASLexer.h create mode 100644 lexer/ETSLexer.cpp create mode 100644 lexer/ETSLexer.h create mode 100644 lexer/TSLexer.cpp create mode 100644 lexer/TSLexer.h create mode 100644 lexer/keywords.cpp create mode 100644 lexer/keywordsBase.h create mode 100644 lexer/scripts/keywords.yaml create mode 100644 lexer/token/number.cpp create mode 100644 lexer/token/number.h create mode 100644 parser/ASparser.cpp create mode 100644 parser/ASparser.h create mode 100644 parser/ETSparser.cpp create mode 100644 parser/ETSparser.h create mode 100644 parser/JSparser.cpp create mode 100644 parser/JSparser.h create mode 100644 parser/TSparser.cpp create mode 100644 parser/TSparser.h create mode 100644 parser/TypedParser.cpp create mode 100644 parser/TypedParser.h create mode 100644 test/compiler/ets/FunctionType1-expected.txt create mode 100644 test/compiler/ets/FunctionType1.ets create mode 100644 test/compiler/ets/FunctionType2-expected.txt create mode 100644 test/compiler/ets/FunctionType2.ets create mode 100644 test/compiler/ets/FunctionType3-expected.txt create mode 100644 test/compiler/ets/FunctionType3.ets create mode 100644 test/compiler/ets/abstractMethodDeclaredInParentClass-expected.txt create mode 100644 test/compiler/ets/abstractMethodDeclaredInParentClass.ets create mode 100644 test/compiler/ets/abstractNewClassInstanceExpression-expected.txt create mode 100644 test/compiler/ets/abstractNewClassInstanceExpression.ets create mode 100644 test/compiler/ets/boxingUnboxingExpressions-expected.txt create mode 100644 test/compiler/ets/boxingUnboxingExpressions.ets create mode 100644 test/compiler/ets/forUpdate-expected.txt create mode 100644 test/compiler/ets/forUpdate.ets create mode 100644 test/compiler/ets/forUpdateCharType-expected.txt create mode 100644 test/compiler/ets/forUpdateCharType.ets create mode 100644 test/compiler/ets/identifierReference1-expected.txt create mode 100644 test/compiler/ets/identifierReference1.ets create mode 100644 test/compiler/ets/identifierReference10-expected.txt create mode 100644 test/compiler/ets/identifierReference10.ets create mode 100644 test/compiler/ets/identifierReference11-expected.txt create mode 100644 test/compiler/ets/identifierReference11.ets create mode 100644 test/compiler/ets/identifierReference12-expected.txt create mode 100644 test/compiler/ets/identifierReference12.ets create mode 100644 test/compiler/ets/identifierReference13-expected.txt create mode 100644 test/compiler/ets/identifierReference13.ets create mode 100644 test/compiler/ets/identifierReference14-expected.txt create mode 100644 test/compiler/ets/identifierReference14.ets create mode 100644 test/compiler/ets/identifierReference15-expected.txt create mode 100644 test/compiler/ets/identifierReference15.ets create mode 100644 test/compiler/ets/identifierReference16-expected.txt create mode 100644 test/compiler/ets/identifierReference16.ets create mode 100644 test/compiler/ets/identifierReference2-expected.txt create mode 100644 test/compiler/ets/identifierReference2.ets create mode 100644 test/compiler/ets/identifierReference3-expected.txt create mode 100644 test/compiler/ets/identifierReference3.ets create mode 100644 test/compiler/ets/identifierReference4-expected.txt create mode 100644 test/compiler/ets/identifierReference4.ets create mode 100644 test/compiler/ets/identifierReference5-expected.txt create mode 100644 test/compiler/ets/identifierReference5.ets create mode 100644 test/compiler/ets/identifierReference6-expected.txt create mode 100644 test/compiler/ets/identifierReference6.ets create mode 100644 test/compiler/ets/identifierReference7-expected.txt create mode 100644 test/compiler/ets/identifierReference7.ets create mode 100644 test/compiler/ets/identifierReference8-expected.txt create mode 100644 test/compiler/ets/identifierReference8.ets create mode 100644 test/compiler/ets/identifierReference9-expected.txt create mode 100644 test/compiler/ets/identifierReference9.ets create mode 100644 test/compiler/ets/infinityNarrowing-expected.txt create mode 100644 test/compiler/ets/infinityNarrowing.ets create mode 100644 test/compiler/ets/interfaceMethodNotOverridden-expected.txt create mode 100644 test/compiler/ets/interfaceMethodNotOverridden.ets create mode 100644 test/compiler/ets/invalidInheritance1-expected.txt create mode 100644 test/compiler/ets/invalidInheritance1.ets create mode 100644 test/compiler/ets/invalidInheritance2-expected.txt create mode 100644 test/compiler/ets/invalidInheritance2.ets create mode 100644 test/compiler/ets/invalidInheritance3-expected.txt create mode 100644 test/compiler/ets/invalidInheritance3.ets create mode 100644 test/compiler/ets/invalidPrivateAcces-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess1-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess1.ets create mode 100644 test/compiler/ets/invalidPrivateAccess2-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess2.ets create mode 100644 test/compiler/ets/invalidPrivateAccess3-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess3.ets create mode 100644 test/compiler/ets/invalidPrivateAccess4-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess4.ets create mode 100644 test/compiler/ets/invalidPrivateAccess5-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess5.ets create mode 100644 test/compiler/ets/invalidPrivateAccess6-expected.txt create mode 100644 test/compiler/ets/invalidPrivateAccess6.ets create mode 100644 test/compiler/ets/methodOverrideCovariantReturnType-expected.txt create mode 100644 test/compiler/ets/methodOverrideCovariantReturnType.ets create mode 100644 test/compiler/ets/methodOverrideDifferentSignature-expected.txt create mode 100644 test/compiler/ets/methodOverrideDifferentSignature.ets create mode 100644 test/compiler/ets/methodOverrideWithoutModifier-expected.txt create mode 100644 test/compiler/ets/methodOverrideWithoutModifier.ets create mode 100644 test/compiler/ets/multipleMethodOverride-expected.txt create mode 100644 test/compiler/ets/multipleMethodOverride.ets create mode 100644 test/compiler/ets/native_toplevel-expected.txt create mode 100644 test/compiler/ets/native_toplevel.ets create mode 100644 test/compiler/ets/overrideModifierNotOverriding-expected.txt create mode 100644 test/compiler/ets/overrideModifierNotOverriding.ets create mode 100644 test/compiler/ets/privateMethodOverride-expected.txt create mode 100644 test/compiler/ets/privateMethodOverride.ets create mode 100644 test/compiler/ets/staticInitializerInInnerClass-expected.txt create mode 100644 test/compiler/ets/staticInitializerInInnerClass.ets create mode 100644 test/compiler/ets/superReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/ets/superReferenceFromStaticContext.ets create mode 100644 test/compiler/ets/switchStatementCorrectConversion-expected.txt create mode 100644 test/compiler/ets/switchStatementCorrectConversion.ets create mode 100644 test/compiler/ets/switchStatementWrongBoxing-expected.txt create mode 100644 test/compiler/ets/switchStatementWrongBoxing.ets create mode 100644 test/compiler/ets/thisReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/ets/thisReferenceFromStaticContext.ets create mode 100644 test/compiler/ets/typeVarReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/ets/typeVarReferenceFromStaticContext.ets create mode 100644 test/compiler/ets/voidTypeInBinaryOperation-expected.txt create mode 100644 test/compiler/ets/voidTypeInBinaryOperation.ets create mode 100644 test/parser/ets/AccessBinaryTrees-expected.txt create mode 100644 test/parser/ets/AccessBinaryTrees.ets create mode 100644 test/parser/ets/AccessFannkuch-expected.txt create mode 100644 test/parser/ets/AccessFannkuch.ets create mode 100644 test/parser/ets/AccessNBody-expected.txt create mode 100644 test/parser/ets/AccessNBody.ets create mode 100644 test/parser/ets/AccessNSieve-expected.txt create mode 100644 test/parser/ets/AccessNSieve.ets create mode 100644 test/parser/ets/Bitops3BitBitsInByte-expected.txt create mode 100644 test/parser/ets/Bitops3BitBitsInByte.ets create mode 100644 test/parser/ets/BitopsBitsInByte-expected.txt create mode 100644 test/parser/ets/BitopsBitsInByte.ets create mode 100644 test/parser/ets/BitopsBitwiseAnd-expected.txt create mode 100644 test/parser/ets/BitopsBitwiseAnd.ets create mode 100644 test/parser/ets/BitopsNSieveBits-expected.txt create mode 100644 test/parser/ets/BitopsNSieveBits.ets create mode 100644 test/parser/ets/Boolean_bitwise-expected.txt create mode 100644 test/parser/ets/Boolean_bitwise.ets create mode 100644 test/parser/ets/ControlFlowRecursive-expected.txt create mode 100644 test/parser/ets/ControlFlowRecursive.ets create mode 100644 test/parser/ets/FunctionType-expected.txt create mode 100644 test/parser/ets/FunctionType.ets create mode 100644 test/parser/ets/MathCordic-expected.txt create mode 100644 test/parser/ets/MathCordic.ets create mode 100644 test/parser/ets/MathPartialSums-expected.txt create mode 100644 test/parser/ets/MathPartialSums.ets create mode 100644 test/parser/ets/MathSpectralNorm-expected.txt create mode 100644 test/parser/ets/MathSpectralNorm.ets create mode 100644 test/parser/ets/Morph3d-expected.txt create mode 100644 test/parser/ets/Morph3d.ets create mode 100644 test/parser/ets/StringBase64-expected.txt create mode 100644 test/parser/ets/StringBase64.ets create mode 100644 test/parser/ets/StringFasta-expected.txt create mode 100644 test/parser/ets/StringFasta.ets create mode 100644 test/parser/ets/anonymous_class-expected.txt create mode 100644 test/parser/ets/anonymous_class.ets create mode 100644 test/parser/ets/array-expected.txt create mode 100644 test/parser/ets/array.ets create mode 100644 test/parser/ets/array_type-expected.txt create mode 100644 test/parser/ets/array_type.ets create mode 100644 test/parser/ets/assert-expected.txt create mode 100644 test/parser/ets/assert.ets create mode 100644 test/parser/ets/assign-expected.txt create mode 100644 test/parser/ets/assign.ets create mode 100644 test/parser/ets/assign_bad-expected.txt create mode 100644 test/parser/ets/assign_bad.ets create mode 100644 test/parser/ets/assignments-expected.txt create mode 100644 test/parser/ets/assignments.ets create mode 100644 test/parser/ets/binary_op-expected.txt create mode 100644 test/parser/ets/binary_op.ets create mode 100644 test/parser/ets/binary_operations-expected.txt create mode 100644 test/parser/ets/binary_operations.ets create mode 100644 test/parser/ets/blocks-expected.txt create mode 100644 test/parser/ets/blocks.ets create mode 100644 test/parser/ets/blocks_scopes-expected.txt create mode 100644 test/parser/ets/blocks_scopes.ets create mode 100644 test/parser/ets/boolean-expected.txt create mode 100644 test/parser/ets/boolean.ets create mode 100644 test/parser/ets/boolean_cond-expected.txt create mode 100644 test/parser/ets/boolean_cond.ets create mode 100644 test/parser/ets/boolean_default-expected.txt create mode 100644 test/parser/ets/boolean_default.ets create mode 100644 test/parser/ets/break-expected.txt create mode 100644 test/parser/ets/break.ets create mode 100644 test/parser/ets/calling_superclass_methods-expected.txt create mode 100644 test/parser/ets/calling_superclass_methods.ets create mode 100644 test/parser/ets/calls-expected.txt create mode 100644 test/parser/ets/calls.ets create mode 100644 test/parser/ets/cast_expressions-expected.txt create mode 100644 test/parser/ets/cast_expressions.ets create mode 100644 test/parser/ets/class_init-expected.txt create mode 100644 test/parser/ets/class_init.ets create mode 100644 test/parser/ets/class_instance-expected.txt create mode 100644 test/parser/ets/class_instance.ets create mode 100644 test/parser/ets/class_instance_creation-expected.txt create mode 100644 test/parser/ets/class_instance_creation.ets create mode 100644 test/parser/ets/class_instance_initializer-expected.txt create mode 100644 test/parser/ets/class_instance_initializer.ets create mode 100644 test/parser/ets/class_property_access-expected.txt create mode 100644 test/parser/ets/class_property_access.ets create mode 100644 test/parser/ets/class_static_initializer-expected.txt create mode 100644 test/parser/ets/class_static_initializer.ets create mode 100644 test/parser/ets/classes-expected.txt create mode 100644 test/parser/ets/classes.ets create mode 100644 test/parser/ets/comment_block-expected.txt create mode 100644 test/parser/ets/comment_block.ets create mode 100644 test/parser/ets/comment_line-expected.txt create mode 100644 test/parser/ets/comment_line.ets create mode 100644 test/parser/ets/const-expected.txt create mode 100644 test/parser/ets/const.ets create mode 100644 test/parser/ets/const_enum-expected.txt create mode 100644 test/parser/ets/const_enum.ets create mode 100644 test/parser/ets/constructor_test-expected.txt create mode 100644 test/parser/ets/constructor_test.ets create mode 100644 test/parser/ets/constructors-expected.txt create mode 100644 test/parser/ets/constructors.ets create mode 100644 test/parser/ets/continue-expected.txt create mode 100644 test/parser/ets/continue.ets create mode 100644 test/parser/ets/decl_infer-expected.txt create mode 100644 test/parser/ets/decl_infer.ets create mode 100644 test/parser/ets/defer-plus-expected.txt create mode 100644 test/parser/ets/defer-plus.ets create mode 100644 test/parser/ets/empty_class-expected.txt create mode 100644 test/parser/ets/empty_class.ets create mode 100644 test/parser/ets/empty_statement-expected.txt create mode 100644 test/parser/ets/empty_statement.ets create mode 100644 test/parser/ets/enum-expected.txt create mode 100644 test/parser/ets/enum.ets create mode 100644 test/parser/ets/enum_with_class_behavior-expected.txt create mode 100644 test/parser/ets/enum_with_class_behavior.ets create mode 100644 test/parser/ets/exports-expected.txt create mode 100644 test/parser/ets/exports.ets create mode 100644 test/parser/ets/field_decl-expected.txt create mode 100644 test/parser/ets/field_decl.ets create mode 100644 test/parser/ets/fields-expected.txt create mode 100644 test/parser/ets/fields.ets create mode 100644 test/parser/ets/final_empty_class-expected.txt create mode 100644 test/parser/ets/final_empty_class.ets create mode 100644 test/parser/ets/for_of-expected.txt create mode 100644 test/parser/ets/for_of.ets create mode 100644 test/parser/ets/for_with_break-expected.txt create mode 100644 test/parser/ets/for_with_break.ets create mode 100644 test/parser/ets/function-expected.txt create mode 100644 test/parser/ets/function.ets create mode 100644 test/parser/ets/function_decl-expected.txt create mode 100644 test/parser/ets/function_decl.ets create mode 100644 test/parser/ets/generic_function-expected.txt create mode 100644 test/parser/ets/generic_function.ets create mode 100644 test/parser/ets/generics_1-expected.txt create mode 100644 test/parser/ets/generics_1.ets create mode 100644 test/parser/ets/identifier-expected.txt create mode 100644 test/parser/ets/identifier.ets create mode 100644 test/parser/ets/if-expected.txt create mode 100644 test/parser/ets/if.ets create mode 100644 test/parser/ets/ifs-expected.txt create mode 100644 test/parser/ets/ifs.ets create mode 100644 test/parser/ets/index_expressions-expected.txt create mode 100644 test/parser/ets/index_expressions.ets create mode 100644 test/parser/ets/inheritance-expected.txt create mode 100644 test/parser/ets/inheritance.ets create mode 100644 test/parser/ets/instanceof-expected.txt create mode 100644 test/parser/ets/instanceof.ets create mode 100644 test/parser/ets/interface-expected.txt create mode 100644 test/parser/ets/interface.ets create mode 100644 test/parser/ets/interfaces-expected.txt create mode 100644 test/parser/ets/interfaces.ets create mode 100644 test/parser/ets/labeled-expected.txt create mode 100644 test/parser/ets/labeled.ets create mode 100644 test/parser/ets/lexer001-expected.txt create mode 100644 test/parser/ets/lexer001.ets create mode 100644 test/parser/ets/lexer002-expected.txt create mode 100644 test/parser/ets/lexer002.ets create mode 100644 test/parser/ets/literals-expected.txt create mode 100644 test/parser/ets/literals.ets create mode 100644 test/parser/ets/localClassIsPermitted-expected.txt create mode 100644 test/parser/ets/localClassIsPermitted.ets create mode 100644 test/parser/ets/loops-expected.txt create mode 100644 test/parser/ets/loops.ets create mode 100644 test/parser/ets/method_empty-expected.txt create mode 100644 test/parser/ets/method_empty.ets create mode 100644 test/parser/ets/method_full-expected.txt create mode 100644 test/parser/ets/method_full.ets create mode 100644 test/parser/ets/methods-expected.txt create mode 100644 test/parser/ets/methods.ets create mode 100644 test/parser/ets/named_types-expected.txt create mode 100644 test/parser/ets/named_types.ets create mode 100644 test/parser/ets/new_expressions-expected.txt create mode 100644 test/parser/ets/new_expressions.ets create mode 100644 test/parser/ets/null-expected.txt create mode 100644 test/parser/ets/null.ets create mode 100644 test/parser/ets/null_invalid-expected.txt create mode 100644 test/parser/ets/null_invalid.ets create mode 100644 test/parser/ets/object-expected.txt create mode 100644 test/parser/ets/object.ets create mode 100644 test/parser/ets/override_method-expected.txt create mode 100644 test/parser/ets/override_method.ets create mode 100644 test/parser/ets/panic-if-expected.txt create mode 100644 test/parser/ets/panic-if.ets create mode 100644 test/parser/ets/panic-statement-expected.txt create mode 100644 test/parser/ets/panic-statement.ets create mode 100644 test/parser/ets/parentheses_expression_value-expected.txt create mode 100644 test/parser/ets/parentheses_expression_value.ets create mode 100644 test/parser/ets/predefined_non_primitive_types-expected.txt create mode 100644 test/parser/ets/predefined_non_primitive_types.ets create mode 100644 test/parser/ets/predefined_types-expected.txt create mode 100644 test/parser/ets/predefined_types.ets create mode 100644 test/parser/ets/regression-target-type-context-expected.txt create mode 100644 test/parser/ets/regression-target-type-context.ets create mode 100644 test/parser/ets/return-expected.txt create mode 100644 test/parser/ets/return.ets create mode 100644 test/parser/ets/scoped_decl-expected.txt create mode 100644 test/parser/ets/scoped_decl.ets create mode 100644 test/parser/ets/simple_types-expected.txt create mode 100644 test/parser/ets/simple_types.ets create mode 100644 test/parser/ets/special_signatures-expected.txt create mode 100644 test/parser/ets/special_signatures.ets create mode 100644 test/parser/ets/string-expected.txt create mode 100644 test/parser/ets/string.ets create mode 100644 test/parser/ets/switch-expected.txt create mode 100644 test/parser/ets/switch.ets create mode 100644 test/parser/ets/switch2-expected.txt create mode 100644 test/parser/ets/switch2.ets create mode 100644 test/parser/ets/ternary-expected.txt create mode 100644 test/parser/ets/ternary.ets create mode 100644 test/parser/ets/test_enum-expected.txt create mode 100644 test/parser/ets/test_enum.ets create mode 100644 test/parser/ets/test_interface-expected.txt create mode 100644 test/parser/ets/test_interface.ets create mode 100644 test/parser/ets/this_callee-expected.txt create mode 100644 test/parser/ets/this_callee.ets create mode 100644 test/parser/ets/this_cmp_object-expected.txt create mode 100644 test/parser/ets/this_cmp_object.ets create mode 100644 test/parser/ets/topLevelStaticClass-expected.txt create mode 100644 test/parser/ets/topLevelStaticClass.ets create mode 100644 test/parser/ets/trap-expected.txt create mode 100644 test/parser/ets/trap-missing-catch-expected.txt create mode 100644 test/parser/ets/trap-missing-catch.ets create mode 100644 test/parser/ets/trap.ets create mode 100644 test/parser/ets/type_cast-expected.txt create mode 100644 test/parser/ets/type_cast.ets create mode 100644 test/parser/ets/type_references-expected.txt create mode 100644 test/parser/ets/type_references.ets create mode 100644 test/parser/ets/types_decls-expected.txt create mode 100644 test/parser/ets/types_decls.ets create mode 100644 test/parser/ets/unary_op-expected.txt create mode 100644 test/parser/ets/unary_op.ets create mode 100644 test/parser/ets/unary_operations-expected.txt create mode 100644 test/parser/ets/unary_operations.ets create mode 100644 test/parser/ets/var_declare-expected.txt create mode 100644 test/parser/ets/var_declare.ets create mode 100644 test/parser/ets/void-expected.txt create mode 100644 test/parser/ets/void.ets create mode 100644 test/parser/js/test-function-decl-1-expected.txt create mode 100644 test/parser/js/test-function-decl-1.js create mode 100644 test/parser/js/test-function-decl-2-expected.txt create mode 100644 test/parser/js/test-function-decl-2.js create mode 100644 test/runtime/ets/AccessBinaryTrees.ets create mode 100644 test/runtime/ets/AccessFannkuch.ets create mode 100644 test/runtime/ets/AccessNBody.ets create mode 100644 test/runtime/ets/AccessNSieve.ets create mode 100644 test/runtime/ets/Bitops3BitBitsInByte.ets create mode 100644 test/runtime/ets/BitopsBitsInByte.ets create mode 100644 test/runtime/ets/BitopsBitwiseAnd.ets create mode 100644 test/runtime/ets/BitopsNSieveBits.ets create mode 100644 test/runtime/ets/ClassNewInstance.ets create mode 100644 test/runtime/ets/ControlFlowRecursive.ets create mode 100644 test/runtime/ets/FunctionType.ets create mode 100644 test/runtime/ets/MathCordic.ets create mode 100644 test/runtime/ets/MathPartialSums.ets create mode 100644 test/runtime/ets/MathSpectralNorm.ets create mode 100644 test/runtime/ets/Morph3d.ets create mode 100644 test/runtime/ets/StringBase64.ets create mode 100644 test/runtime/ets/StringFasta.ets create mode 100644 test/runtime/ets/array-expression.ets create mode 100644 test/runtime/ets/cast.ets create mode 100644 test/runtime/ets/char-type.ets create mode 100644 test/runtime/ets/class-init.ets create mode 100644 test/runtime/ets/class-init2.ets create mode 100644 test/runtime/ets/count.ets create mode 100644 test/runtime/ets/date-now.ets create mode 100644 test/runtime/ets/generics_1.ets create mode 100644 test/runtime/ets/instanceof.ets create mode 100644 test/runtime/ets/skippedTest.ets create mode 100644 test/runtime/ets/string-builder.ets create mode 100644 test/runtime/ets/unboxing.ets delete mode 100644 typescript/checker.cpp delete mode 100644 typescript/types/typeMapping.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c56fd3717 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +test/__pycache__/ +test/runner/__pycache__/ +test/runner/plugins/ets/__pycache__/ +test/runner/plugins/hermes/__pycache__/ +test/runner/plugins/parser/__pycache__/ +test/runner/plugins/test262/__pycache__/ diff --git a/BUILD.gn b/BUILD.gn index 714417c16..60b4520b5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -25,8 +25,14 @@ config("libes2panda_public_config") { libes2panda_sources = [ "es2panda.cpp", + "binder/ASBinder.cpp", + "binder/TSBinder.cpp", + "binder/TypedBinder.cpp", + "binder/ETSBinder.cpp", + "binder/JSBinder.cpp", "binder/binder.cpp", "binder/declaration.cpp", + "binder/recordTable.cpp", "binder/scope.cpp", "binder/variable.cpp", "compiler/base/catchTable.cpp", @@ -38,26 +44,36 @@ libes2panda_sources = [ "compiler/base/literals.cpp", "compiler/base/lreference.cpp", "compiler/base/optionalChain.cpp", + "compiler/core/codeGen.cpp", + "compiler/core/compileJob.cpp", "compiler/core/compileQueue.cpp", "compiler/core/compilerContext.cpp", "compiler/core/compilerImpl.cpp", "compiler/core/dynamicContext.cpp", "compiler/core/emitter.cpp", + "compiler/core/JSemitter.cpp", "compiler/core/envScope.cpp", "compiler/core/function.cpp", - "compiler/core/inlineCache.cpp", "compiler/core/labelTarget.cpp", "compiler/core/moduleContext.cpp", "compiler/core/pandagen.cpp", + "compiler/core/programElement.cpp", "compiler/core/regAllocator.cpp", "compiler/core/regScope.cpp", + "compiler/core/regSpiller.cpp", + "compiler/core/ETSemitter.cpp", + "compiler/core/ETSGen.cpp", + "compiler/core/ETSfunction.cpp", "compiler/core/switchBuilder.cpp", + "compiler/core/targetTypeContext.cpp", + "compiler/core/vReg.cpp", "compiler/debugger/debuginfoDumper.cpp", "compiler/function/asyncFunctionBuilder.cpp", "compiler/function/asyncGeneratorFunctionBuilder.cpp", "compiler/function/functionBuilder.cpp", "compiler/function/generatorFunctionBuilder.cpp", "ir/astDump.cpp", + "ir/astNode.cpp", "ir/irnode.cpp", "ir/base/catchClause.cpp", "ir/base/classElement.cpp", @@ -71,6 +87,10 @@ libes2panda_sources = [ "ir/base/scriptFunction.cpp", "ir/base/spreadElement.cpp", "ir/base/templateElement.cpp", + "ir/base/tsIndexSignature.cpp", + "ir/base/tsMethodSignature.cpp", + "ir/base/tsPropertySignature.cpp", + "ir/base/tsSignatureDeclaration.cpp", "ir/expression.cpp", "ir/expressions/arrayExpression.cpp", "ir/expressions/arrowFunctionExpression.cpp", @@ -88,6 +108,7 @@ libes2panda_sources = [ "ir/expressions/literal.cpp", "ir/expressions/literals/bigIntLiteral.cpp", "ir/expressions/literals/booleanLiteral.cpp", + "ir/expressions/literals/charLiteral.cpp", "ir/expressions/literals/nullLiteral.cpp", "ir/expressions/literals/numberLiteral.cpp", "ir/expressions/literals/regExpLiteral.cpp", @@ -113,11 +134,13 @@ libes2panda_sources = [ "ir/module/importNamespaceSpecifier.cpp", "ir/module/importSpecifier.cpp", "ir/statement.cpp", + "ir/statements/assertStatement.cpp", "ir/statements/blockStatement.cpp", "ir/statements/breakStatement.cpp", "ir/statements/classDeclaration.cpp", "ir/statements/continueStatement.cpp", "ir/statements/debuggerStatement.cpp", + "ir/statements/deferStatement.cpp", "ir/statements/doWhileStatement.cpp", "ir/statements/emptyStatement.cpp", "ir/statements/expressionStatement.cpp", @@ -128,9 +151,11 @@ libes2panda_sources = [ "ir/statements/ifStatement.cpp", "ir/statements/labelledStatement.cpp", "ir/statements/loopStatement.cpp", + "ir/statements/panicStatement.cpp", "ir/statements/returnStatement.cpp", "ir/statements/switchCaseStatement.cpp", "ir/statements/switchStatement.cpp", + "ir/statements/trapStatement.cpp", "ir/statements/throwStatement.cpp", "ir/statements/tryStatement.cpp", "ir/statements/variableDeclaration.cpp", @@ -152,7 +177,6 @@ libes2panda_sources = [ "ir/ts/tsFunctionType.cpp", "ir/ts/tsImportEqualsDeclaration.cpp", "ir/ts/tsImportType.cpp", - "ir/ts/tsIndexSignature.cpp", "ir/ts/tsIndexedAccessType.cpp", "ir/ts/tsInferType.cpp", "ir/ts/tsInterfaceBody.cpp", @@ -161,7 +185,6 @@ libes2panda_sources = [ "ir/ts/tsIntersectionType.cpp", "ir/ts/tsLiteralType.cpp", "ir/ts/tsMappedType.cpp", - "ir/ts/tsMethodSignature.cpp", "ir/ts/tsModuleBlock.cpp", "ir/ts/tsModuleDeclaration.cpp", "ir/ts/tsNamedTupleMember.cpp", @@ -172,9 +195,7 @@ libes2panda_sources = [ "ir/ts/tsObjectKeyword.cpp", "ir/ts/tsParameterProperty.cpp", "ir/ts/tsParenthesizedType.cpp", - "ir/ts/tsPropertySignature.cpp", "ir/ts/tsQualifiedName.cpp", - "ir/ts/tsSignatureDeclaration.cpp", "ir/ts/tsStringKeyword.cpp", "ir/ts/tsThisType.cpp", "ir/ts/tsTupleType.cpp", @@ -192,61 +213,118 @@ libes2panda_sources = [ "ir/ts/tsUnionType.cpp", "ir/ts/tsUnknownKeyword.cpp", "ir/ts/tsVoidKeyword.cpp", + "ir/ets/etsClassLiteral.cpp", + "ir/ets/etsFunctionType.cpp", + "ir/ets/etsMethodReferenceExpression.cpp", + "ir/ets/etsNewArrayInstanceExpression.cpp", + "ir/ets/etsNewClassInstanceExpression.cpp", + "ir/ets/etsNewMultiDimArrayInstanceExpression.cpp", + "ir/ets/etsPackageDeclaration.cpp", + "ir/ets/etsPrimitiveType.cpp", + "ir/ets/etsScript.cpp", + "ir/ets/etsTryExpression.cpp", + "ir/ets/etsTypeReference.cpp", + "ir/ets/etsTypeReferencePart.cpp", + "ir/ets/etsWildcardType.cpp", + "lexer/ASLexer.cpp", + "lexer/keywords.cpp", "lexer/keywordsUtil.cpp", "lexer/lexer.cpp", + "lexer/ETSLexer.cpp", + "lexer/TSLexer.cpp", "lexer/regexp/regexp.cpp", + "lexer/token/number.cpp", "lexer/token/sourceLocation.cpp", "lexer/token/token.cpp", "parser/context/classPrivateContext.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", + "parser/ASparser.cpp", + "parser/JSparser.cpp", "parser/parserImpl.cpp", + "parser/ETSparser.cpp", + "parser/TSparser.cpp", + "parser/TypedParser.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", - "typescript/checker.cpp", - "typescript/core/binaryLikeExpression.cpp", - "typescript/core/checkerContext.cpp", - "typescript/core/destructuringContext.cpp", - "typescript/core/function.cpp", - "typescript/core/helpers.cpp", - "typescript/core/object.cpp", - "typescript/core/typeCreation.cpp", - "typescript/core/typeElaborationContext.cpp", - "typescript/core/typeRelation.cpp", - "typescript/core/util.cpp", - "typescript/types/anyType.cpp", - "typescript/types/arrayType.cpp", - "typescript/types/bigintLiteralType.cpp", - "typescript/types/bigintType.cpp", - "typescript/types/booleanLiteralType.cpp", - "typescript/types/booleanType.cpp", - "typescript/types/constructorType.cpp", - "typescript/types/enumLiteralType.cpp", - "typescript/types/enumType.cpp", - "typescript/types/functionType.cpp", - "typescript/types/globalTypesHolder.cpp", - "typescript/types/indexInfo.cpp", - "typescript/types/interfaceType.cpp", - "typescript/types/neverType.cpp", - "typescript/types/nonPrimitiveType.cpp", - "typescript/types/nullType.cpp", - "typescript/types/numberLiteralType.cpp", - "typescript/types/numberType.cpp", - "typescript/types/objectDescriptor.cpp", - "typescript/types/objectLiteralType.cpp", - "typescript/types/objectType.cpp", - "typescript/types/signature.cpp", - "typescript/types/stringLiteralType.cpp", - "typescript/types/stringType.cpp", - "typescript/types/tupleType.cpp", - "typescript/types/type.cpp", - "typescript/types/typeParameter.cpp", - "typescript/types/typeReference.cpp", - "typescript/types/typeRelation.cpp", - "typescript/types/undefinedType.cpp", - "typescript/types/unionType.cpp", - "typescript/types/unknownType.cpp", - "typescript/types/voidType.cpp", + "checker/checker.cpp", + "checker/checkerContext.cpp", + "checker/ETSchecker.cpp", + "checker/TSchecker.cpp", + "checker/ASchecker.cpp", + "checker/JSchecker.cpp", + "checker/ets/aliveAnalyzer.cpp", + "checker/ets/arithmetic.cpp", + "checker/ets/baseAnalyzer.cpp", + "checker/ets/boxingConverter.cpp", + "checker/ets/function.cpp", + "checker/ets/helpers.cpp", + "checker/ets/narrowingConverter.cpp", + "checker/ets/narrowingWideningConverter.cpp", + "checker/ets/object.cpp", + "checker/ets/primitiveWrappers.cpp", + "checker/ets/typeConverter.cpp", + "checker/ets/typeCreation.cpp", + "checker/ets/typeRelationContext.cpp", + "checker/ets/unboxingConverter.cpp", + "checker/ets/wideningConverter.cpp", + "checker/ts/binaryLikeExpression.cpp", + "checker/ts/destructuringContext.cpp", + "checker/ts/function.cpp", + "checker/ts/helpers.cpp", + "checker/ts/object.cpp", + "checker/ts/typeCreation.cpp", + "checker/ts/typeElaborationContext.cpp", + "checker/ts/util.cpp", + "checker/types/signature.cpp", + "checker/types/type.cpp", + "checker/types/typeRelation.cpp", + "checker/types/globalTypesHolder.cpp", + "checker/types/ets/byteType.cpp", + "checker/types/ets/charType.cpp", + "checker/types/ets/doubleType.cpp", + "checker/types/ets/floatType.cpp", + "checker/types/ets/intType.cpp", + "checker/types/ets/longType.cpp", + "checker/types/ets/shortType.cpp", + "checker/types/ets/etsArrayType.cpp", + "checker/types/ets/etsBooleanType.cpp", + "checker/types/ets/etsFunctionType.cpp", + "checker/types/ets/etsObjectType.cpp", + "checker/types/ets/etsStringType.cpp", + "checker/types/ets/etsTypeParameter.cpp", + "checker/types/ets/etsTypeReference.cpp", + "checker/types/ets/etsVoidType.cpp", + "checker/types/ets/wildcardType.cpp", + "checker/types/ts/anyType.cpp", + "checker/types/ts/arrayType.cpp", + "checker/types/ts/bigintLiteralType.cpp", + "checker/types/ts/bigintType.cpp", + "checker/types/ts/booleanLiteralType.cpp", + "checker/types/ts/booleanType.cpp", + "checker/types/ts/constructorType.cpp", + "checker/types/ts/enumLiteralType.cpp", + "checker/types/ts/enumType.cpp", + "checker/types/ts/functionType.cpp", + "checker/types/ts/indexInfo.cpp", + "checker/types/ts/interfaceType.cpp", + "checker/types/ts/neverType.cpp", + "checker/types/ts/nonPrimitiveType.cpp", + "checker/types/ts/nullType.cpp", + "checker/types/ts/numberLiteralType.cpp", + "checker/types/ts/numberType.cpp", + "checker/types/ts/objectDescriptor.cpp", + "checker/types/ts/objectLiteralType.cpp", + "checker/types/ts/objectType.cpp", + "checker/types/ts/stringLiteralType.cpp", + "checker/types/ts/stringType.cpp", + "checker/types/ts/tupleType.cpp", + "checker/types/ts/typeParameter.cpp", + "checker/types/ts/typeReference.cpp", + "checker/types/ts/undefinedType.cpp", + "checker/types/ts/unionType.cpp", + "checker/types/ts/unknownType.cpp", + "checker/types/ts/voidType.cpp", "util/bitset.cpp", "util/helpers.cpp", "util/ustring.cpp", @@ -277,8 +355,8 @@ ohos_shared_library("libes2panda") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_lexer_keywords_h", + ":gen_es2panda_compiler_signatures_h", "$ark_root/assembler:libarkassembler", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", @@ -299,8 +377,8 @@ ohos_static_library("libes2panda_frontend_static") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_lexer_keywords_h", + ":gen_es2panda_compiler_signatures_h", "$ark_root/assembler:libarkassembler_frontend_static", "$ark_root/libpandabase:libarkbase_frontend_static", "$ark_root/libpandafile:libarkfile_frontend_static", @@ -318,20 +396,26 @@ ark_isa_gen("isa_gen_es2panda") { destination = "$target_gen_dir/generated" } -action("es2panda_lexer_keywords_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywords.h" ] - args = [ - rebase_path("lexer/templates/keywords.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywords.h", root_build_dir), +ark_gen("gen_es2panda_lexer") { + data = "lexer/scripts/keywords.yaml" + template_files = [ + "keywords.h.erb", + ] + sources = "lexer/templates" + destination = "$target_gen_dir/generated" + requires = [ + "lexer/scripts/keywords.rb", ] } -action("es2panda_lexer_keywords_map_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywordsMap.h" ] - args = [ - rebase_path("lexer/templates/keywordsMap.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywordsMap.h", root_build_dir), +ark_gen("gen_es2panda_compiler") { + data = "compiler/scripts/signatures.yaml" + template_files = [ + "signatures.h.erb", + ] + sources = "compiler/templates" + destination = "$target_gen_dir/generated" + requires = [ + "compiler/scripts/signatures.rb", ] } diff --git a/CMakeLists.txt b/CMakeLists.txt index 3113e256f..5fea46729 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(GENERATED_DIR ${OUTPUT_DIR}/generated) set(GENERATED_STAMP ${OUTPUT_DIR}/gen_dir.stamp) -add_custom_target(es2panda-gen) +file(MAKE_DIRECTORY "${GENERATED_DIR}") add_custom_command( OUTPUT ${GENERATED_STAMP} @@ -40,35 +40,36 @@ panda_isa_gen( EXTRA_DEPENDENCIES ${GENERATED_STAMP} ) -add_dependencies(es2panda-gen isa_gen_es2panda) - -function(gen_keywords TEMPLATE OUT_DIR) - set(TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates/${TEMPLATE}) - - string(REGEX REPLACE "\.erb$" "" NAME ${TEMPLATE}) - string(REPLACE "\." "_" CUSTOM_TARGET ${NAME}) - string(REPLACE "/" "_" CUSTOM_TARGET ${CUSTOM_TARGET}) - set(CUSTOM_TARGET "panda_es2panda_parser_gen_${CUSTOM_TARGET}") - - set(OUT_FILE ${OUT_DIR}/${NAME}) - set(GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb) - - add_custom_command(OUTPUT ${OUT_FILE} - COMMAND ruby ${GENERATOR} ${TEMPLATE_FILE} ${OUT_FILE} - DEPENDS ${GENERATED_STAMP} ${GENERATOR} ${TEMPLATE_FILE} - ) - - add_custom_target(${CUSTOM_TARGET} DEPENDS ${OUT_FILE}) - add_dependencies(es2panda-gen ${CUSTOM_TARGET}) -endfunction() +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.yaml + TARGET_NAME es2panda_keywords + TEMPLATES keywords.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates + DESTINATION ${GENERATED_DIR} +) -gen_keywords(keywords.h.erb ${GENERATED_DIR}) -gen_keywords(keywordsMap.h.erb ${GENERATED_DIR}) +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.yaml + TARGET_NAME es2panda_signatures + TEMPLATES signatures.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/compiler/templates + DESTINATION ${GENERATED_DIR} +) set(ES2PANDA_LIB_SRC es2panda.cpp + binder/ASBinder.cpp + binder/TSBinder.cpp + binder/TypedBinder.cpp + binder/ETSBinder.cpp + binder/JSBinder.cpp binder/binder.cpp binder/declaration.cpp + binder/recordTable.cpp binder/scope.cpp binder/variable.cpp compiler/base/catchTable.cpp @@ -80,26 +81,36 @@ set(ES2PANDA_LIB_SRC compiler/base/literals.cpp compiler/base/lreference.cpp compiler/base/optionalChain.cpp + compiler/core/codeGen.cpp + compiler/core/compileJob.cpp compiler/core/compileQueue.cpp compiler/core/compilerContext.cpp compiler/core/compilerImpl.cpp compiler/core/dynamicContext.cpp compiler/core/emitter.cpp + compiler/core/JSemitter.cpp compiler/core/envScope.cpp compiler/core/function.cpp - compiler/core/inlineCache.cpp compiler/core/labelTarget.cpp compiler/core/moduleContext.cpp compiler/core/pandagen.cpp + compiler/core/programElement.cpp compiler/core/regAllocator.cpp compiler/core/regScope.cpp + compiler/core/regSpiller.cpp + compiler/core/ETSemitter.cpp + compiler/core/ETSGen.cpp + compiler/core/ETSfunction.cpp compiler/core/switchBuilder.cpp + compiler/core/targetTypeContext.cpp + compiler/core/vReg.cpp compiler/debugger/debuginfoDumper.cpp compiler/function/asyncFunctionBuilder.cpp compiler/function/asyncGeneratorFunctionBuilder.cpp compiler/function/functionBuilder.cpp compiler/function/generatorFunctionBuilder.cpp ir/astDump.cpp + ir/astNode.cpp ir/irnode.cpp ir/base/catchClause.cpp ir/base/classElement.cpp @@ -113,6 +124,10 @@ set(ES2PANDA_LIB_SRC ir/base/scriptFunction.cpp ir/base/spreadElement.cpp ir/base/templateElement.cpp + ir/base/tsIndexSignature.cpp + ir/base/tsMethodSignature.cpp + ir/base/tsPropertySignature.cpp + ir/base/tsSignatureDeclaration.cpp ir/expression.cpp ir/expressions/arrayExpression.cpp ir/expressions/arrowFunctionExpression.cpp @@ -130,6 +145,7 @@ set(ES2PANDA_LIB_SRC ir/expressions/literal.cpp ir/expressions/literals/bigIntLiteral.cpp ir/expressions/literals/booleanLiteral.cpp + ir/expressions/literals/charLiteral.cpp ir/expressions/literals/nullLiteral.cpp ir/expressions/literals/numberLiteral.cpp ir/expressions/literals/regExpLiteral.cpp @@ -155,11 +171,13 @@ set(ES2PANDA_LIB_SRC ir/module/importNamespaceSpecifier.cpp ir/module/importSpecifier.cpp ir/statement.cpp + ir/statements/assertStatement.cpp ir/statements/blockStatement.cpp ir/statements/breakStatement.cpp ir/statements/classDeclaration.cpp ir/statements/continueStatement.cpp ir/statements/debuggerStatement.cpp + ir/statements/deferStatement.cpp ir/statements/doWhileStatement.cpp ir/statements/emptyStatement.cpp ir/statements/expressionStatement.cpp @@ -170,16 +188,31 @@ set(ES2PANDA_LIB_SRC ir/statements/ifStatement.cpp ir/statements/labelledStatement.cpp ir/statements/loopStatement.cpp + ir/statements/panicStatement.cpp ir/statements/returnStatement.cpp ir/statements/switchCaseStatement.cpp ir/statements/switchStatement.cpp ir/statements/throwStatement.cpp + ir/statements/trapStatement.cpp ir/statements/tryStatement.cpp ir/statements/variableDeclaration.cpp ir/statements/variableDeclarator.cpp ir/statements/whileStatement.cpp ir/as/namedType.cpp ir/as/prefixAssertionExpression.cpp + ir/ets/etsClassLiteral.cpp + ir/ets/etsFunctionType.cpp + ir/ets/etsMethodReferenceExpression.cpp + ir/ets/etsNewArrayInstanceExpression.cpp + ir/ets/etsNewClassInstanceExpression.cpp + ir/ets/etsNewMultiDimArrayInstanceExpression.cpp + ir/ets/etsPackageDeclaration.cpp + ir/ets/etsPrimitiveType.cpp + ir/ets/etsScript.cpp + ir/ets/etsTryExpression.cpp + ir/ets/etsTypeReference.cpp + ir/ets/etsTypeReferencePart.cpp + ir/ets/etsWildcardType.cpp ir/ts/tsAnyKeyword.cpp ir/ts/tsArrayType.cpp ir/ts/tsAsExpression.cpp @@ -194,7 +227,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsFunctionType.cpp ir/ts/tsImportEqualsDeclaration.cpp ir/ts/tsImportType.cpp - ir/ts/tsIndexSignature.cpp ir/ts/tsIndexedAccessType.cpp ir/ts/tsInferType.cpp ir/ts/tsInterfaceBody.cpp @@ -203,7 +235,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsIntersectionType.cpp ir/ts/tsLiteralType.cpp ir/ts/tsMappedType.cpp - ir/ts/tsMethodSignature.cpp ir/ts/tsModuleBlock.cpp ir/ts/tsModuleDeclaration.cpp ir/ts/tsNamedTupleMember.cpp @@ -214,9 +245,7 @@ set(ES2PANDA_LIB_SRC ir/ts/tsObjectKeyword.cpp ir/ts/tsParameterProperty.cpp ir/ts/tsParenthesizedType.cpp - ir/ts/tsPropertySignature.cpp ir/ts/tsQualifiedName.cpp - ir/ts/tsSignatureDeclaration.cpp ir/ts/tsStringKeyword.cpp ir/ts/tsThisType.cpp ir/ts/tsTupleType.cpp @@ -234,68 +263,112 @@ set(ES2PANDA_LIB_SRC ir/ts/tsUnionType.cpp ir/ts/tsUnknownKeyword.cpp ir/ts/tsVoidKeyword.cpp + lexer/ASLexer.cpp + lexer/keywords.cpp lexer/keywordsUtil.cpp lexer/lexer.cpp + lexer/ETSLexer.cpp + lexer/TSLexer.cpp lexer/regexp/regexp.cpp + lexer/token/number.cpp lexer/token/sourceLocation.cpp lexer/token/token.cpp parser/context/classPrivateContext.cpp parser/context/parserContext.cpp parser/expressionParser.cpp + parser/ASparser.cpp + parser/JSparser.cpp parser/parserImpl.cpp + parser/ETSparser.cpp + parser/TSparser.cpp + parser/TypedParser.cpp parser/program/program.cpp parser/statementParser.cpp - typescript/checker.cpp - typescript/core/binaryLikeExpression.cpp - typescript/core/checkerContext.cpp - typescript/core/destructuringContext.cpp - typescript/core/function.cpp - typescript/core/helpers.cpp - typescript/core/object.cpp - typescript/core/typeCreation.cpp - typescript/core/typeElaborationContext.cpp - typescript/core/typeRelation.cpp - typescript/core/util.cpp - typescript/types/anyType.cpp - typescript/types/arrayType.cpp - typescript/types/bigintLiteralType.cpp - typescript/types/bigintType.cpp - typescript/types/booleanLiteralType.cpp - typescript/types/booleanType.cpp - typescript/types/constructorType.cpp - typescript/types/enumLiteralType.cpp - typescript/types/enumType.cpp - typescript/types/functionType.cpp - typescript/types/globalTypesHolder.cpp - typescript/types/indexInfo.cpp - typescript/types/interfaceType.cpp - typescript/types/neverType.cpp - typescript/types/nonPrimitiveType.cpp - typescript/types/nullType.cpp - typescript/types/numberLiteralType.cpp - typescript/types/numberType.cpp - typescript/types/objectDescriptor.cpp - typescript/types/objectLiteralType.cpp - typescript/types/objectType.cpp - typescript/types/signature.cpp - typescript/types/stringLiteralType.cpp - typescript/types/stringType.cpp - typescript/types/tupleType.cpp - typescript/types/type.cpp - typescript/types/typeParameter.cpp - typescript/types/typeReference.cpp - typescript/types/typeRelation.cpp - typescript/types/undefinedType.cpp - typescript/types/unionType.cpp - typescript/types/unknownType.cpp - typescript/types/voidType.cpp + checker/checker.cpp + checker/checkerContext.cpp + checker/ETSchecker.cpp + checker/TSchecker.cpp + checker/ASchecker.cpp + checker/JSchecker.cpp + checker/ets/aliveAnalyzer.cpp + checker/ets/arithmetic.cpp + checker/ets/baseAnalyzer.cpp + checker/ets/boxingConverter.cpp + checker/ets/function.cpp + checker/ets/helpers.cpp + checker/ets/narrowingConverter.cpp + checker/ets/narrowingWideningConverter.cpp + checker/ets/object.cpp + checker/ets/primitiveWrappers.cpp + checker/ets/typeConverter.cpp + checker/ets/typeCreation.cpp + checker/ets/typeRelationContext.cpp + checker/ets/unboxingConverter.cpp + checker/ets/wideningConverter.cpp + checker/ts/binaryLikeExpression.cpp + checker/ts/destructuringContext.cpp + checker/ts/function.cpp + checker/ts/helpers.cpp + checker/ts/object.cpp + checker/ts/typeCreation.cpp + checker/ts/typeElaborationContext.cpp + checker/ts/util.cpp + checker/types/signature.cpp + checker/types/type.cpp + checker/types/typeRelation.cpp + checker/types/globalTypesHolder.cpp + checker/types/ets/byteType.cpp + checker/types/ets/charType.cpp + checker/types/ets/doubleType.cpp + checker/types/ets/floatType.cpp + checker/types/ets/intType.cpp + checker/types/ets/longType.cpp + checker/types/ets/shortType.cpp + checker/types/ets/etsArrayType.cpp + checker/types/ets/etsBooleanType.cpp + checker/types/ets/etsFunctionType.cpp + checker/types/ets/etsObjectType.cpp + checker/types/ets/etsStringType.cpp + checker/types/ets/etsTypeParameter.cpp + checker/types/ets/etsTypeReference.cpp + checker/types/ets/etsVoidType.cpp + checker/types/ets/wildcardType.cpp + checker/types/ts/anyType.cpp + checker/types/ts/arrayType.cpp + checker/types/ts/bigintLiteralType.cpp + checker/types/ts/bigintType.cpp + checker/types/ts/booleanLiteralType.cpp + checker/types/ts/booleanType.cpp + checker/types/ts/constructorType.cpp + checker/types/ts/enumLiteralType.cpp + checker/types/ts/enumType.cpp + checker/types/ts/functionType.cpp + checker/types/ts/indexInfo.cpp + checker/types/ts/interfaceType.cpp + checker/types/ts/neverType.cpp + checker/types/ts/nonPrimitiveType.cpp + checker/types/ts/nullType.cpp + checker/types/ts/numberLiteralType.cpp + checker/types/ts/numberType.cpp + checker/types/ts/objectDescriptor.cpp + checker/types/ts/objectLiteralType.cpp + checker/types/ts/objectType.cpp + checker/types/ts/stringLiteralType.cpp + checker/types/ts/stringType.cpp + checker/types/ts/tupleType.cpp + checker/types/ts/typeParameter.cpp + checker/types/ts/typeReference.cpp + checker/types/ts/undefinedType.cpp + checker/types/ts/unionType.cpp + checker/types/ts/unknownType.cpp + checker/types/ts/voidType.cpp util/bitset.cpp util/helpers.cpp util/ustring.cpp ) add_library(es2panda-lib ${PANDA_DEFAULT_LIB_TYPE} ${ES2PANDA_LIB_SRC}) -add_dependencies(es2panda-lib es2panda-gen) +add_dependencies(es2panda-lib isa_gen_es2panda es2panda_keywords es2panda_signatures) set(ICU_INCLUDE_DIRS ${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source/common @@ -318,10 +391,19 @@ if(POLICY CMP0079) cmake_policy(SET CMP0079 NEW) endif() -target_link_libraries(es2panda-lib - PUBLIC arkbase hmicuuc.z - PRIVATE arkassembler -) +if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)) + target_link_libraries(es2panda-lib + PUBLIC arkbase hmicuuc.z stdc++fs + PRIVATE arkassembler + ) +else() + target_link_libraries(es2panda-lib + PUBLIC arkbase hmicuuc.z + PRIVATE arkassembler + ) +endif() + if (PANDA_FUZZILLI) target_compile_options(es2panda-lib diff --git a/README.md b/README.md index 1ae69d9bc..43a3d5500 100644 --- a/README.md +++ b/README.md @@ -25,38 +25,19 @@ es2panda [OPTIONS] [input file] -- [arguments] ## Running the tests ```sh -pip install tqdm dataclasses python-dotenv +pip install tqdm ``` ```sh -python3 test/runner/runner.py [OPTIONS] [build_directory] +python3 test/runner.py [OPTIONS] [build_directory] ``` ### Optional arguments -#### Test sets - `--regression`: Run regression tests - - `--test262`: Run test262. To run tests from test262 set specify environment variables `TEST262_REVISION` and `TEST262_URL` in the `.env` file. - - `--hermes`: Run Hermes runtime tests. To run tests from hermes set specify environment variables `HERMES_REVISION` and `HERMES_URL` in the `.env` file. - -#### Extra arguments + - `--test262`: Run test262 - `--no-progress`: Don't show progress bar - - `--verbose`: Generates more detailed output - -Other options are described at starter.py file -#### Tail arguments +### Tail arguments - `build_directory`: Path to panda build directory -### Execution time report -It is possible to collect statistics how long separate tests work. In the result report tests are grouped by execution time. -The grouping edges are set in seconds in the environment variable `TIME_EDGES`. For example the value `1 5 10` specifies -4 groups - less than 1 second, from 1 second to 5 seconds, from 5 seconds to 10 seconds and from 10 seconds and more. -For the last group the report contains real durations. - - Specify the option `--time-report` - - Set an environment variable in the `.env` file in the format `TIME_EDGES="1 5 10"` - - After test run the short report will be output to the console - - And full report will be created at the path `test/time_report.txt` - ### Skip list -Skip list for the runtime: - - test262: `test/test262skiplist.txt, test/test262skiplist-long.txt` - - hermes: `test/hermes-excluded.txt, test/hermes-excluded-aot-inline-full.txt`. +Skip list for the runtime: `test/test262skiplist.txt, test/test262skiplist-long.txt`. diff --git a/aot/main.cpp b/aot/main.cpp index 778d36a76..51c8339d7 100644 --- a/aot/main.cpp +++ b/aot/main.cpp @@ -63,13 +63,14 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options panda::Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), componentMask); if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } panda::bytecodeopt::OPTIONS.SetOptLevel(options->OptLevel()); // Set default value instead of maximum set in panda::bytecodeopt::SetCompilerOptions() panda::compiler::OPTIONS.SetCompilerMaxBytecodeSize(panda::compiler::OPTIONS.GetCompilerMaxBytecodeSize()); - panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), true, true); + panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), options->IsDynamic(), true); } #endif @@ -83,6 +84,7 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options } if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } @@ -118,10 +120,19 @@ int Run(int argc, const char **argv) return 1; } + std::string_view sourceFile; + std::string_view parserInput; + if (options->CompilerOptions().genStdLib) { + sourceFile = "etsstdlib.ets"; + parserInput = ""; + } else { + sourceFile = options->SourceFile(); + parserInput = options->ParserInput(); + } es2panda::Compiler compiler(options->Extension(), options->ThreadCount()); - es2panda::SourceFile input(options->SourceFile(), options->ParserInput(), options->ParseModule()); + es2panda::SourceFile input(sourceFile, parserInput, options->ParseModule()); - auto *program = compiler.Compile(input, options->CompilerOptions()); + auto program = std::unique_ptr {compiler.Compile(input, options->CompilerOptions())}; if (program == nullptr) { const auto &err = compiler.GetError(); @@ -131,15 +142,13 @@ int Run(int argc, const char **argv) } std::cout << err.TypeString() << ": " << err.Message(); - std::cout << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl; + std::cout << " [" << (err.File().empty() ? options->SourceFile() : err.File()) << ":" << err.Line() << ":" + << err.Col() << "]" << std::endl; return err.ErrorCode(); } - GenerateProgram(program, options.get()); - delete program; - - return 0; + return GenerateProgram(program.get(), options.get()); } } // namespace panda::es2panda::aot diff --git a/aot/options.cpp b/aot/options.cpp index fbce88d98..053713541 100644 --- a/aot/options.cpp +++ b/aot/options.cpp @@ -48,7 +48,7 @@ bool Options::Parse(int argc, const char **argv) // parser panda::PandArg inputExtension("extension", "js", - "Parse the input as the given extension (options: js | ts | as)"); + "Parse the input as the given extension (options: js | ts | as | ets)"); panda::PandArg opModule("module", false, "Parse the input as module"); panda::PandArg opParseOnly("parse-only", false, "Parse the input only"); panda::PandArg opDumpAst("dump-ast", false, "Dump the parsed AST"); @@ -64,6 +64,8 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg opSizeStat("dump-size-stat", false, "Dump size statistics"); panda::PandArg outputFile("output", "", "Compiler binary output (.abc)"); panda::PandArg logLevel("log-level", "error", "Log-level"); + panda::PandArg stdLib("stdlib", "", "Path to standard library"); + panda::PandArg genStdLib("gen-stdlib", false, "Gen standard library"); // tail arguments panda::PandArg inputFile("input", "", "input file"); @@ -83,6 +85,8 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&inputExtension); argparser_->Add(&outputFile); argparser_->Add(&logLevel); + argparser_->Add(&stdLib); + argparser_->Add(&genStdLib); argparser_->PushBackTail(&inputFile); argparser_->EnableTail(); @@ -137,8 +141,10 @@ bool Options::Parse(int argc, const char **argv) extension_ = es2panda::ScriptExtension::TS; } else if (extension == "as") { extension_ = es2panda::ScriptExtension::AS; + } else if (extension == "ets") { + extension_ = es2panda::ScriptExtension::ETS; } else { - errorMsg_ = "Invalid extension (available options: js, ts, as)"; + errorMsg_ = "Invalid extension (available options: js, ts, as, ets)"; return false; } } @@ -163,6 +169,8 @@ bool Options::Parse(int argc, const char **argv) compilerOptions_.dumpDebugInfo = opDumpDebugInfo.GetValue(); compilerOptions_.isDebug = opDebugInfo.GetValue(); compilerOptions_.parseOnly = opParseOnly.GetValue(); + compilerOptions_.stdLib_ = stdLib.GetValue(); + compilerOptions_.genStdLib = genStdLib.GetValue(); return true; } diff --git a/aot/options.h b/aot/options.h index a3d7d2f0a..d463599cd 100644 --- a/aot/options.h +++ b/aot/options.h @@ -18,7 +18,6 @@ #include "plugins/ecmascript/es2panda/es2panda.h" -#include #include #include #include @@ -30,10 +29,10 @@ class PandaArg; namespace panda::es2panda::aot { enum class OptionFlags : uint32_t { - DEFAULT = 0x0U, - PARSE_ONLY = 0x1U, - PARSE_MODULE = 0x2U, - SIZE_STAT = 0x4U, + DEFAULT = 0U, + PARSE_ONLY = 1U << 0U, + PARSE_MODULE = 1U << 1U, + SIZE_STAT = 1U << 2U, }; inline std::underlying_type_t operator&(OptionFlags a, OptionFlags b) @@ -119,6 +118,11 @@ public: return (options_ & OptionFlags::SIZE_STAT) != 0; } + bool IsDynamic() const + { + return extension_ != es2panda::ScriptExtension::ETS; + } + private: es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS}; es2panda::CompilerOptions compilerOptions_ {}; diff --git a/binder/ASBinder.cpp b/binder/ASBinder.cpp new file mode 100644 index 000000000..8a58d1c3e --- /dev/null +++ b/binder/ASBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ASBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/ASBinder.h b/binder/ASBinder.h new file mode 100644 index 000000000..ac6c8b22e --- /dev/null +++ b/binder/ASBinder.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_AS_BINDER_H +#define ES2PANDA_BINDER_AS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class ASBinder : public Binder { +public: + explicit ASBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(ASBinder); + NO_MOVE_SEMANTIC(ASBinder); + ~ASBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::AS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::BINDINGS; + } + + void IdentifierAnalysis() override {} + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/ETSBinder.cpp b/binder/ETSBinder.cpp new file mode 100644 index 000000000..dbc39a9e2 --- /dev/null +++ b/binder/ETSBinder.cpp @@ -0,0 +1,740 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ETSBinder.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/functionDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsPrimitiveType.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReferencePart.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsMethodReferenceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsScript.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumMember.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importSpecifier.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::binder { + +void ETSBinder::IdentifierAnalysis() +{ + ASSERT(Program()->Ast()); + ASSERT(GetScope() == TopScope()); + ASSERT(VarScope() == TopScope()); + + recordTable_->SetProgram(Program()); + globalRecordTable_.SetClassDefinition(Program()->GlobalClass()); + externalRecordTable_.insert({Program(), &globalRecordTable_}); + + BuildProgram(); + + ASSERT(globalRecordTable_.ClassDefinition() == Program()->GlobalClass()); +} + +void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef) +{ + auto *iter = typeRef->Part(); + + while (iter != nullptr) { + if (iter->TypeParams() == nullptr) { + iter = iter->Previous(); + continue; + } + + for (auto *it : iter->TypeParams()->Params()) { + if (!it->IsETSTypeReference()) { + continue; + } + + ResolveReference(it); + } + + iter = iter->Previous(); + } +} + +void ETSBinder::LookupTypeReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + auto *iter = GetScope(); + + while (iter != nullptr) { + ScopeFindResult res = iter->Find(name, ResolveBindingOptions::DECLARATION); + + if (res.variable == nullptr) { + break; + } + + switch (res.variable->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: + case ir::AstNodeType::TS_TYPE_PARAMETER: + case ir::AstNodeType::TS_ENUM_DECLARATION: { + ident->SetVariable(res.variable); + return; + } + default: { + iter = iter->Parent(); + } + } + } + + ThrowUnresolvableType(ident->Start(), name); +} + +void ETSBinder::LookupIdentReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + ScopeFindResult res = GetScope()->Find(name, ResolveBindingOptions::ALL); + if (res.level != 0) { + ASSERT(res.variable != nullptr); + + auto *outerFunction = GetScope()->EnclosingVariableScope()->Node(); + + if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) && + !res.variable->IsGlobalVariable() && res.level > 1) { + ThrowInvalidCapture(ident->Start(), name); + } + + res.variable->SetLexical(res.scope); + } + + if (res.variable == nullptr) { + return; + } + + if (ident->IsReference() && res.variable->Declaration()->IsLetOrConstDecl() && + !res.variable->HasFlag(VariableFlags::INITIALIZED)) { + ThrowTDZ(ident->Start(), name); + } + + ident->SetVariable(res.variable); +} + +void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop) +{ + ResolveReferences(prop); +} + +void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl) +{ + ScopeFindResult res = GetScope()->Find(decl->Id()->Name()); + + ASSERT(res.variable && res.variable->Declaration()->IsInterfaceDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); + decl->Id()->SetVariable(res.variable); +} + +void ETSBinder::ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl) +{ + auto bctx = BoundContext(recordTable_, enumDecl); + auto enumScopeCtx = LexicalScope::Enter(this, enumDecl->Scope()); + + for (auto *member : enumDecl->Members()) { + ResolveReference(member); + } +} + +void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl) +{ + auto bctx = BoundContext(recordTable_, decl); + + for (auto *extend : decl->Extends()) { + ResolveReference(extend); + } + + auto scopeCtx = LexicalScope::Enter(this, decl->Scope()->AsClassScope()); + + for (auto *stmt : decl->Body()->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + + ResolveReference(stmt); + + auto fieldVar = ResolvePropertyReference(stmt->AsClassProperty(), decl->Scope()->AsClassScope()) + ->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + } + + for (auto *stmt : decl->Body()->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl) +{ + if (decl->TypeParams() != nullptr) { + auto typeParamScopeCtx = LexicalScope::Enter(this, decl->TypeParams()->Scope()); + ResolveReferences(decl->TypeParams()); + ResolveInterfaceDeclaration(decl); + return; + } + + ResolveInterfaceDeclaration(decl); +} + +void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef) +{ + if (methodDef->Function()->TypeParams() != nullptr) { + auto scopeCtx = LexicalScope::Enter(this, methodDef->Function()->TypeParams()->Scope()); + ResolveReferences(methodDef->Function()->TypeParams()); + ResolveMethodDefinition(methodDef); + return; + } + + ResolveMethodDefinition(methodDef); +} + +void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef) +{ + auto *func = methodDef->Function(); + ResolveReferences(methodDef); + + if (recordTable_->InterfaceDeclaration() != nullptr || methodDef->IsStatic() || func->IsStaticBlock()) { + return; + } + + auto paramScopeCtx = LexicalScope::Enter(this, func->Scope()->ParamScope()); + auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS); + thisParam->Declaration()->BindNode(thisParam_); +} + +void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr) +{ + ResolveReference(memberExpr->Object()); + + if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) { + ResolveReference(memberExpr->Property()); + } +} + +void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef) +{ + auto bctx = BoundContext(recordTable_, classDef); + + if (classDef->TypeParams() != nullptr) { + auto scopeCtx = LexicalScope::Enter(this, classDef->TypeParams()->Scope()); + ResolveReferences(classDef->TypeParams()); + BuildClassDefinitionImpl(classDef); + return; + } + + BuildClassDefinitionImpl(classDef); +} + +LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope) +{ + ResolveReferences(prop); + + if (prop->IsStatic()) { + return scope->StaticFieldScope(); + } + + return scope->InstanceFieldScope(); +} + +void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef) +{ + auto classCtx = LexicalScope::Enter(this, classDef->Scope()->AsClassScope()); + + if (classDef->Super() != nullptr) { + ResolveReference(classDef->Super()); + } + + for (auto *impl : classDef->Implements()) { + ResolveReference(impl); + } + + for (auto *stmt : classDef->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + + auto fieldVar = ResolvePropertyReference(stmt->AsClassProperty(), classDef->Scope()->AsClassScope()) + ->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + if (fieldVar->Declaration()->IsConstDecl() && stmt->AsClassProperty()->Value() == nullptr) { + fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED); + } + } + + for (auto *stmt : classDef->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void ETSBinder::AddLambdaFunctionThisParam(ir::ScriptFunction *func) +{ + auto paramScopeCtx = LexicalScope::Enter(this, func->Scope()->ParamScope()); + auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS); + thisParam->Declaration()->BindNode(thisParam_); + Functions().push_back(func->Scope()); +} + +void ETSBinder::AddInvokeFunctionThisParam(ir::ScriptFunction *func) +{ + auto paramScopeCtx = LexicalScope::Enter(this, func->Scope()->ParamScope()); + auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS); + thisParam->Declaration()->BindNode(thisParam_); +} + +void ETSBinder::BuildMethodReferenceExpression(ir::ETSMethodReferenceExpression *methodRef) +{ + ResolveReferences(methodRef); + + auto bctx = BoundContext(recordTable_, methodRef->LambdaObject()); + AddLambdaFunctionThisParam(methodRef->LambdaObject()->Body()[1]->AsMethodDefinition()->Function()); + AddLambdaFunctionThisParam(methodRef->LambdaObject()->Body()[2]->AsMethodDefinition()->Function()); + + LambdaObjects().push_back(methodRef); +} + +void ETSBinder::BuildFunctionType(ir::ETSFunctionType *funcType) +{ + auto bctx = BoundContext(recordTable_, funcType->FunctionalInterface()); + + auto *invokeFunc = funcType->FunctionalInterface()->Body()->Body()[0]->AsMethodDefinition()->Function(); + auto *funcScope = invokeFunc->Scope(); + funcScope->BindName(recordTable_->RecordName()); + AddInvokeFunctionThisParam(invokeFunc); + + recordTable_->Signatures().push_back(funcScope); + FunctionalInterfaces().push_back(funcType); +} + +void ETSBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::ETS_TYPE_REFERENCE: { + auto *typeRef = childNode->AsETSTypeReference(); + ASSERT(typeRef->BaseName()->IsReference()); + LookupTypeReference(typeRef->BaseName()); + LookupTypeArgumentReferences(typeRef); + break; + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration()); + break; + } + case ir::AstNodeType::TS_ENUM_DECLARATION: { + ResolveEnumDeclaration(childNode->AsTSEnumDeclaration()); + break; + } + case ir::AstNodeType::EXPORT_NAMED_DECLARATION: { + break; + } + case ir::AstNodeType::IMPORT_DECLARATION: { + BuildImportDeclaration(childNode->AsImportDeclaration()); + break; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + BuildMemberExpression(childNode->AsMemberExpression()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + BuildMethodDefinition(childNode->AsMethodDefinition()); + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::ETS_METHOD_REFERENCE_EXPRESSION: { + BuildMethodReferenceExpression(childNode->AsETSMethodReferenceExpression()); + break; + } + case ir::AstNodeType::ETS_FUNCTION_TYPE: { + BuildFunctionType(childNode->AsETSFunctionType()); + break; + } + case ir::AstNodeType::DEFER_STATEMENT: { + GetScope()->AddFlag(ScopeFlags::DEFER_STMT); + ResolveReferences(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} + +bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc) +{ + auto *funcScope = scriptFunc->Scope(); + funcScope->BindName(recordTable_->RecordName()); + bool isExternal = recordTable_->IsExternal(); + + bool compilable = scriptFunc->Body() != nullptr && !isExternal; + + if (!compilable) { + recordTable_->Signatures().push_back(funcScope); + } + + if (isExternal) { + scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL); + } + + return compilable; +} + +void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const +{ + auto *funcScope = func->Scope(); + + std::stringstream ss; + ss << funcScope->Name() << compiler::Signatures::METHOD_SEPARATOR; + + const auto *signature = func->Signature(); + + if (func->IsStaticBlock()) { + ss << compiler::Signatures::CCTOR; + } else { + if (func->IsConstructor()) { + ss << compiler::Signatures::CTOR; + } else { + ss << util::Helpers::FunctionName(Allocator(), func); + } + } + + signature->ToAssemblerType(ss); + + util::UString internalName(ss.str(), Allocator()); + funcScope->BindInternalName(internalName.View()); +} + +void ETSBinder::FormLambdaName(util::UString &name, const util::StringView &signature, bool addSeparator) +{ + if (addSeparator) { + name.Append(compiler::Signatures::LAMBDA_SEPARATOR); + } + + std::string replaced = std::string(signature.Utf8()); + std::replace(replaced.begin(), replaced.end(), '.', '-'); + std::replace(replaced.begin(), replaced.end(), ':', '-'); + std::replace(replaced.begin(), replaced.end(), ';', '-'); + replaced.append("0"); + name.Append(replaced); +} + +void ETSBinder::BuildLambdaObjectName(ir::ETSMethodReferenceExpression *methodRef) +{ + auto *lambdaClass = methodRef->LambdaObject(); + + util::UString lambdaObjectName(lambdaClass->Ident()->Name(), Allocator()); + FormLambdaName(lambdaObjectName, methodRef->ComputedSignature()->InternalName()); + lambdaClass->Ident()->SetName(lambdaObjectName.View()); + lambdaClass->SetInternalName(lambdaClass->Ident()->Name()); + + util::StringView assemblerName(lambdaClass->Ident()->Name()); + auto *program = static_cast(methodRef->GetTopStatement())->Program(); + util::StringView prefix = program->GetPackageName(); + prefix = program->GetPackageName(); + + if (!prefix.Empty()) { + util::UString fullPath(prefix, Allocator()); + fullPath.Append('.'); + fullPath.Append(assemblerName); + assemblerName = fullPath.View(); + } + + checker::ETSObjectType *lambdaObject = lambdaClass->TsType()->AsETSObjectType(); + lambdaObject->SetName(lambdaClass->Ident()->Name()); + lambdaObject->SetAssemblerName(assemblerName); + + auto *ctorFunc = lambdaClass->Body()[1]->AsMethodDefinition()->Function(); + auto *ctorFuncScope = ctorFunc->Scope(); + ctorFuncScope->BindName(lambdaClass->Ident()->Name()); + + util::UString ctorInternalName(ctorFuncScope->Name(), Allocator()); + ctorInternalName.Append(compiler::Signatures::METHOD_SEPARATOR); + ctorInternalName.Append(compiler::Signatures::CTOR); + std::stringstream ctorSignatureSs; + ctorFunc->Signature()->ToAssemblerType(ctorSignatureSs); + ctorInternalName.Append(ctorSignatureSs.str()); + ctorFuncScope->BindInternalName(ctorInternalName.View()); + + auto *invokeFunc = lambdaClass->Body()[2]->AsMethodDefinition()->Function(); + auto *invokeFuncScope = invokeFunc->Scope(); + invokeFuncScope->BindName(lambdaClass->Ident()->Name()); + + util::UString invokeInternalName(invokeFuncScope->Name(), Allocator()); + invokeInternalName.Append(compiler::Signatures::METHOD_SEPARATOR); + invokeInternalName.Append(invokeFunc->Id()->Name()); + std::stringstream invokeSinatureSs; + invokeFunc->Signature()->ToAssemblerType(invokeSinatureSs); + invokeInternalName.Append(invokeSinatureSs.str()); + invokeFuncScope->BindInternalName(invokeInternalName.View()); +} + +void ETSBinder::BuildFunctionalInterfaceName(ir::ETSFunctionType *funcType) +{ + auto *functionalInterface = funcType->FunctionalInterface(); + auto *invokeFunc = functionalInterface->Body()->Body()[0]->AsMethodDefinition()->Function(); + util::UString functionalInterfaceName(functionalInterface->Id()->Name(), Allocator()); + std::stringstream ss; + invokeFunc->Signature()->ToAssemblerType(ss); + util::StringView signatureName(ss.str()); + FormLambdaName(functionalInterfaceName, signatureName, false); + functionalInterface->Id()->SetName(functionalInterfaceName.View()); + functionalInterface->SetInternalName(functionalInterface->Id()->Name()); + + util::StringView assemblerName(functionalInterface->Id()->Name()); + auto *program = static_cast(funcType->GetTopStatement())->Program(); + util::StringView prefix = program->GetPackageName(); + prefix = program->GetPackageName(); + + if (!prefix.Empty()) { + util::UString fullPath(prefix, Allocator()); + fullPath.Append('.'); + fullPath.Append(assemblerName); + assemblerName = fullPath.View(); + } + + checker::ETSObjectType *functionalInterfaceType = functionalInterface->TsType()->AsETSObjectType(); + functionalInterfaceType->SetName(functionalInterface->Id()->Name()); + functionalInterfaceType->SetAssemblerName(assemblerName); + + auto *invokeFuncScope = invokeFunc->Scope(); + invokeFuncScope->BindName(functionalInterface->Id()->Name()); + + util::UString invokeInternalName(invokeFuncScope->Name(), Allocator()); + invokeInternalName.Append(compiler::Signatures::METHOD_SEPARATOR); + invokeInternalName.Append(invokeFunc->Id()->Name()); + std::stringstream invokeSinatureSs; + invokeFunc->Signature()->ToAssemblerType(invokeSinatureSs); + invokeInternalName.Append(invokeSinatureSs.str()); + invokeFuncScope->BindInternalName(invokeInternalName.View()); +} + +void ETSBinder::InitImplicitThisParam() +{ + thisParam_ = Allocator()->New("this", Allocator()); +} + +void ETSBinder::BuildProgram() +{ + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + BuildExternalProgram(extProg); + } + } + + for (auto *defaultImport : defaultImports_) { + BuildImportDeclaration(defaultImport); + } + + auto &stmts = Program()->Ast()->Statements(); + const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { + return stmt->IsClassDeclaration() && + stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL); + }); + + if (etsGlobal != stmts.end()) { + const auto begin = stmts.begin(); + const size_t index = std::distance(begin, etsGlobal); + std::rotate(begin, begin + index, begin + index + 1); + } + + for (auto *stmt : stmts) { + ResolveReference(stmt); + } +} + +void ETSBinder::BuildExternalProgram(parser::Program *extProgram) +{ + auto *savedProgram = Program(); + auto *savedrecordTable = recordTable_; + auto *savedTopScope_ = TopScope(); + + auto flags = Program()->Binder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL; + auto *extRecordTable = Allocator()->New(Allocator(), extProgram, flags); + externalRecordTable_.insert({extProgram, extRecordTable}); + + ResetTopScope(extProgram->GlobalScope()); + recordTable_ = extRecordTable; + SetProgram(extProgram); + + BuildProgram(); + + SetProgram(savedProgram); + recordTable_ = savedrecordTable; + ResetTopScope(savedTopScope_); +} + +void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance) +{ + BoundContext boundCtx(recordTable_, classInstance->ClassDefinition()); + ResolveReference(classInstance->GetTypeRef()); + + for (auto *arg : classInstance->GetArguments()) { + ResolveReference(arg); + } + + if (classInstance->ClassDefinition() == nullptr) { + return; + } + + ResolveReference(classInstance->ClassDefinition()); +} + +void ETSBinder::BuildImportDeclaration(ir::ImportDeclaration *decl) +{ + auto *specifier = decl->Specifiers().front()->AsImportSpecifier(); + + if (!specifier->Imported()->IsTSQualifiedName()) { + return; + } + + auto *importName = specifier->Imported()->AsTSQualifiedName(); + util::StringView fullPath = importName->ToString(Allocator()); + + if (*fullPath.Utf8().rbegin() == Binder::STAR_IMPORT.front()) { + HandleStarImport(importName, fullPath); + return; + } + + util::StringView packageName = importName->BaseToString(Allocator()); + + if (packageName == Program()->GetPackageName()) { + return; + } + + util::StringView imported = importName->ResolveLeftMostQualifiedName()->Right()->Name(); + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto &packageNameSpace = res->second.front()->GlobalScope()->Bindings(); + auto bindingRes = packageNameSpace.find(imported); + + if (bindingRes == packageNameSpace.end()) { + ThrowError(importName->Start(), "Cannot find import"); + } + + auto *var = bindingRes->second; + util::StringView localName = imported; + + if (specifier->Local() != nullptr) { + localName = specifier->Local()->Name(); + } + + if (!TopScope()->Bindings().insert({localName, var}).second) { + ThrowError(importName->Start(), "Import already exists."); + } +} + +void ETSBinder::HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath) +{ + // Cut ".*" + util::StringView packageName = fullPath.Substr(0, fullPath.Length() - 2); + + if (packageName == Program()->GetPackageName()) { + return; + } + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto *packageGlobalScope = res->second.front()->GlobalScope(); + + for (auto [bindingName, var] : packageGlobalScope->Bindings()) { + if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) { + auto *classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition(); + ImportGlobalProperties(classDef); + continue; + } + + auto insRes = TopScope()->Bindings().insert({bindingName, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(importName->Start(), "Import already exists."); + } + } + } +} + +void ETSBinder::ImportGlobalProperties(ir::ClassDefinition *classDef) +{ + auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()->AsClassScope()); + + for (auto *prop : classDef->Body()) { + auto *classElement = prop->AsClassElement(); + + if (classElement->IsClassStaticBlock()) { + continue; + } + + ASSERT(classElement->IsStatic()); + auto &name = classElement->Id()->Name(); + auto *var = scopeCtx.GetScope()->FindLocal(name, ResolveBindingOptions::ALL); + ASSERT(var); + + auto insRes = TopScope()->Bindings().insert({name, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(classElement->Id()->Start(), "Import already exists."); + } + } + } +} + +} // namespace panda::es2panda::binder diff --git a/binder/ETSBinder.h b/binder/ETSBinder.h new file mode 100644 index 000000000..edcb922f6 --- /dev/null +++ b/binder/ETSBinder.h @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_ETS_BINDER_H +#define ES2PANDA_BINDER_ETS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" +#include "plugins/ecmascript/es2panda/binder/recordTable.h" + +namespace panda::es2panda::binder { +class ETSBinder : public TypedBinder { +public: + explicit ETSBinder(ArenaAllocator *allocator) + : TypedBinder(allocator), + globalRecordTable_(allocator, Program(), RecordTableFlags::NONE), + recordTable_(&globalRecordTable_), + externalRecordTable_(allocator->Adapter()), + defaultImports_(allocator->Adapter()) + { + InitImplicitThisParam(); + } + + NO_COPY_SEMANTIC(ETSBinder); + NO_MOVE_SEMANTIC(ETSBinder); + ~ETSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::ETS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::BINDINGS; + } + + RecordTable *GetRecordTable() + { + return recordTable_; + } + + const RecordTable *GetRecordTable() const + { + return recordTable_; + } + + RecordTable *GetGlobalRecordTable() + { + return &globalRecordTable_; + } + + const RecordTable *GetGlobalRecordTable() const + { + return &globalRecordTable_; + } + + ArenaUnorderedMap &GetExternalRecordTable() + { + return externalRecordTable_; + } + + const ArenaUnorderedMap &GetExternalRecordTable() const + { + return externalRecordTable_; + } + + void HandleCustomNodes(ir::AstNode *childNode) override; + + void IdentifierAnalysis() override; + void BuildClassDefinition(ir::ClassDefinition *classDef) override; + void BuildClassProperty(const ir::ClassProperty *prop) override; + void LookupIdentReference(ir::Identifier *ident) override; + bool BuildInternalName(ir::ScriptFunction *scriptFunc) override; + + void LookupTypeReference(ir::Identifier *ident); + void LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef); + void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl); + void BuildMemberExpression(ir::MemberExpression *memberExpr); + void BuildMethodDefinition(ir::MethodDefinition *methodDef); + void BuildImportDeclaration(ir::ImportDeclaration *decl); + void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance); + void BuildMethodReferenceExpression(ir::ETSMethodReferenceExpression *methodRef); + void BuildFunctionType(ir::ETSFunctionType *funcType); + + void ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl); + void ResolveMethodDefinition(ir::MethodDefinition *methodDef); + LocalScope *ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope); + void ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl); + void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl); + void BuildExternalProgram(parser::Program *extProgram); + void BuildProgram(); + + void BuildFunctionName(const ir::ScriptFunction *func) const; + void AddLambdaFunctionThisParam(ir::ScriptFunction *func); + void AddInvokeFunctionThisParam(ir::ScriptFunction *func); + void BuildLambdaObjectName(ir::ETSMethodReferenceExpression *methodRef); + void FormLambdaName(util::UString &name, const util::StringView &signature, bool addSeparator = true); + void BuildFunctionalInterfaceName(ir::ETSFunctionType *funcType); + + void SetDefaultImports(ArenaVector defaultImports) + { + defaultImports_ = std::move(defaultImports); + } + + static constexpr std::string_view DEFAULT_IMPORT_SOURCE_FILE = ".ets"; + static constexpr std::string_view DEFAULT_IMPORT_SOURCE = R"( +import std.containers.*; +import std.core.*; +import std.math.*; +import std.time.*; +)"; + +private: + void BuildClassDefinitionImpl(ir::ClassDefinition *classDef); + void InitImplicitThisParam(); + void HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath); + void ImportGlobalProperties(ir::ClassDefinition *classDef); + + RecordTable globalRecordTable_; + RecordTable *recordTable_; + ArenaUnorderedMap externalRecordTable_; + ArenaVector defaultImports_; + ir::Identifier *thisParam_ {}; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/JSBinder.cpp b/binder/JSBinder.cpp new file mode 100644 index 000000000..1e1ead592 --- /dev/null +++ b/binder/JSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/JSBinder.h b/binder/JSBinder.h new file mode 100644 index 000000000..af3178f4f --- /dev/null +++ b/binder/JSBinder.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_JS_BINDER_H +#define ES2PANDA_BINDER_JS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class JSBinder : public Binder { +public: + explicit JSBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(JSBinder); + NO_MOVE_SEMANTIC(JSBinder); + ~JSBinder() = default; + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TSBinder.cpp b/binder/TSBinder.cpp new file mode 100644 index 000000000..c33d7d0ca --- /dev/null +++ b/binder/TSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/TSBinder.h b/binder/TSBinder.h new file mode 100644 index 000000000..30b115829 --- /dev/null +++ b/binder/TSBinder.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_TS_BINDER_H +#define ES2PANDA_BINDER_TS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" + +namespace panda::es2panda::binder { +class TSBinder : public TypedBinder { +public: + explicit TSBinder(ArenaAllocator *allocator) : TypedBinder(allocator) {} + + NO_COPY_SEMANTIC(TSBinder); + NO_MOVE_SEMANTIC(TSBinder); + ~TSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::TS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::ALL; + } + +protected: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TypedBinder.cpp b/binder/TypedBinder.cpp new file mode 100644 index 000000000..97078df08 --- /dev/null +++ b/binder/TypedBinder.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TypedBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" + +namespace panda::es2panda::binder { + +void TypedBinder::BuildSignatureDeclarationBaseParams(ir::AstNode *typeNode) +{ + if (typeNode == nullptr) { + return; + } + + Scope *scope = nullptr; + + switch (typeNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: { + scope = typeNode->AsTSFunctionType()->Scope(); + break; + } + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { + scope = typeNode->AsTSConstructorType()->Scope(); + break; + } + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + scope = typeNode->AsTSSignatureDeclaration()->Scope(); + break; + } + case ir::AstNodeType::TS_METHOD_SIGNATURE: { + scope = typeNode->AsTSMethodSignature()->Scope(); + break; + } + default: { + ResolveReference(typeNode); + return; + } + } + + ASSERT(scope && scope->IsFunctionParamScope()); + + auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); + ResolveReferences(typeNode); +} + +void TypedBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: + case ir::AstNodeType::TS_METHOD_SIGNATURE: + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + BuildSignatureDeclarationBaseParams(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} +} // namespace panda::es2panda::binder diff --git a/binder/TypedBinder.h b/binder/TypedBinder.h new file mode 100644 index 000000000..468e611eb --- /dev/null +++ b/binder/TypedBinder.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_TYPED_BINDER_H +#define ES2PANDA_BINDER_TYPED_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class TypedBinder : public Binder { +public: + explicit TypedBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(TypedBinder); + NO_MOVE_SEMANTIC(TypedBinder); + ~TypedBinder() = default; + +protected: + void HandleCustomNodes(ir::AstNode *childNode) override; + void BuildSignatureDeclarationBaseParams([[maybe_unused]] ir::AstNode *typeNode) override; +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/binder.cpp b/binder/binder.cpp index 682ac0684..07bb950a3 100644 --- a/binder/binder.cpp +++ b/binder/binder.cpp @@ -16,6 +16,7 @@ #include "binder.h" #include "plugins/ecmascript/es2panda/binder/privateBinding.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/tsBinding.h" @@ -24,12 +25,15 @@ #include "plugins/ecmascript/es2panda/ir/astNode.h" #include "plugins/ecmascript/es2panda/ir/base/catchClause.h" #include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" #include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" #include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/objectExpression.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" @@ -42,10 +46,17 @@ #include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/module/exportNamedDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" #include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" namespace panda::es2panda::binder { void Binder::InitTopScope() @@ -60,36 +71,67 @@ void Binder::InitTopScope() varScope_ = topScope_; } -ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param) +std::tuple Binder::AddParamDecl(ir::AstNode *param) { ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope()); - auto [decl, node] = static_cast(scope_)->AddParamDecl(Allocator(), param); + auto [decl, node, var] = static_cast(scope_)->AddParamDecl(Allocator(), param); if (node == nullptr) { - return decl; + return {decl, var}; } ThrowRedeclaration(node->Start(), decl->Name()); } -void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) +void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const { - lexer::LineIndex index(program_->SourceCode()); - lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; ss << "Variable '" << name << "' has already been declared."; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find variable '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find type '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Variable '" << name << "' is accessed before it's initialization."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot capture variable'" << name << "'."; + ThrowError(pos, ss.str()); } void Binder::ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Private field '" << name << "' must be declared in an enclosing class"; + + ThrowError(pos, ss.str()); +} + +void Binder::ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const { lexer::LineIndex index(program_->SourceCode()); lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; - ss << "Private field '" << name << "' must be declared in an enclosing class"; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + throw Error(ErrorType::SYNTAX, program_->SourceFile().Utf8(), msg, loc.line, loc.col); } void Binder::IdentifierAnalysis() @@ -98,11 +140,10 @@ void Binder::IdentifierAnalysis() ASSERT(scope_ == topScope_); ASSERT(varScope_ == topScope_); - if (program_->Extension() == ScriptExtension::AS) { - return; - } + functionScopes_.push_back(topScope_); + topScope_->BindName(MAIN); + topScope_->BindInternalName(BuildFunctionName(MAIN, 0)); - BuildFunction(topScope_, "main"); topScope_->CheckDirectEval(compilerCtx_); ResolveReferences(program_->Ast()); @@ -150,7 +191,7 @@ void Binder::InstantiateArguments() scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable}); } - scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS); + scope->AddFlag(ScopeFlags::USE_ARGS); break; } @@ -167,7 +208,7 @@ void Binder::PropagateDirectEval() const VariableScope *scope = iter->IsFunctionParamScope() ? iter->AsFunctionParamScope()->GetFunctionScope() : iter->EnclosingVariableScope(); - scope->AddFlag(VariableScopeFlags::NO_REG_STORE); + scope->AddFlag(ScopeFlags::NO_REG_STORE); iter = iter->Parent(); } while (iter != nullptr); } @@ -197,16 +238,20 @@ void Binder::InstantiatePrivateContext(const ir::Identifier *ident) const void Binder::LookupIdentReference(ir::Identifier *ident) { + if (!ident->IsReference()) { + return; + } + if (ident->Name().Is(FUNCTION_ARGUMENTS)) { InstantiateArguments(); } - if (ident->IsPrivate()) { + if (ident->IsPrivateIdent()) { InstantiatePrivateContext(ident); return; } - ScopeFindResult res = scope_->Find(ident->Name(), bindingOptions_); + ScopeFindResult res = scope_->Find(ident->Name(), BindingOptions()); if (res.level != 0) { ASSERT(res.variable); res.variable->SetLexical(res.scope); @@ -223,32 +268,29 @@ void Binder::LookupIdentReference(ir::Identifier *ident) ident->SetVariable(res.variable); } -void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +util::StringView Binder::BuildFunctionName(util::StringView name, uint32_t idx) { - uint32_t idx = functionScopes_.size(); - functionScopes_.push_back(funcScope); - std::stringstream ss; ss << "func_" << name << "_" << std::to_string(idx); util::UString internalName(ss.str(), Allocator()); - funcScope->BindName(name, internalName.View()); + return internalName.View(); } -void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc) +bool Binder::BuildInternalName(ir::ScriptFunction *scriptFunc) { - if (scriptFunc->IsArrow()) { - VariableScope *outerVarScope = outerScope->EnclosingVariableScope(); - outerVarScope->AddFlag(VariableScopeFlags::INNER_ARROW); - } + auto *funcScope = scriptFunc->Scope(); + auto name = util::Helpers::FunctionName(Allocator(), scriptFunc); - BuildFunction(scope_->AsFunctionScope(), util::Helpers::FunctionName(Allocator(), scriptFunc)); + uint32_t idx = functionScopes_.size(); + funcScope->BindName(name); + funcScope->BindInternalName(BuildFunctionName(name, idx)); + + return !scriptFunc->IsOverload(); } -void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::BuildVarDeclaratorId(ir::AstNode *childNode) { - childNode->SetParent(parent); - switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); @@ -259,12 +301,8 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } auto *variable = scope_->FindLocal(name); - - if (Program()->Extension() == ScriptExtension::TS) { - ident->SetVariable(variable); - BuildTSSignatureDeclarationBaseParams(ident->TypeAnnotation()); - } - + ident->SetVariable(variable); + BuildSignatureDeclarationBaseParams(ident->TypeAnnotation()); variable->AddFlag(VariableFlags::INITIALIZED); break; } @@ -272,34 +310,34 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN auto *objPattern = childNode->AsObjectPattern(); for (auto *prop : objPattern->Properties()) { - BuildVarDeclaratorId(childNode, prop); + BuildVarDeclaratorId(prop); } - BuildTSSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); break; } case ir::AstNodeType::ARRAY_PATTERN: { auto *arrayPattern = childNode->AsArrayPattern(); for (auto *element : childNode->AsArrayPattern()->Elements()) { - BuildVarDeclaratorId(childNode, element); + BuildVarDeclaratorId(element); } - BuildTSSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); break; } case ir::AstNodeType::ASSIGNMENT_PATTERN: { - ResolveReference(childNode, childNode->AsAssignmentPattern()->Right()); - BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left()); + ResolveReference(childNode->AsAssignmentPattern()->Right()); + BuildVarDeclaratorId(childNode->AsAssignmentPattern()->Left()); break; } case ir::AstNodeType::PROPERTY: { - ResolveReference(childNode, childNode->AsProperty()->Key()); - BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value()); + ResolveReference(childNode->AsProperty()->Key()); + BuildVarDeclaratorId(childNode->AsProperty()->Value()); break; } case ir::AstNodeType::REST_ELEMENT: { - BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument()); + BuildVarDeclaratorId(childNode->AsRestElement()->Argument()); break; } default: @@ -307,86 +345,67 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } } -void Binder::BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode) +void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) { - if (typeNode == nullptr) { + if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { + ResolveReferences(varDecl); return; } - Scope *scope = nullptr; - - switch (typeNode->Type()) { - case ir::AstNodeType::TS_FUNCTION_TYPE: { - scope = typeNode->AsTSFunctionType()->Scope(); - break; - } - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { - scope = typeNode->AsTSConstructorType()->Scope(); - break; - } - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - scope = typeNode->AsTSSignatureDeclaration()->Scope(); - break; - } - case ir::AstNodeType::TS_METHOD_SIGNATURE: { - scope = typeNode->AsTSMethodSignature()->Scope(); - break; - } - default: { - ResolveReferences(typeNode); - return; - } + if (varDecl->Init()) { + ResolveReference(varDecl->Init()); } - ASSERT(scope && scope->IsFunctionParamScope()); + BuildVarDeclaratorId(varDecl->Id()); +} + +void Binder::BuildClassProperty(const ir::ClassProperty *prop) +{ + const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop); + auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); - ResolveReferences(typeNode); + ResolveReferences(prop); } -void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) +void Binder::InitializeClassBinding(ir::ClassDefinition *classDef) { - if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { - ResolveReferences(varDecl); - return; - } + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - if (varDecl->Init() != nullptr) { - ResolveReference(varDecl, varDecl->Init()); - } + ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); +} + +void Binder::InitializeClassIdent(ir::ClassDefinition *classDef) +{ + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - BuildVarDeclaratorId(varDecl, varDecl->Id()); + ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); } void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassBinding(classDef); } auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); if (classDef->Super() != nullptr) { - ResolveReference(classDef, classDef->Super()); + ResolveReference(classDef->Super()); } Variable *variable = scope_->FindLocal(classDef->PrivateId()); variable->AddFlag(VariableFlags::INITIALIZED); if (classDef->Ident() != nullptr) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassIdent(classDef); } - ResolveReference(classDef, classDef->Ctor()); + ResolveReference(classDef->Ctor()); for (auto *stmt : classDef->Body()) { - ResolveReference(classDef, stmt); + ResolveReference(stmt); } } @@ -397,35 +416,35 @@ void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt) auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); if (forUpdateStmt->Init() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Init()); + ResolveReference(forUpdateStmt->Init()); } if (forUpdateStmt->Update() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Update()); + ResolveReference(forUpdateStmt->Update()); } auto loopCtx = LexicalScope::Enter(this, loopScope); if (forUpdateStmt->Test() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Test()); + ResolveReference(forUpdateStmt->Test()); } - ResolveReference(forUpdateStmt, forUpdateStmt->Body()); + ResolveReference(forUpdateStmt->Body()); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } -void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body) +void Binder::BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, + ir::Statement *body) { auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); - ResolveReference(parent, right); - ResolveReference(parent, left); + ResolveReference(right); + ResolveReference(left); auto loopCtx = LexicalScope::Enter(this, loopScope); - ResolveReference(parent, body); + ResolveReference(body); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } @@ -433,81 +452,98 @@ void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt) { if (catchClauseStmt->Param() != nullptr) { auto paramScopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()->ParamScope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Param()); + ResolveReference(catchClauseStmt->Param()); } auto scopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Body()); + ResolveReference(catchClauseStmt->Body()); +} + +void Binder::AddCompilableFunction(ir::ScriptFunction *func) +{ + if (func->IsArrow()) { + VariableScope *outerVarScope = scope_->EnclosingVariableScope(); + outerVarScope->AddFlag(ScopeFlags::INNER_ARROW); + } + + AddCompilableFunctionScope(func->Scope()); +} + +void Binder::AddCompilableFunctionScope(binder::FunctionScope *funcScope) +{ + functionScopes_.push_back(funcScope); } -void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::VisitScriptFunction(ir::ScriptFunction *func) { - childNode->SetParent(parent); + auto *funcScope = func->Scope(); + { + auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); + + for (auto *param : func->Params()) { + ResolveReference(param); + } + } + + if (func->ReturnTypeAnnotation()) { + ResolveReference(func->ReturnTypeAnnotation()); + } + + if (!BuildInternalName(func)) { + return; + } + + AddCompilableFunction(func); + + auto scopeCtx = LexicalScope::Enter(this, funcScope); + + if (func->Body()) { + ResolveReference(func->Body()); + } +} + +void Binder::VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func) +{ + if (func->TypeParams()) { + auto typeParamScopeCtx = LexicalScope::Enter(this, func->TypeParams()->Scope()); + VisitScriptFunction(func); + return; + } + + VisitScriptFunction(func); +} + +void Binder::ResolveReference(ir::AstNode *childNode) +{ switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); - if (ident->IsReference()) { - LookupIdentReference(ident); - } - + LookupIdentReference(ident); ResolveReferences(childNode); break; } case ir::AstNodeType::SUPER_EXPRESSION: { VariableScope *varScope = scope_->EnclosingVariableScope(); - varScope->AddFlag(VariableScopeFlags::USE_SUPER); - + varScope->AddFlag(ScopeFlags::USE_SUPER); ResolveReferences(childNode); break; } case ir::AstNodeType::SCRIPT_FUNCTION: { - auto *scriptFunc = childNode->AsScriptFunction(); - auto *funcScope = scriptFunc->Scope(); - - auto *outerScope = scope_; - - { - auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); - - for (auto *param : scriptFunc->Params()) { - ResolveReference(scriptFunc, param); - } - } - - if (Program()->Extension() == ScriptExtension::TS) { - if (scriptFunc->ReturnTypeAnnotation() != nullptr) { - ResolveReference(scriptFunc, scriptFunc->ReturnTypeAnnotation()); - } - - if (scriptFunc->IsOverload()) { - break; - } - } - - auto scopeCtx = LexicalScope::Enter(this, funcScope); - - BuildScriptFunction(outerScope, scriptFunc); - - ResolveReference(scriptFunc, scriptFunc->Body()); + VisitScriptFunctionWithPotentialTypeParams(childNode->AsScriptFunction()); break; } case ir::AstNodeType::VARIABLE_DECLARATOR: { BuildVarDeclarator(childNode->AsVariableDeclarator()); - break; } case ir::AstNodeType::CLASS_DEFINITION: { BuildClassDefinition(childNode->AsClassDefinition()); - break; } case ir::AstNodeType::CLASS_PROPERTY: { - const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(childNode->AsClassProperty()); - auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - - ResolveReferences(childNode); + BuildClassProperty(childNode->AsClassProperty()); break; } case ir::AstNodeType::BLOCK_STATEMENT: { @@ -527,18 +563,18 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) { auto loopScopeCtx = LexicalScope::Enter(this, doWhileStatement->Scope()); - ResolveReference(doWhileStatement, doWhileStatement->Body()); + ResolveReference(doWhileStatement->Body()); } - ResolveReference(doWhileStatement, doWhileStatement->Test()); + ResolveReference(doWhileStatement->Test()); break; } case ir::AstNodeType::WHILE_STATEMENT: { auto *whileStatement = childNode->AsWhileStatement(); - ResolveReference(whileStatement, whileStatement->Test()); + ResolveReference(whileStatement->Test()); auto loopScopeCtx = LexicalScope::Enter(this, whileStatement->Scope()); - ResolveReference(whileStatement, whileStatement->Body()); + ResolveReference(whileStatement->Body()); break; } @@ -548,36 +584,29 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) } case ir::AstNodeType::FOR_IN_STATEMENT: { auto *forInStmt = childNode->AsForInStatement(); - BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); + BuildForInOfLoop(forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); break; } case ir::AstNodeType::FOR_OF_STATEMENT: { auto *forOfStmt = childNode->AsForOfStatement(); - BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); + BuildForInOfLoop(forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); break; } case ir::AstNodeType::CATCH_CLAUSE: { BuildCatchClause(childNode->AsCatchClause()); break; } - // TypeScript specific part - case ir::AstNodeType::TS_FUNCTION_TYPE: - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: - case ir::AstNodeType::TS_METHOD_SIGNATURE: - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - BuildTSSignatureDeclarationBaseParams(childNode); - break; - } default: { - ResolveReferences(childNode); + HandleCustomNodes(childNode); break; } } } + void Binder::ResolveReferences(const ir::AstNode *parent) { - parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); }); + parent->Iterate([this](auto *childNode) { ResolveReference(childNode); }); } LocalVariable *Binder::AddMandatoryParam(const std::string_view &name) @@ -601,7 +630,7 @@ void Binder::LookUpMandatoryReferences(const FunctionScope *funcScope, bool need LookupReference(MANDATORY_PARAM_NEW_TARGET); LookupReference(MANDATORY_PARAM_THIS); - if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) { + if (funcScope->HasFlag(ScopeFlags::USE_ARGS)) { LookupReference(FUNCTION_ARGUMENTS); } @@ -649,9 +678,9 @@ void Binder::AddMandatoryParams() bool lexicalFunctionObject {}; if (ctor != nullptr && util::Helpers::GetClassDefiniton(ctor)->Super() != nullptr && - funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) { - ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW)); - ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION); + funcScope->HasFlag(ScopeFlags::USE_SUPER)) { + ASSERT(ctor->Scope()->HasFlag(ScopeFlags::INNER_ARROW)); + ctor->Scope()->AddFlag(ScopeFlags::SET_LEXICAL_FUNCTION); lexicalFunctionObject = true; AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS); } else { diff --git a/binder/binder.h b/binder/binder.h index 2f67336d1..08adfded9 100644 --- a/binder/binder.h +++ b/binder/binder.h @@ -20,7 +20,11 @@ #include "plugins/ecmascript/es2panda/binder/variableFlags.h" #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "macros.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::parser { +class Program; +enum class ScriptKind; +} // namespace panda::es2panda::parser namespace panda::es2panda::ir { class AstNode; @@ -34,28 +38,28 @@ class ScriptFunction; class Statement; class VariableDeclarator; class TSFunctionType; +class ThisExpression; +class MemberExpression; +class ClassStaticBlock; } // namespace panda::es2panda::ir namespace panda::es2panda::binder { class Binder { public: - explicit Binder(parser::Program *program, ScriptExtension extension) - : program_(program), functionScopes_(Allocator()->Adapter()) + explicit Binder(ArenaAllocator *allocator) + : allocator_(allocator), + functionScopes_(allocator_->Adapter()), + lambdaObjects_(allocator_->Adapter()), + functionalInterfaces_(allocator_->Adapter()) { - if (extension == ScriptExtension::TS) { - bindingOptions_ = ResolveBindingOptions::ALL; - return; - } - - bindingOptions_ = ResolveBindingOptions::BINDINGS; } NO_COPY_SEMANTIC(Binder); - DEFAULT_MOVE_SEMANTIC(Binder); + NO_MOVE_SEMANTIC(Binder); ~Binder() = default; void InitTopScope(); - void IdentifierAnalysis(); + virtual void IdentifierAnalysis(); template T *AddDecl(const lexer::SourcePosition &pos, Args &&...args); @@ -63,7 +67,26 @@ public: template T *AddTsDecl(const lexer::SourcePosition &pos, Args &&...args); - ParameterDecl *AddParamDecl(const ir::AstNode *param); + template + std::tuple NewVarDecl(const lexer::SourcePosition &pos, Args &&...args); + + std::tuple AddParamDecl(ir::AstNode *param); + + void SetProgram(parser::Program *program) + { + program_ = program; + } + + parser::Program *Program() + { + return program_; + } + + const parser::Program *Program() const + { + ASSERT(program_); + return program_; + } void SetCompilerContext(compiler::CompilerContext *compilerContext) { @@ -77,17 +100,46 @@ public: return compilerCtx_; } + void SetGenStdLib(bool genStdLib) + { + genStdLib_ = genStdLib; + } + + bool IsGenStdLib() + { + return genStdLib_; + } + Scope *GetScope() const { return scope_; } + void ResetTopScope(GlobalScope *topScope) + { + ASSERT(topScope_ == scope_); + topScope_ = topScope; + varScope_ = topScope_; + scope_ = topScope_; + } + GlobalScope *TopScope() const { return topScope_; } - [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name); + VariableScope *VarScope() const + { + return varScope_; + } + + [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const; void PropagateDirectEval() const; @@ -96,7 +148,7 @@ public: inline ArenaAllocator *Allocator() const { - return program_->Allocator(); + return allocator_; } const ArenaVector &Functions() const @@ -104,14 +156,39 @@ public: return functionScopes_; } - ArenaVector Functions() + ArenaVector &Functions() { return functionScopes_; } - const parser::Program *Program() const + const ArenaVector &LambdaObjects() const { - return program_; + return lambdaObjects_; + } + + ArenaVector &LambdaObjects() + { + return lambdaObjects_; + } + + const ArenaVector &FunctionalInterfaces() const + { + return functionalInterfaces_; + } + + ArenaVector &FunctionalInterfaces() + { + return functionalInterfaces_; + } + + virtual ScriptExtension Extension() const + { + return ScriptExtension::JS; + } + + virtual ResolveBindingOptions BindingOptions() const + { + return ResolveBindingOptions::BINDINGS; } static constexpr std::string_view FUNCTION_ARGUMENTS = "arguments"; @@ -127,9 +204,11 @@ public: static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t"; static constexpr std::string_view LEXICAL_CONTEXT_PARAM = "=eval"; + static constexpr std::string_view MAIN = "main"; static constexpr uint32_t LEXICAL_CONTEXT_PARAM_REG = MANDATORY_PARAMS_NUMBER; + static constexpr std::string_view STAR_IMPORT = "*"; -private: +protected: template using MandatoryParams = std::array; @@ -150,33 +229,48 @@ private: template void AddMandatoryParams(const MandatoryParams ¶ms); void AddMandatoryParams(); - void BuildFunction(FunctionScope *funcScope, util::StringView name); - void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc); - void BuildClassDefinition(ir::ClassDefinition *classDef); void LookupReference(const util::StringView &name); void InstantiateArguments(); void InstantiatePrivateContext(const ir::Identifier *ident) const; void BuildVarDeclarator(ir::VariableDeclarator *varDecl); - void BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode); + void BuildVarDeclaratorId(ir::AstNode *childNode); void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt); - void BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body); + void BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, ir::Statement *body); void BuildCatchClause(ir::CatchClause *catchClauseStmt); - void LookupIdentReference(ir::Identifier *ident); - void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode); + void ResolveReference(ir::AstNode *childNode); void ResolveReferences(const ir::AstNode *parent); + void VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func); + void VisitScriptFunction(ir::ScriptFunction *func); + util::StringView BuildFunctionName(util::StringView name, uint32_t idx); - // TypeScript specific functions - void BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode); - [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + void AddCompilableFunction(ir::ScriptFunction *func); + void AddCompilableFunctionScope(binder::FunctionScope *funcScope); + void InitializeClassBinding(ir::ClassDefinition *classDef); + void InitializeClassIdent(ir::ClassDefinition *classDef); + + virtual void LookupIdentReference(ir::Identifier *ident); + virtual void HandleCustomNodes(ir::AstNode *childNode) + { + ResolveReferences(childNode); + } + virtual void BuildSignatureDeclarationBaseParams([[maybe_unused]] ir::AstNode *typeNode) {}; + virtual void BuildClassDefinition(ir::ClassDefinition *classDef); + virtual void BuildClassProperty(const ir::ClassProperty *prop); + virtual bool BuildInternalName(ir::ScriptFunction *scriptFunc); + +private: parser::Program *program_ {}; + ArenaAllocator *allocator_ {}; compiler::CompilerContext *compilerCtx_ {}; GlobalScope *topScope_ {}; Scope *scope_ {}; VariableScope *varScope_ {}; ArenaVector functionScopes_; - ResolveBindingOptions bindingOptions_; + ArenaVector lambdaObjects_; + ArenaVector functionalInterfaces_; + ResolveBindingOptions bindingOptions_ {}; + bool genStdLib_ {false}; }; template @@ -201,12 +295,13 @@ public: binder_->varScope_ = prevVarScope_; } - [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope) + [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope, bool checkEval = true) { LexicalScope lexScope(scope, binder); - if (binder->Program()->Extension() == ScriptExtension::TS) { + if (!checkEval || binder->Extension() == ScriptExtension::TS) { return lexScope; } + // NOLINTNEXTLINE(readability-braces-around-statements) if constexpr (std::is_same_v) { binder->varScope_ = scope->GetFunctionScope(); @@ -221,7 +316,7 @@ public: binder->varScope_ = scope; binder->varScope_->CheckDirectEval(binder->compilerCtx_); } - // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation,bugprone-suspicious-semicolon) + // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) } else if constexpr (std::is_same_v) { if (scope->IsLoopDeclarationScope()) { binder->varScope_ = scope; @@ -266,7 +361,7 @@ T *Binder::AddTsDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddTsDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddTsDecl(Allocator(), decl, Extension()) != nullptr) { return decl; } @@ -278,12 +373,25 @@ T *Binder::AddDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddDecl(Allocator(), decl, Extension()) != nullptr) { return decl; } ThrowRedeclaration(pos, decl->Name()); } + +template +std::tuple Binder::NewVarDecl(const lexer::SourcePosition &pos, Args &&...args) +{ + T *decl = Allocator()->New(std::forward(args)...); + binder::Variable *var = scope_->AddDecl(Allocator(), decl, Extension()); + + if (var != nullptr) { + return {decl, var}; + } + + ThrowRedeclaration(pos, decl->Name()); +} } // namespace panda::es2panda::binder #endif diff --git a/binder/declaration.h b/binder/declaration.h index ba4cee19e..90cf8831b 100644 --- a/binder/declaration.h +++ b/binder/declaration.h @@ -49,6 +49,11 @@ public: return name_; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; @@ -73,7 +78,7 @@ public: DECLARATION_KINDS(DECLARE_CHECKS_CASTS) #undef DECLARE_CHECKS_CASTS - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } @@ -83,12 +88,18 @@ public: return IsLetDecl() || IsConstDecl(); } + bool PossibleTDZ() const + { + return IsLetOrConstDecl() || IsParameterDecl(); + } + protected: explicit Decl(util::StringView name) : name_(name) {} + explicit Decl(util::StringView name, ir::AstNode *declNode) : name_(name), node_(declNode) {} // NOLINTBEGIN(misc-non-private-member-variables-in-classes) util::StringView name_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) }; @@ -100,6 +111,11 @@ public: { } + explicit MultiDecl(ArenaAllocator *allocator, util::StringView name, ir::AstNode *declNode) + : Decl(name, declNode), declarations_(allocator->Adapter()) + { + } + const ArenaVector &Decls() const { return declarations_; @@ -117,6 +133,10 @@ private: class EnumLiteralDecl : public Decl { public: explicit EnumLiteralDecl(util::StringView name, bool isConst) : Decl(name), isConst_(isConst) {} + explicit EnumLiteralDecl(util::StringView name, ir::AstNode *declNode, bool isConst) + : Decl(name, declNode), isConst_(isConst) + { + } DeclType Type() const override { @@ -146,6 +166,10 @@ private: class InterfaceDecl : public MultiDecl { public: explicit InterfaceDecl(ArenaAllocator *allocator, util::StringView name) : MultiDecl(allocator, name) {} + explicit InterfaceDecl(ArenaAllocator *allocator, util::StringView name, ir::AstNode *declNode) + : MultiDecl(allocator, name, declNode) + { + } DeclType Type() const override { @@ -153,9 +177,20 @@ public: } }; +class ClassDecl : public Decl { +public: + explicit ClassDecl(util::StringView name) : Decl(name) {} + explicit ClassDecl(util::StringView name, ir::AstNode *node) : Decl(name, node) {} + + DeclType Type() const override + { + return DeclType::CLASS; + } +}; + class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) + explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, ir::AstNode *node) : MultiDecl(allocator, name) { node_ = node; @@ -169,7 +204,7 @@ public: class TypeParameterDecl : public Decl { public: - explicit TypeParameterDecl(util::StringView name, const ir::AstNode *node); + explicit TypeParameterDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -240,6 +275,7 @@ public: class LetDecl : public Decl { public: explicit LetDecl(util::StringView name) : Decl(name) {} + explicit LetDecl(util::StringView name, ir::AstNode *declNode) : Decl(name, declNode) {} DeclType Type() const override { @@ -250,6 +286,7 @@ public: class ConstDecl : public Decl { public: explicit ConstDecl(util::StringView name) : Decl(name) {} + explicit ConstDecl(util::StringView name, ir::AstNode *declNode) : Decl(name, declNode) {} DeclType Type() const override { @@ -274,7 +311,7 @@ public: { } - explicit ImportDecl(util::StringView importName, util::StringView localName, const ir::AstNode *node) + explicit ImportDecl(util::StringView importName, util::StringView localName, ir::AstNode *node) : Decl(localName), importName_(importName) { BindNode(node); @@ -306,7 +343,7 @@ public: { } - explicit ExportDecl(util::StringView exportName, util::StringView localName, const ir::AstNode *node) + explicit ExportDecl(util::StringView exportName, util::StringView localName, ir::AstNode *node) : Decl(localName), exportName_(exportName) { BindNode(node); diff --git a/binder/recordTable.cpp b/binder/recordTable.cpp new file mode 100644 index 000000000..862bb2131 --- /dev/null +++ b/binder/recordTable.cpp @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "recordTable.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "generated/signatures.h" + +namespace panda::es2panda::binder { +BoundContext::BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef) + : prev_(recordTable->boundCtx_), recordTable_(recordTable), savedRecord_(recordTable->record_) +{ + if (classDef == nullptr || !recordTable_->classDefinitions_.insert(classDef).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->record_ = classDef; + recordIdent_ = classDef->Ident(); + classDef->SetInternalName(FormRecordName()); +} + +BoundContext::BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl) + : prev_(recordTable->boundCtx_), recordTable_(recordTable), savedRecord_(recordTable->record_) +{ + if (interfaceDecl == nullptr || !recordTable_->interfaceDeclarations_.insert(interfaceDecl).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->record_ = interfaceDecl; + recordIdent_ = interfaceDecl->Id(); + interfaceDecl->SetInternalName(FormRecordName()); +} + +BoundContext::BoundContext(RecordTable *recordTable, ir::TSEnumDeclaration *enumDecl) + : prev_(recordTable->boundCtx_), recordTable_(recordTable), savedRecord_(recordTable->record_) +{ + if (enumDecl == nullptr || !recordTable_->enumDeclarations_.insert(enumDecl).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->record_ = enumDecl; + recordIdent_ = enumDecl->Key(); + enumDecl->SetInternalName(FormRecordName()); +} + +BoundContext::~BoundContext() +{ + recordTable_->record_ = savedRecord_; + recordTable_->boundCtx_ = prev_; +} + +util::StringView BoundContext::FormRecordName() const +{ + const auto &packageName = recordTable_->program_->GetPackageName(); + if (prev_ == nullptr) { + if (packageName.Empty()) { + return recordIdent_->Name(); + } + + util::UString recordName(recordTable_->program_->Allocator()); + recordName.Append(packageName); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); + } + + util::UString recordName(recordTable_->program_->Allocator()); + recordName.Append(prev_->FormRecordName()); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); +} + +util::StringView RecordTable::RecordName() const +{ + if (std::holds_alternative(record_)) { + return std::get(record_)->InternalName(); + } + if (std::holds_alternative(record_)) { + return std::get(record_)->Id()->Name(); + } + + ASSERT(std::holds_alternative(record_)); + return std::get(record_)->InternalName(); +} + +} // namespace panda::es2panda::binder diff --git a/binder/recordTable.h b/binder/recordTable.h new file mode 100644 index 000000000..c5b184b7f --- /dev/null +++ b/binder/recordTable.h @@ -0,0 +1,216 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_recordTable_RECORD_TABLE_H +#define ES2PANDA_recordTable_RECORD_TABLE_H + +#include "macros.h" +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::checker { +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::es2panda::ir { +class ClassDefinition; +class TSInterfaceDeclaration; +class TSEnumDeclaration; +class Identifier; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class FunctionScope; +class BoundContext; + +enum class RecordTableFlags : uint32_t { + NONE = 0U, + EXTERNAL = 1U << 0U, +}; + +DEFINE_BITOPS(RecordTableFlags) + +class RecordTable { +public: + explicit RecordTable(ArenaAllocator *allocator, parser::Program *program, RecordTableFlags flags) + : classDefinitions_(allocator->Adapter()), + lambdaObjects_(allocator->Adapter()), + interfaceDeclarations_(allocator->Adapter()), + enumDeclarations_(allocator->Adapter()), + signatures_(allocator->Adapter()), + program_(program), + flags_(flags) + { + } + + NO_COPY_SEMANTIC(RecordTable); + NO_MOVE_SEMANTIC(RecordTable); + + ~RecordTable() = default; + + bool IsExternal() const + { + return (flags_ & RecordTableFlags::EXTERNAL) != 0; + } + + ArenaUnorderedSet &ClassDefinitions() + { + return classDefinitions_; + } + + const ArenaUnorderedSet &ClassDefinitions() const + { + return classDefinitions_; + } + + ArenaUnorderedSet &LambdaObjects() + { + return lambdaObjects_; + } + + const ArenaUnorderedSet &LambdaObjects() const + { + return lambdaObjects_; + } + + ArenaUnorderedSet &InterfaceDeclarations() + { + return interfaceDeclarations_; + } + + const ArenaUnorderedSet &InterfaceDeclarations() const + { + return interfaceDeclarations_; + } + + ArenaUnorderedSet &EnumDeclaration() + { + return enumDeclarations_; + } + + const ArenaUnorderedSet &EnumDeclaration() const + { + return enumDeclarations_; + } + + ArenaVector &Signatures() + { + return signatures_; + } + + const ArenaVector &Signatures() const + { + return signatures_; + } + + void SetClassDefinition(ir::ClassDefinition *classDefinition) + { + record_ = classDefinition; + } + + ir::ClassDefinition *ClassDefinition() + { + return std::holds_alternative(record_) ? std::get(record_) + : nullptr; + } + + const ir::ClassDefinition *ClassDefinition() const + { + return std::holds_alternative(record_) ? std::get(record_) + : nullptr; + } + + void SetInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDeclaration) + { + record_ = interfaceDeclaration; + } + + ir::TSInterfaceDeclaration *InterfaceDeclaration() + { + return std::holds_alternative(record_) + ? std::get(record_) + : nullptr; + } + + const ir::TSInterfaceDeclaration *InterfaceDeclaration() const + { + return std::holds_alternative(record_) + ? std::get(record_) + : nullptr; + } + + void SetProgram(parser::Program *program) + { + program_ = program; + } + + parser::Program *Program() + { + return program_; + } + + const parser::Program *Program() const + { + return program_; + } + + util::StringView RecordName() const; + +private: + friend class BoundContext; + using RecordHolder = + std::variant; + + ArenaUnorderedSet classDefinitions_; + ArenaUnorderedSet lambdaObjects_; + ArenaUnorderedSet interfaceDeclarations_; + ArenaUnorderedSet enumDeclarations_; + ArenaVector signatures_; + RecordHolder record_ {nullptr}; + parser::Program *program_ {}; + BoundContext *boundCtx_ {}; + RecordTableFlags flags_ {}; +}; + +class BoundContext { +public: + explicit BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef); + explicit BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl); + explicit BoundContext(RecordTable *recordTable, ir::TSEnumDeclaration *enumDecl); + ~BoundContext(); + + NO_COPY_SEMANTIC(BoundContext); + NO_MOVE_SEMANTIC(BoundContext); + + void *operator new(size_t) = delete; + void *operator new[](size_t) = delete; + + util::StringView FormRecordName() const; + +private: + BoundContext *prev_; + RecordTable *recordTable_; + RecordTable::RecordHolder savedRecord_ {nullptr}; + ir::Identifier *recordIdent_; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/scope.cpp b/binder/scope.cpp index 2c8fbad99..327b6acb0 100644 --- a/binder/scope.cpp +++ b/binder/scope.cpp @@ -22,12 +22,19 @@ #include "plugins/ecmascript/es2panda/binder/variableFlags.h" #include "plugins/ecmascript/es2panda/ir/astNode.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" #include "plugins/ecmascript/es2panda/ir/module/exportAllDeclaration.h" #include "plugins/ecmascript/es2panda/ir/module/exportNamedDeclaration.h" #include "plugins/ecmascript/es2panda/ir/module/exportSpecifier.h" #include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" #include "plugins/ecmascript/es2panda/ir/expressions/literals/stringLiteral.h" #include "plugins/ecmascript/es2panda/ir/expressions/literals/booleanLiteral.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" #include "plugins/ecmascript/es2panda/compiler/base/literals.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" #include "macros.h" @@ -67,6 +74,7 @@ const VariableScope *Scope::EnclosingVariableScope() const return nullptr; } +// NOLINTNEXTLINE(google-default-arguments) Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const { if ((options & ResolveBindingOptions::INTERFACES) != 0) { @@ -166,39 +174,44 @@ std::tuple Scope::IterateShadowedVariables(const util::StringView return {iter, false}; } -bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { - VariableFlags flags = VariableFlags::NONE; + VariableFlags flags = VariableFlags::LEXICAL; switch (newDecl->Type()) { case DeclType::VAR: { auto [scope, shadowed] = IterateShadowedVariables( newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); }); if (shadowed) { - return false; + return nullptr; } VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR; if (scope->IsGlobalScope()) { - scope->Bindings().insert({newDecl->Name(), allocator->New(newDecl, varFlags)}); - } else { - scope->PropagateBinding(allocator, newDecl->Name(), newDecl, varFlags); + return scope->Bindings() + .insert({newDecl->Name(), allocator->New(newDecl, varFlags)}) + .first->second; } - return true; + return scope->PropagateBinding(allocator, newDecl->Name(), newDecl, varFlags); } case DeclType::ENUM: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}).first->second; } case DeclType::ENUM_LITERAL: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::ENUM_LITERAL)}); - return true; + return bindings_ + .insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::ENUM_LITERAL)}) + .first->second; } case DeclType::INTERFACE: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)}) + .first->second; + } + case DeclType::TYPE_PARAMETER: { + return bindings_ + .insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::TYPE_PARAMETER)}) + .first->second; } case DeclType::FUNC: { flags = VariableFlags::HOIST; @@ -206,7 +219,7 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl } default: { if (currentVariable != nullptr) { - return false; + return nullptr; } auto [_, shadowed] = IterateShadowedVariables( @@ -214,11 +227,10 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl (void)_; if (shadowed) { - return false; + return nullptr; } - bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}).first->second; } } } @@ -227,7 +239,7 @@ void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx) { ASSERT(compilerCtx); - if (!HasFlag(VariableScopeFlags::NO_REG_STORE) || bindings_.empty()) { + if (!HasFlag(ScopeFlags::NO_REG_STORE) || bindings_.empty()) { evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID; return; } @@ -276,52 +288,53 @@ void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx) evalBindings_ = compilerCtx->AddContextLiteral(std::move(literals)); } -bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags) +Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags) { ASSERT(newDecl->IsParameterDecl()); if (currentVariable != nullptr) { - return false; + return nullptr; } auto *param = allocator->New(newDecl, flags); params_.push_back(param); bindings_.insert({newDecl->Name(), param}); - return true; + return param; } -std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, - const ir::AstNode *param) +std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, + ir::AstNode *param) { const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size()); auto *decl = NewDecl(allocator, name); + auto *var = AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR); - if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) { - return {decl, param}; + if (var == nullptr) { + return {decl, param, nullptr}; } if (!pattern) { decl->BindNode(param); - return {decl, nullptr}; + return {decl, nullptr, var}; } - std::vector bindings = util::Helpers::CollectBindingNames(param); + std::vector bindings = util::Helpers::CollectBindingNames(param); - for (const auto *binding : bindings) { + for (auto *binding : bindings) { auto *varDecl = NewDecl(allocator, binding->Name()); varDecl->BindNode(binding); if (FindLocal(varDecl->Name()) != nullptr) { - return {decl, binding}; + return {decl, binding, nullptr}; } auto *paramVar = allocator->New(varDecl, VariableFlags::VAR); bindings_.insert({varDecl->Name(), paramVar}); } - return {decl, nullptr}; + return {decl, nullptr, var}; } void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name) @@ -332,15 +345,15 @@ void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView na } } -bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator, - [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator, + [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { UNREACHABLE(); } -bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { switch (newDecl->Type()) { case DeclType::VAR: { @@ -350,8 +363,7 @@ bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVaria return AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}).first->second; } case DeclType::ENUM_LITERAL: { return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); @@ -365,8 +377,8 @@ bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVaria } } -bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { switch (newDecl->Type()) { case DeclType::VAR: { @@ -376,8 +388,7 @@ bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}).first->second; } case DeclType::ENUM_LITERAL: { return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); @@ -389,14 +400,12 @@ bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddLexical(allocator, currentVariable, newDecl); } } - - return true; } // ModuleScope -bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { switch (newDecl->Type()) { case DeclType::VAR: { @@ -406,8 +415,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}).first->second; } case DeclType::ENUM_LITERAL: { return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); @@ -419,7 +427,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddImport(allocator, currentVariable, newDecl); } case DeclType::EXPORT: { - return true; + return allocator->New(newDecl, VariableFlags::NONE); } default: { return AddLexical(allocator, currentVariable, newDecl); @@ -427,7 +435,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl } } -void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls) +void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls) { auto res = imports_.emplace_back(importDecl, decls); @@ -436,7 +444,7 @@ void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportD } } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl) { decl->BindNode(exportDecl); @@ -446,7 +454,7 @@ void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) AddExportDecl(exportDecl, std::move(decls)); } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls) { auto res = exports_.emplace_back(exportDecl, decls); @@ -455,21 +463,21 @@ void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList && } } -bool ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) +Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) { - return false; + return nullptr; } if (newDecl->Node()->IsImportNamespaceSpecifier()) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::READONLY)}); - } else { - auto *variable = allocator->New(newDecl, VariableFlags::NONE); - variable->ExoticName() = newDecl->AsImportDecl()->ImportName(); - bindings_.insert({newDecl->Name(), variable}); + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::READONLY)}) + .first->second; } - return true; + auto *variable = allocator->New(newDecl, VariableFlags::NONE); + variable->ExoticName() = newDecl->AsImportDecl()->ImportName(); + bindings_.insert({newDecl->Name(), variable}); + return variable; } bool ModuleScope::ExportAnalysis() @@ -522,12 +530,123 @@ bool ModuleScope::ExportAnalysis() // LocalScope -bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { return AddLocal(allocator, currentVariable, newDecl, extension); } +// NOLINTNEXTLINE(google-default-arguments) +Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const +{ + if ((options & ResolveBindingOptions::VARIABLES) != 0) { + auto found = instanceFieldScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) { + auto found = staticFieldScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + if ((options & ResolveBindingOptions::DECLARATION) != 0) { + auto found = instanceDeclScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) { + auto found = staticDeclScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + if ((options & ResolveBindingOptions::METHODS) != 0) { + auto found = instanceMethodScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) { + auto found = staticMethodScope_->Bindings().find(name); + if (found != bindings_.end()) { + return found->second; + } + } + + return nullptr; +} + +Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) +{ + VariableFlags flags = VariableFlags::NONE; + bool isStatic = newDecl->Node()->IsStatic(); + ir::Identifier *ident {}; + LocalScope *targetScope {}; + + if (isStatic) { + flags |= VariableFlags::STATIC; + } + + switch (newDecl->Type()) { + case DeclType::CONST: + case DeclType::LET: { + targetScope = isStatic ? staticFieldScope_ : instanceFieldScope_; + ident = newDecl->Node()->AsClassProperty()->Id(); + flags |= VariableFlags::PROPERTY; + break; + } + case DeclType::INTERFACE: { + targetScope = isStatic ? staticDeclScope_ : instanceDeclScope_; + ident = newDecl->Node()->AsTSInterfaceDeclaration()->Id(); + flags |= VariableFlags::INTERFACE; + break; + } + case DeclType::CLASS: { + targetScope = isStatic ? staticDeclScope_ : instanceDeclScope_; + ident = newDecl->Node()->AsClassDefinition()->Ident(); + flags |= VariableFlags::CLASS; + break; + } + case DeclType::ENUM_LITERAL: { + targetScope = isStatic ? staticDeclScope_ : instanceDeclScope_; + ident = newDecl->Node()->AsTSEnumDeclaration()->Key(); + flags |= VariableFlags::ENUM_LITERAL; + break; + } + default: { + UNREACHABLE(); + break; + } + } + + if (FindLocal(newDecl->Name(), ResolveBindingOptions::ALL) != nullptr) { + return nullptr; + } + + auto *var = targetScope->AddBinding(allocator, nullptr, newDecl, extension); + + if (!var) { + return nullptr; + } + + var->AddFlag(flags); + + if (ident) { + ident->SetVariable(var); + } + + return var; +} + void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator) { if (NeedLexEnv()) { @@ -580,17 +699,17 @@ void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator) } } -bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED); } -bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { if (!newDecl->IsVarDecl() && (paramScope_->FindLocal(newDecl->Name()) != nullptr)) { - return false; + return nullptr; } return AddLocal(allocator, currentVariable, newDecl, extension); diff --git a/binder/scope.h b/binder/scope.h index 9beb2fcc0..d0b903131 100644 --- a/binder/scope.h +++ b/binder/scope.h @@ -18,7 +18,7 @@ #include "plugins/ecmascript/es2panda/binder/declaration.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" @@ -127,11 +127,31 @@ public: const VariableScope *EnclosingVariableScope() const; + void AddFlag(ScopeFlags flag) + { + flags_ |= flag; + } + + void ClearFlag(ScopeFlags flag) + { + flags_ &= ~flag; + } + + bool HasFlag(ScopeFlags flag) const + { + return (flags_ & flag) != 0; + } + const ArenaVector &Decls() const { return decls_; } + void SetParent(Scope *parent) + { + parent_ = parent; + } + Scope *Parent() { return parent_; @@ -162,23 +182,28 @@ public: endIns_ = ins; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; } - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } - bool AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension) + Variable *AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension) { decls_.push_back(decl); return AddBinding(allocator, FindLocal(decl->Name()), decl, extension); } - bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension) + Variable *AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension) { decls_.push_back(decl); return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension); @@ -192,10 +217,10 @@ public: template static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node); + ir::AstNode *node); template - void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args); + Variable *PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args); VariableMap &Bindings() { @@ -207,11 +232,12 @@ public: return bindings_; } - virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) = 0; + virtual Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) = 0; - Variable *FindLocal(const util::StringView &name, - ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const; + // NOLINTNEXTLINE(google-default-arguments) + virtual Variable *FindLocal(const util::StringView &name, + ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const; ScopeFindResult Find(const util::StringView &name, ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const; @@ -224,6 +250,11 @@ protected: { } + explicit Scope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags) + : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter()), flags_(flags) + { + } + /** * @return true - if the variable is shadowed * false - otherwise @@ -236,14 +267,15 @@ protected: */ std::tuple IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor); - bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension); + Variable *AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) Scope *parent_ {}; ArenaVector decls_; VariableMap bindings_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; + ScopeFlags flags_ {}; const compiler::IRNode *startIns_ {}; const compiler::IRNode *endIns_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -255,21 +287,6 @@ public: NO_COPY_SEMANTIC(VariableScope); NO_MOVE_SEMANTIC(VariableScope); - void AddFlag(VariableScopeFlags flag) - { - flags_ |= flag; - } - - void ClearFlag(VariableScopeFlags flag) - { - flags_ &= ~flag; - } - - bool HasFlag(VariableScopeFlags flag) const - { - return (flags_ & flag) != 0; - } - uint32_t NextSlot() { return slotIndex_++; @@ -296,20 +313,19 @@ protected: explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {} template - bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); + Variable *AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); template - bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension); + Variable *AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension); template - bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags); + Variable *AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags); template - bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); + Variable *AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - VariableScopeFlags flags_ {}; uint32_t evalBindings_ {}; uint32_t slotIndex_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -332,7 +348,7 @@ public: return params_; } - std::tuple AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param); + std::tuple AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param); protected: explicit ParamScope(ArenaAllocator *allocator, Scope *parent) @@ -340,7 +356,7 @@ protected: { } - bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags); + Variable *AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags); // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) ArenaVector params_; @@ -374,8 +390,8 @@ public: return ScopeType::FUNCTION_PARAM; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; friend class FunctionScope; template @@ -429,9 +445,13 @@ public: return ScopeType::FUNCTION; } - void BindName(util::StringView name, util::StringView internalName) + void BindName(util::StringView name) { name_ = name; + } + + void BindInternalName(util::StringView internalName) + { internalName_ = internalName; } @@ -445,8 +465,8 @@ public: return internalName_; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; private: util::StringView name_ {}; @@ -456,14 +476,115 @@ private: class LocalScope : public Scope { public: explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {} + explicit LocalScope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags) : Scope(allocator, parent, flags) {} ScopeType Type() const override { return ScopeType::LOCAL; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; +}; + +class ClassScope : public LocalScope { +public: + explicit ClassScope(ArenaAllocator *allocator, Scope *parent) + : LocalScope(allocator, parent), + staticDeclScope_(allocator->New(allocator, this, ScopeFlags::STATIC_DECL_SCOPE)), + staticFieldScope_(allocator->New(allocator, staticDeclScope_, ScopeFlags::STATIC_FIELD_SCOPE)), + staticMethodScope_(allocator->New(allocator, staticFieldScope_, ScopeFlags::STATIC_METHOD_SCOPE)), + instanceDeclScope_(allocator->New(allocator, staticMethodScope_, ScopeFlags::DECL_SCOPE)), + instanceFieldScope_(allocator->New(allocator, instanceDeclScope_, ScopeFlags::FIELD_SCOPE)), + instanceMethodScope_(allocator->New(allocator, instanceFieldScope_, ScopeFlags::METHOD_SCOPE)) + { + } + + ScopeType Type() const override + { + return ScopeType::CLASS; + } + + LocalScope *StaticDeclScope() + { + return staticDeclScope_; + } + + const LocalScope *StaticDeclScope() const + { + return staticDeclScope_; + } + + LocalScope *StaticFieldScope() + { + return staticFieldScope_; + } + + const LocalScope *StaticFieldScope() const + { + return staticFieldScope_; + } + + LocalScope *StaticMethodScope() + { + return staticMethodScope_; + } + + const LocalScope *StaticMethodScope() const + { + return staticMethodScope_; + } + + LocalScope *InstanceFieldScope() + { + return instanceFieldScope_; + } + + const LocalScope *InstanceFieldScope() const + { + return instanceFieldScope_; + } + + LocalScope *InstanceMethodScope() + { + return instanceMethodScope_; + } + + const LocalScope *InstanceMethodScope() const + { + return instanceMethodScope_; + } + + LocalScope *InstanceDeclScope() + { + return instanceDeclScope_; + } + + const LocalScope *InstanceDeclScope() const + { + return instanceDeclScope_; + } + + uint32_t GetAndIncrementAnonymousClassIdx() const + { + return anonymousClassIdx_++; + } + + // NOLINTNEXTLINE(google-default-arguments) + Variable *FindLocal(const util::StringView &name, + ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const override; + + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; + +private: + LocalScope *staticDeclScope_; + LocalScope *staticFieldScope_; + LocalScope *staticMethodScope_; + LocalScope *instanceDeclScope_; + LocalScope *instanceFieldScope_; + LocalScope *instanceMethodScope_; + mutable uint32_t anonymousClassIdx_ {1}; }; class CatchParamScope : public ParamScope { @@ -475,8 +596,8 @@ public: return ScopeType::CATCH_PARAM; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; friend class CatchScope; }; @@ -490,8 +611,8 @@ public: return ScopeType::CATCH; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; }; class LoopScope; @@ -505,8 +626,8 @@ public: return loopType_; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override { return AddLocal(allocator, currentVariable, newDecl, extension); } @@ -551,8 +672,8 @@ public: void ConvertToVariableScope(ArenaAllocator *allocator); - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override { return AddLocal(allocator, currentVariable, newDecl, extension); } @@ -578,8 +699,8 @@ public: return ScopeType::GLOBAL; } - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; }; class ModuleScope : public GlobalScope { @@ -604,12 +725,12 @@ public: return ScopeType::MODULE; } - const ModuleEntry &Imports() const + const ModuleEntry &Imports() const { return imports_; } - const ModuleEntry &Exports() const + const ModuleEntry &Exports() const { return exports_; } @@ -619,98 +740,90 @@ public: return localExports_; } - void AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls); + void AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl); + void AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls); + void AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls); - bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) override; + Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) override; bool ExportAnalysis(); private: - bool AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); + Variable *AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); ArenaAllocator *allocator_; - ModuleEntry imports_; - ModuleEntry exports_; + ModuleEntry imports_; + ModuleEntry exports_; LocalExportNameMap localExports_; }; template -bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) +Variable *VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { if (!currentVariable) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::HOIST_VAR)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::HOIST_VAR)}).first->second; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: { currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); - break; + [[fallthrough]]; } case DeclType::PARAM: case DeclType::FUNC: { - break; + return currentVariable; } default: { - return false; + return nullptr; } } - - return true; } template -bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, - [[maybe_unused]] ScriptExtension extension) +Variable *VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, + [[maybe_unused]] ScriptExtension extension) { VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST; if (!currentVariable) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}).first->second; } if (extension != ScriptExtension::JS || IsModuleScope()) { - return false; + return nullptr; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: case DeclType::FUNC: { currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); - break; + return currentVariable; } default: { - return false; + return nullptr; } } - - return true; } template -bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, - VariableFlags flags) +Variable *VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, + Decl *newDecl, VariableFlags flags) { ASSERT(!currentVariable); - bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}).first->second; } template -bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) +Variable *VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { if (currentVariable) { - return false; + return nullptr; } - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::NONE)}); - return true; + return bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::NONE)}).first->second; } template @@ -739,8 +852,7 @@ VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, V } template -VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node) +VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node) { auto *decl = allocator->New(name); auto *variable = allocator->New(decl, flags); @@ -749,15 +861,15 @@ VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, } template -void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args) +Variable *Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args) { auto res = bindings_.find(name); if (res == bindings_.end()) { - bindings_.insert({name, allocator->New(std::forward(args)...)}); - return; + return bindings_.insert({name, allocator->New(std::forward(args)...)}).first->second; } res->second->Reset(std::forward(args)...); + return res->second; } } // namespace panda::es2panda::binder diff --git a/binder/variable.cpp b/binder/variable.cpp index fec0ece21..bb7dba273 100644 --- a/binder/variable.cpp +++ b/binder/variable.cpp @@ -27,6 +27,8 @@ LocalVariable::LocalVariable(Decl *decl, VariableFlags flags) : Variable(decl, f } } +LocalVariable::LocalVariable(VariableFlags flags) : Variable(flags) {} + const util::StringView &Variable::Name() const { return decl_->Name(); diff --git a/binder/variable.h b/binder/variable.h index ffa856132..8c0f2d733 100644 --- a/binder/variable.h +++ b/binder/variable.h @@ -26,6 +26,7 @@ namespace panda::es2panda::checker { class Type; +enum class PropertyType; } // namespace panda::es2panda::checker namespace panda::es2panda::binder { @@ -65,7 +66,12 @@ public: VARIABLE_TYPES(DECLARE_CHECKS_CASTS) #undef DECLARE_CHECKS_CASTS - Decl *Declaration() const + const Decl *Declaration() const + { + return decl_; + } + + Decl *Declaration() { return decl_; } @@ -116,9 +122,10 @@ public: protected: explicit Variable(Decl *decl, VariableFlags flags) : decl_(decl), flags_(flags) {} + explicit Variable(VariableFlags flags) : flags_(flags) {} // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Decl *decl_; + Decl *decl_ {}; VariableFlags flags_ {}; checker::Type *tsType_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -127,6 +134,7 @@ protected: class LocalVariable : public Variable { public: explicit LocalVariable(Decl *decl, VariableFlags flags); + explicit LocalVariable(VariableFlags flags); VariableType Type() const override { @@ -143,7 +151,7 @@ public: { ASSERT(!LexicalBound()); AddFlag(VariableFlags::LEXICAL_BOUND); - vreg_ = slot; + vreg_.SetIndex(slot); } compiler::VReg Vreg() const @@ -151,17 +159,22 @@ public: return vreg_; } + compiler::VReg &Vreg() + { + return vreg_; + } + uint32_t LexIdx() const { ASSERT(LexicalBound()); - return vreg_; + return vreg_.GetIndex(); } void SetLexical([[maybe_unused]] Scope *scope) override; LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const; private: - uint32_t vreg_ {}; + compiler::VReg vreg_ {}; }; class GlobalVariable : public Variable { diff --git a/binder/variableFlags.h b/binder/variableFlags.h index 7be9b096f..d424f91ad 100644 --- a/binder/variableFlags.h +++ b/binder/variableFlags.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_COMPILER_SCOPES_VARIABLE_FLAGS_H #define ES2PANDA_COMPILER_SCOPES_VARIABLE_FLAGS_H +#include #include "plugins/ecmascript/es2panda/util/enumbitops.h" namespace panda::es2panda::binder { @@ -35,6 +36,7 @@ namespace panda::es2panda::binder { _(ENUM_LITERAL, EnumLiteralDecl) \ _(TYPE_PARAMETER, TypeParameterDecl) \ _(PROPERTY, PropertyDecl) \ + _(CLASS, ClassDecl) \ _(METHOD, MethodDecl) \ _(ENUM, EnumDecl) @@ -52,6 +54,7 @@ enum class DeclType { _(CATCH_PARAM, CatchParamScope) \ _(FUNCTION_PARAM, FunctionParamScope) \ _(CATCH, CatchScope) \ + _(CLASS, ClassScope) \ _(LOCAL, LocalScope) \ /* Variable Scopes */ \ _(LOOP, LoopScope) \ @@ -68,11 +71,20 @@ enum class ScopeType { }; enum class ResolveBindingOptions : uint32_t { - NONE = 0, - BINDINGS = 0x1U, - INTERFACES = 0x2U, - - ALL = BINDINGS | INTERFACES, + BINDINGS = 1U << 0U, + INTERFACES = 1U << 1U, + VARIABLES = 1U << 2U, + METHODS = 1U << 3U, + DECLARATION = 1U << 4U, + STATIC_VARIABLES = 1U << 5U, + STATIC_METHODS = 1U << 6U, + STATIC_DECLARATION = 1U << 7U, + ALL_VARIABLES = VARIABLES | STATIC_VARIABLES, + ALL_METHOD = METHODS | STATIC_METHODS, + ALL_DECLARATION = DECLARATION | STATIC_DECLARATION, + + LAST = STATIC_DECLARATION, + ALL = (LAST << 1U) - 1U, }; DEFINE_BITOPS(ResolveBindingOptions) @@ -99,32 +111,46 @@ enum class VariableKind { MODULE, }; -enum class VariableFlags : uint32_t { - NONE = 0, - OPTIONAL = 0x1U, - PROPERTY = 0x2U, - METHOD = 0x4U, - TYPE_ALIAS = 0x8U, - INTERFACE = 0x10U, - ENUM_LITERAL = 0x20U, - READONLY = 0x40U, - COMPUTED = 0x80U, - COMPUTED_IDENT = 0x100U, // Remove - INFERED_IN_PATTERN = 0x200U, - REST_ARG = 0x400U, - NUMERIC_NAME = 0x800U, - TYPE = 0x1000U, - LOCAL_EXPORT = 0x2000U, - - LOOP_DECL = 0x4000U, - PER_ITERATION = 0x8000U, - LEXICAL_VAR = 0x10000U, - HOIST = 0x20000U, - VAR = 0x40000U, - INITIALIZED = 0x80000U, - LEXICAL_BOUND = 0x100000U, +enum class VariableFlags : uint64_t { + NONE = 0U, + OPTIONAL = 1U << 0U, + PROPERTY = 1U << 1U, + METHOD = 1U << 2U, + TYPE_ALIAS = 1U << 3U, + INTERFACE = 1U << 4U, + ENUM_LITERAL = 1U << 5U, + READONLY = 1U << 6U, + COMPUTED = 1U << 7U, + COMPUTED_IDENT = 1U << 8U, // Remove + INFERED_IN_PATTERN = 1U << 9U, + REST_ARG = 1U << 10U, + NUMERIC_NAME = 1U << 11U, + TYPE = 1U << 12U, + LOCAL_EXPORT = 1U << 13U, + TYPE_PARAMETER = 1U << 14U, + STATIC = 1U << 15U, + CLASS = 1U << 16U, + EXPLICIT_INIT_REQUIRED = 1U << 17U, + PUBLIC = 1U << 18U, + PROTECTED = 1U << 19U, + PRIVATE = 1U << 20U, + SYNTHETIC = 1U << 21U, + METHOD_REFERENCE = 1U << 22U, + + LEXICAL = 1U << 24U, + LOOP_DECL = 1U << 25U, + PER_ITERATION = 1U << 26U, + LEXICAL_VAR = 1U << 27U, + HOIST = 1U << 28U, + VAR = 1U << 29U, + INITIALIZED = 1U << 30U, + LEXICAL_BOUND = 1U << 31U, + + BUILTIN_TYPE = 1ULL << 32ULL, HOIST_VAR = HOIST | VAR, + CLASS_OR_INTERFACE = CLASS | INTERFACE, + CLASS_OR_INTERFACE_OR_ENUM = CLASS_OR_INTERFACE | ENUM_LITERAL, }; DEFINE_BITOPS(VariableFlags) @@ -134,16 +160,25 @@ enum class LetOrConstStatus { UNINITIALIZED, }; -enum class VariableScopeFlags : uint32_t { - NONE = 0x0U, - SET_LEXICAL_FUNCTION = 0x1U, - USE_ARGS = 0x2U, - USE_SUPER = 0x4U, - INNER_ARROW = 0x8U, - NO_REG_STORE = 0x10U, +enum class ScopeFlags : uint32_t { + NONE = 0U, + SET_LEXICAL_FUNCTION = 1U << 0U, + USE_ARGS = 1U << 2U, + USE_SUPER = 1U << 3U, + INNER_ARROW = 1U << 4U, + NO_REG_STORE = 1U << 5U, + DEFER_STMT = 1U << 6U, + DECL_SCOPE = 1U << 7U, + FIELD_SCOPE = 1U << 8U, + METHOD_SCOPE = 1U << 9U, + STATIC = 1U << 10U, + + STATIC_DECL_SCOPE = DECL_SCOPE | STATIC, + STATIC_FIELD_SCOPE = FIELD_SCOPE | STATIC, + STATIC_METHOD_SCOPE = METHOD_SCOPE | STATIC, }; -DEFINE_BITOPS(VariableScopeFlags) +DEFINE_BITOPS(ScopeFlags) } // namespace panda::es2panda::binder #endif diff --git a/checker/ASchecker.cpp b/checker/ASchecker.cpp new file mode 100644 index 000000000..fbafe0c3d --- /dev/null +++ b/checker/ASchecker.cpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ASchecker.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool ASChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << Program()->Dump() << std::endl; + } + + return false; +} + +} // namespace panda::es2panda::checker diff --git a/checker/ASchecker.h b/checker/ASchecker.h new file mode 100644 index 000000000..d5dcaea2a --- /dev/null +++ b/checker/ASchecker.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_AS_CHECKER_H +#define ES2PANDA_CHECKER_AS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" + +namespace panda::es2panda::checker { + +class ASChecker : public Checker { +public: + // NOLINTNEXTLINE(readability-redundant-member-init) + explicit ASChecker() : Checker() {} + + bool StartChecker([[maybe_unused]] binder::Binder *binder, + [[maybe_unused]] const CompilerOptions &options) override; + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override + { + return nullptr; + } + + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/ETSchecker.cpp b/checker/ETSchecker.cpp new file mode 100644 index 000000000..5bfd93ce1 --- /dev/null +++ b/checker/ETSchecker.cpp @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ETSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/checker/ets/aliveAnalyzer.h" + +namespace panda::es2panda::checker { +void ETSChecker::InitializeBuiltins(binder::ETSBinder *binder) +{ + if (HasStatus(CheckerStatus::BUILTINS_INITIALIZED)) { + return; + } + + const auto varMap = binder->TopScope()->Bindings(); + + const auto object = varMap.find("Object"); + ASSERT(object != varMap.end()); + GetGlobalTypesHolder()->InitializeBuiltin( + object->first, BuildClassProperties(object->second->Declaration()->Node()->AsClassDefinition())); + + for (const auto &[name, var] : varMap) { + if (name == object->first) { + continue; + } + + if (var->HasFlag(binder::VariableFlags::BUILTIN_TYPE)) { + Type *type {nullptr}; + if (var->Declaration()->Node()->IsClassDefinition()) { + type = BuildClassProperties(var->Declaration()->Node()->AsClassDefinition()); + } else { + ASSERT(var->Declaration()->Node()->IsTSInterfaceDeclaration()); + type = BuildInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); + } + GetGlobalTypesHolder()->InitializeBuiltin(name, type); + } + } + + AddStatus(CheckerStatus::BUILTINS_INITIALIZED); +} + +bool ETSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << Program()->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + binder->SetGenStdLib(options.genStdLib); + binder->IdentifierAnalysis(); + + auto *etsBinder = static_cast(binder); + InitializeBuiltins(etsBinder); + + CheckProgram(Program(), true); + + for (auto *func : binder->Functions()) { + etsBinder->BuildFunctionName(func->Node()->AsScriptFunction()); + } + + for (auto *lambda : binder->LambdaObjects()) { + etsBinder->BuildLambdaObjectName(lambda); + } + + for (auto *functional : binder->FunctionalInterfaces()) { + etsBinder->BuildFunctionalInterfaceName(functional); + } + + return true; +} + +void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) +{ + auto *savedProgram = Program(); + SetProgram(program); + + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + CheckProgram(extProg); + } + } + + ASSERT(Program()->Ast()->IsProgram()); + Program()->Ast()->Check(this); + + if (runAnalysis) { + AliveAnalyzer(Program()->Ast(), this); + } + + auto *binder = static_cast(Binder()); + auto *recordTable = binder->GetExternalRecordTable().find(program)->second; + + InitializeRecordElements(binder, recordTable); + + SetProgram(savedProgram); +} + +void ETSChecker::InitializeRecordElements(binder::ETSBinder *binder, binder::RecordTable *recordTable) +{ + for (auto *func : recordTable->Signatures()) { + binder->BuildFunctionName(func->Node()->AsScriptFunction()); + } +} + +Type *ETSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (expr->TsType() == nullptr) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} + +ETSObjectType *ETSChecker::AsETSObjectType(Type *(GlobalTypesHolder::*typeFunctor)()) const +{ + auto *ret = (GetGlobalTypesHolder()->*typeFunctor)(); + return ret != nullptr ? ret->AsETSObjectType() : nullptr; +} + +Type *ETSChecker::GlobalByteType() const +{ + return GetGlobalTypesHolder()->GlobalByteType(); +} + +Type *ETSChecker::GlobalShortType() const +{ + return GetGlobalTypesHolder()->GlobalShortType(); +} + +Type *ETSChecker::GlobalIntType() const +{ + return GetGlobalTypesHolder()->GlobalIntType(); +} + +Type *ETSChecker::GlobalLongType() const +{ + return GetGlobalTypesHolder()->GlobalLongType(); +} + +Type *ETSChecker::GlobalFloatType() const +{ + return GetGlobalTypesHolder()->GlobalFloatType(); +} + +Type *ETSChecker::GlobalDoubleType() const +{ + return GetGlobalTypesHolder()->GlobalDoubleType(); +} + +Type *ETSChecker::GlobalCharType() const +{ + return GetGlobalTypesHolder()->GlobalCharType(); +} + +Type *ETSChecker::GlobalETSBooleanType() const +{ + return GetGlobalTypesHolder()->GlobalETSBooleanType(); +} + +Type *ETSChecker::GlobalVoidType() const +{ + return GetGlobalTypesHolder()->GlobalETSVoidType(); +} + +Type *ETSChecker::GlobalETSNullType() const +{ + return GetGlobalTypesHolder()->GlobalETSNullType(); +} + +Type *ETSChecker::GlobalETSStringLiteralType() const +{ + return GetGlobalTypesHolder()->GlobalETSStringLiteralType(); +} + +Type *ETSChecker::GlobalWildcardType() const +{ + return GetGlobalTypesHolder()->GlobalWildcardType(); +} + +ETSObjectType *ETSChecker::GlobalETSObjectType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalETSObjectType); +} + +ETSObjectType *ETSChecker::GlobalBuiltinETSStringType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalETSStringBuiltinType); +} + +ETSObjectType *ETSChecker::GlobalBuiltinTypeType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalTypeBuiltinType); +} + +ETSObjectType *ETSChecker::GlobalBuiltinExceptionType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalExceptionBuiltinType); +} + +ETSObjectType *ETSChecker::GlobalBuiltinPanicType() const +{ + return AsETSObjectType(&GlobalTypesHolder::GlobalPanicBuiltinType); +} + +ETSObjectType *ETSChecker::GlobalBuiltinEnumType() const +{ + return globalBuiltinEnumType_; +} + +const checker::WrapperDesc &ETSChecker::PrimitiveWrapper() const +{ + return primitiveWrappers_.Wrappers(); +} + +GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() +{ + return globalArraySignatures_; +} + +const GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() const +{ + return globalArraySignatures_; +} +} // namespace panda::es2panda::checker diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h new file mode 100644 index 000000000..e121a4e03 --- /dev/null +++ b/checker/ETSchecker.h @@ -0,0 +1,322 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_ETS_CHECKER_H +#define ES2PANDA_CHECKER_ETS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checkerContext.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/primitiveWrappers.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" + +#include "macros.h" + +#include +#include +#include +#include +#include + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +class ETSBinder; +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +enum class OperationType { + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + LEFT_SHIFT, + RIGHT_SHIFT, + ADDITON, + SUBSTRACTION, + MULTIPLICATION, + DIVISION, + MOD, + LESS_THAN, + LESS_THAN_EQUAL, + GREATER_THAN, + GREATER_THAN_EQUAL, +}; + +enum class OverrideErrorCode { + NO_ERROR, + OVERRIDING_STATIC, + OVERRIDEN_STATIC, + OVERRIDEN_NOT_OPEN, + INCOMPATIBLE_RETURN, + OVERRIDEN_WEAKER, +}; + +using ComputedAbstracts = + ArenaUnorderedMap, std::unordered_set>>; +using ArrayMap = ArenaUnorderedMap; +using GlobalArraySignatureMap = ArenaUnorderedMap; + +class ETSChecker : public Checker { +public: + explicit ETSChecker() + // NOLINTNEXTLINE(readability-redundant-member-init) + : Checker(), + arrayTypes_(Allocator()->Adapter()), + globalArraySignatures_(Allocator()->Adapter()), + primitiveWrappers_(Allocator()), + cachedComputedAbstracts_(Allocator()->Adapter()) + { + } + + static inline TypeFlag ETSType(const Type *type) + { + return static_cast(type->TypeFlags() & TypeFlag::ETS_TYPE); + } + + static inline TypeFlag TypeKind(const Type *type) + { + return static_cast(type->TypeFlags() & checker::TypeFlag::ETS_TYPE); + } + + Type *GlobalByteType() const; + Type *GlobalShortType() const; + Type *GlobalIntType() const; + Type *GlobalLongType() const; + Type *GlobalFloatType() const; + Type *GlobalDoubleType() const; + Type *GlobalCharType() const; + Type *GlobalETSBooleanType() const; + Type *GlobalVoidType() const; + Type *GlobalETSNullType() const; + Type *GlobalETSStringLiteralType() const; + Type *GlobalWildcardType() const; + + ETSObjectType *GlobalETSObjectType() const; + ETSObjectType *GlobalBuiltinETSStringType() const; + ETSObjectType *GlobalBuiltinTypeType() const; + ETSObjectType *GlobalBuiltinExceptionType() const; + ETSObjectType *GlobalBuiltinPanicType() const; + ETSObjectType *GlobalBuiltinEnumType() const; + + const checker::WrapperDesc &PrimitiveWrapper() const; + + GlobalArraySignatureMap &GlobalArrayTypes(); + const GlobalArraySignatureMap &GlobalArrayTypes() const; + + void InitializeBuiltins(binder::ETSBinder *binder); + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override; + + // Object + ETSObjectType *BuildClassProperties(ir::ClassDefinition *classDef); + ETSObjectType *BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType); + ETSObjectType *BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl); + void BuildEnumProperties(ETSObjectType *enumType); + ETSObjectType *GetSuperType(ETSObjectType *type); + ArenaVector GetInterfaces(ETSObjectType *type); + ArenaVector GetInterfacesOfClass(ETSObjectType *type); + ArenaVector GetInterfacesOfInterface(ETSObjectType *type); + void ValidateImplementedInterface(ETSObjectType *type, Type *interface, std::unordered_set *extendsSet, + const lexer::SourcePosition &pos); + void ResolveMembersOfEnumDecl(ETSObjectType *type); + void ResolveDeclaredMembersOfObject(ETSObjectType *type); + Type *ValidateArrayIndex(ir::Expression *expr); + Type *CheckArrayElementAccess(ir::MemberExpression *expr); + ETSObjectType *CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg); + void CreateTypeForClassTypeParameters(ETSObjectType *type); + void CreateTypeForInterfaceTypeParameters(ETSObjectType *type); + void SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType); + void ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos); + void AddImplementedSignature(std::vector *implementedSignatures, binder::LocalVariable *function, + ETSFunctionType *it); + void CheckInnerClassMembers(const ETSObjectType *classType); + void CheckClassDefinition(ir::ClassDefinition *classDef); + void FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void CheckConstFields(const ETSObjectType *classType); + void CheckConstFieldInitialized(const ETSObjectType *classType, binder::LocalVariable *classVar); + void CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *classVar); + void ComputeAbstractsFromInterface(ETSObjectType *interfaceType); + ArenaVector &GetAbstractsForClass(ETSObjectType *classType); + std::vector CollectAbstractSignaturesFromObject(const ETSObjectType *objType); + void CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target); + void CheckCyclicContructorCall(Signature *signature); + binder::LocalVariable *ResolveMemberReference(const ir::MemberExpression *memberExpr, ETSObjectType *target); + void CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig); + void CheckValidInheritance(ETSObjectType *classType, ir::ClassDefinition *classDef); + + // Type creation + ByteType *CreateByteType(int8_t value); + ETSBooleanType *CreateETSBooleanType(bool value); + DoubleType *CreateDoubleType(double value); + FloatType *CreateFloatType(float value); + IntType *CreateIntType(int32_t value); + LongType *CreateLongType(int64_t value); + ShortType *CreateShortType(int16_t value); + CharType *CreateCharType(char16_t value); + ETSStringType *CreateETSStringLiteralType(util::StringView value); + ETSArrayType *CreateETSArrayType(Type *elementType); + ETSFunctionType *CreateETSFunctionType(Signature *signature); + ETSFunctionType *CreateETSFunctionType(util::StringView name); + ETSFunctionType *CreateETSFunctionType(ArenaVector &signatures); + ETSTypeReference *CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar); + ETSTypeParameter *CreateTypeParameter(Type *assemblerType); + ETSObjectType *CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + ETSObjectType *CreateETSEnumType(ir::TSEnumDeclaration *enumDecl); + std::tuple CreateBuiltinArraySignatureInfo(ETSArrayType *arrayType, size_t dim); + Signature *CreateBuiltinArraySignature(ETSArrayType *arrayType, size_t dim); + IntType *CreateIntTypeFromType(Type *type); + ETSObjectType *CreateNewETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + + Signature *CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func); + Signature *CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName); + SignatureInfo *CreateSignatureInfo(); + + // Arithmetic + Type *NegateNumericType(Type *type, ir::Expression *node); + Type *BitwiseNegateIntegralType(Type *type, ir::Expression *node); + std::tuple CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos); + Type *HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + Type *HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + // Function + bool ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags); + Signature *ValidateSignatures(ArenaVector &signatures, const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags); + Signature *ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, const lexer::SourcePosition &pos, + bool isIdentifier); + + Signature *ResolveConstructExpression(ETSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos); + checker::ETSFunctionType *BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig = false); + checker::ETSFunctionType *BuildMethodSignature(ir::MethodDefinition *method); + Signature *CheckEveryAbstractSignatureIsOverriden(ETSFunctionType *target, ETSFunctionType *source); + Signature *GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef); + void CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, + const lexer::SourcePosition &overloadStart); + void CheckOverride(Signature *signature); + bool CheckOverride(Signature *signature, ETSObjectType *site); + std::tuple CheckOverride(Signature *signature, Signature *other); + bool IsMethodOverridesOther(Signature *target, Signature *source); + bool IsOverridableIn(Signature *signature); + void ValidateSignatureAccessibility(ETSObjectType *callee, Signature *signature, const lexer::SourcePosition &pos); + void ResolveLambdaObject(ir::ETSMethodReferenceExpression *methodRef, ETSObjectType *functionalInterface); + void ResolveLambdaObjectCtor(ir::ClassDefinition *lambdaObject); + void ResolveLambdaObjectInvoke(ir::ClassDefinition *lambdaObject, Signature *signatureRef); + ir::Statement *ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition *lambdaObject, Signature *signatureRef); + + // Helpers + Type *GetReferencedTypeFromBase(Type *baseType, ir::Expression *name); + Type *GetReferencedTypeBase(ir::Expression *name); + Type *GetTypeFromInterfaceReference(binder::Variable *var); + Type *GetTypeFromClassReference(binder::Variable *var); + Type *GetTypeFromEnumReference(binder::Variable *var); + Type *GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos); + Type *GetDefaultTypeFromPrimitiveType(Type *type); + bool IsConstantExpression(ir::Expression *expr, Type *type); + void ValidateUnaryOperatorOperand(binder::Variable *variable); + std::tuple ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test); + Type *ApplyUnaryOperatorPromotion(Type *type, bool createConst = true); + Type *HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType); + checker::Type *CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation, ir::Expression *init, + ir::ModifierFlags flags); + void CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos); + void ConcantConstantString(util::UString &target, Type *type); + Type *HandleStringConcatenation(Type *leftType, Type *rightType); + Type *ResolveIdentifier(ir::Identifier *ident); + ETSFunctionType *FindFunctionInVectorGivenByName(util::StringView name, ArenaVector &list); + void MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t); + void MergeSignatures(ETSFunctionType *target, ETSFunctionType *source); + ir::AstNode *FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type); + util::StringView GetContainingObjectNameFromSignature(Signature *signature); + bool IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature); + void CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature); + bool IsTypeBuiltinType(Type *type); + const ir::AstNode *FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, const ir::Identifier *target); + void ValidatePropertyAccess(binder::Variable *var, ETSObjectType *obj, const lexer::SourcePosition &pos); + binder::VariableFlags GetAccessFlagFromNode(const ir::AstNode *node); + void CheckSwitchDiscriminant(ir::Expression *discriminant); + Type *ETSBuiltinTypeAsPrimitiveType(Type *objectType); + Type *PrimitiveTypeAsETSBuiltinType(Type *objectType); + void CheckForSameSwitchCases(ArenaVector *cases); + util::StringView GetStringViewFromIdentifierValue(ir::Expression *identifier); + bool CompareIdentifiersValuesAreDifferent(ir::Expression *identifier, ir::Expression *compareValue); + void CheckIdentifierSwitchCase(ir::Expression *currentCase, ir::Expression *compareCase, + const lexer::SourcePosition &pos); + util::StringView GetStringViewFromLiteral(ir::Expression *caseTest); + binder::Variable *FindVariableInClass(util::StringView name); + std::tuple GetClassScopeFromClass(ETSObjectType *classType); + bool IsSameDeclarationType(binder::LocalVariable *target, binder::LocalVariable *compare); + + // Exception + ETSObjectType *CheckExceptionType(checker::Type *type, lexer::SourcePosition pos); + ETSObjectType *CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos); + + static Type *TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes); + +private: + void CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams); + ETSObjectType *CheckException(checker::Type *type, lexer::SourcePosition pos, ETSObjectType *expected, + std::string_view msg); + ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + void CheckProgram(parser::Program *program, bool runAnalysis = false); + void InitializeRecordElements(binder::ETSBinder *binder, binder::RecordTable *recordTable); + + template + UType HandleModulo(UType leftValue, UType rightValue); + + template + UType HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType); + + template + typename TargetType::UType GetOperand(Type *type); + + ETSObjectType *AsETSObjectType(Type *(GlobalTypesHolder::*typeFunctor)()) const; + + ArrayMap arrayTypes_; + GlobalArraySignatureMap globalArraySignatures_; + PrimitiveWrappers primitiveWrappers_; + ComputedAbstracts cachedComputedAbstracts_; + // TODO(szd): remove after enum rework + ETSObjectType *globalBuiltinEnumType_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/JSchecker.cpp b/checker/JSchecker.cpp new file mode 100644 index 000000000..2ba5ffed2 --- /dev/null +++ b/checker/JSchecker.cpp @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSchecker.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool JSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << Program()->Dump() << std::endl; + } + + return !options.parseOnly; +} + +} // namespace panda::es2panda::checker diff --git a/typescript/core/checkerContext.h b/checker/JSchecker.h similarity index 48% rename from typescript/core/checkerContext.h rename to checker/JSchecker.h index 3aef77d60..6b1eefe77 100644 --- a/typescript/core/checkerContext.h +++ b/checker/JSchecker.h @@ -13,46 +13,33 @@ * limitations under the License. */ -#ifndef ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H -#define ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H +#ifndef ES2PANDA_CHECKER_JS_CHECKER_H +#define ES2PANDA_CHECKER_JS_CHECKER_H -#include -#include "plugins/ecmascript/es2panda/util/enumbitops.h" - -#include +#include "plugins/ecmascript/es2panda/checker/checker.h" namespace panda::es2panda::checker { -enum class CheckerStatus : uint32_t { - NO_OPTS = 0x0U, - FORCE_TUPLE = 0x1U, - IN_CONST_CONTEXT = 0x2U, - KEEP_LITERAL_TYPE = 0x4U, - IN_PARAMETER = 0x8U, -}; -DEFINE_BITOPS(CheckerStatus) - -class CheckerContext { +class JSChecker : public Checker { public: - explicit CheckerContext(CheckerStatus newStatus) : status_(newStatus) {} + // NOLINTNEXTLINE(readability-redundant-member-init) + explicit JSChecker() : Checker() {} - const CheckerStatus &Status() const - { - return status_; - } + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; - CheckerStatus &Status() + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override { - return status_; + return nullptr; } - DEFAULT_COPY_SEMANTIC(CheckerContext); - DEFAULT_MOVE_SEMANTIC(CheckerContext); - ~CheckerContext() = default; + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} -private: - CheckerStatus status_; + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } }; + } // namespace panda::es2panda::checker -#endif +#endif /* CHECKER_H */ diff --git a/checker/TSchecker.cpp b/checker/TSchecker.cpp new file mode 100644 index 000000000..6865ccfb0 --- /dev/null +++ b/checker/TSchecker.cpp @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool TSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << Program()->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + ASSERT(Program()->Ast()->IsProgram()); + Program()->Ast()->Check(this); + + return false; +} + +Type *TSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (expr->TsType() == nullptr) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} + +} // namespace panda::es2panda::checker diff --git a/typescript/checker.h b/checker/TSchecker.h similarity index 45% rename from typescript/checker.h rename to checker/TSchecker.h index dd3365372..c315ab46e 100644 --- a/typescript/checker.h +++ b/checker/TSchecker.h @@ -13,18 +13,18 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H +#ifndef ES2PANDA_CHECKER_TS_CHECKER_H +#define ES2PANDA_CHECKER_TS_CHECKER_H +#include "plugins/ecmascript/es2panda/checker/checker.h" #include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" -#include "plugins/ecmascript/es2panda/typescript/core/checkerContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/types/types.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/types.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "macros.h" +#include #include #include #include @@ -104,170 +104,125 @@ enum class AstNodeType; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -using StringLiteralPool = std::unordered_map; -using NumberLiteralPool = std::unordered_map; -using FunctionParamsResolveResult = std::variant &, bool>; -using InterfacePropertyMap = std::unordered_map>; -using TypeOrNode = std::variant; -using IndexInfoTypePair = std::pair; -using PropertyMap = std::unordered_map; -using ArgRange = std::pair; - -class Checker { -public: - explicit Checker(ArenaAllocator *allocator, binder::Binder *binder); - ~Checker() = default; - NO_COPY_SEMANTIC(Checker); - NO_MOVE_SEMANTIC(Checker); - ArenaAllocator *Allocator() const - { - return allocator_; - } - - binder::Binder *Binder() - { - return binder_; - } - - binder::Scope *Scope() const - { - return scope_; - } +class TSChecker : public Checker { +public: + // NOLINTNEXTLINE(readability-redundant-member-init) + explicit TSChecker() : Checker() {} Type *GlobalNumberType() { - return globalTypes_->GlobalNumberType(); + return GetGlobalTypesHolder()->GlobalNumberType(); } Type *GlobalAnyType() { - return globalTypes_->GlobalAnyType(); + return GetGlobalTypesHolder()->GlobalAnyType(); } Type *GlobalStringType() { - return globalTypes_->GlobalStringType(); + return GetGlobalTypesHolder()->GlobalStringType(); } Type *GlobalBooleanType() { - return globalTypes_->GlobalBooleanType(); + return GetGlobalTypesHolder()->GlobalBooleanType(); } Type *GlobalVoidType() { - return globalTypes_->GlobalVoidType(); + return GetGlobalTypesHolder()->GlobalVoidType(); } Type *GlobalNullType() { - return globalTypes_->GlobalNullType(); + return GetGlobalTypesHolder()->GlobalNullType(); } Type *GlobalUndefinedType() { - return globalTypes_->GlobalUndefinedType(); + return GetGlobalTypesHolder()->GlobalUndefinedType(); } Type *GlobalUnknownType() { - return globalTypes_->GlobalUnknownType(); + return GetGlobalTypesHolder()->GlobalUnknownType(); } Type *GlobalNeverType() { - return globalTypes_->GlobalNeverType(); + return GetGlobalTypesHolder()->GlobalNeverType(); } Type *GlobalNonPrimitiveType() { - return globalTypes_->GlobalNonPrimitiveType(); + return GetGlobalTypesHolder()->GlobalNonPrimitiveType(); } Type *GlobalBigintType() { - return globalTypes_->GlobalBigintType(); + return GetGlobalTypesHolder()->GlobalBigintType(); } Type *GlobalFalseType() { - return globalTypes_->GlobalFalseType(); + return GetGlobalTypesHolder()->GlobalFalseType(); } Type *GlobalTrueType() { - return globalTypes_->GlobalTrueType(); + return GetGlobalTypesHolder()->GlobalTrueType(); } Type *GlobalNumberOrBigintType() { - return globalTypes_->GlobalNumberOrBigintType(); + return GetGlobalTypesHolder()->GlobalNumberOrBigintType(); } Type *GlobalStringOrNumberType() { - return globalTypes_->GlobalStringOrNumberType(); + return GetGlobalTypesHolder()->GlobalStringOrNumberType(); } Type *GlobalZeroType() { - return globalTypes_->GlobalZeroType(); + return GetGlobalTypesHolder()->GlobalZeroType(); } Type *GlobalEmptyStringType() { - return globalTypes_->GlobalEmptyStringType(); + return GetGlobalTypesHolder()->GlobalEmptyStringType(); } Type *GlobalZeroBigintType() { - return globalTypes_->GlobalZeroBigintType(); + return GetGlobalTypesHolder()->GlobalZeroBigintType(); } Type *GlobalPrimitiveType() { - return globalTypes_->GlobalPrimitiveType(); + return GetGlobalTypesHolder()->GlobalPrimitiveType(); } Type *GlobalEmptyTupleType() { - return globalTypes_->GlobalEmptyTupleType(); + return GetGlobalTypesHolder()->GlobalEmptyTupleType(); } Type *GlobalEmptyObjectType() { - return globalTypes_->GlobalEmptyObjectType(); + return GetGlobalTypesHolder()->GlobalEmptyObjectType(); } Type *GlobalResolvingReturnType() { - return globalTypes_->GlobalResolvingReturnType(); + return GetGlobalTypesHolder()->GlobalResolvingReturnType(); } Type *GlobalErrorType() { - return globalTypes_->GlobalErrorType(); - } - - CheckerContext Context() - { - return context_; - } - - bool HasStatus(CheckerStatus status) - { - return (context_.Status() & status) != 0; - } - - void RemoveStatus(CheckerStatus status) - { - context_.Status() &= ~status; - } - - void AddStatus(CheckerStatus status) - { - context_.Status() |= status; + return GetGlobalTypesHolder()->GlobalErrorType(); } NumberLiteralPool &NumberLiteralMap() @@ -285,82 +240,44 @@ public: return bigintLiteralMap_; } - TypeRelation *Relation() - { - return relation_; - } - - RelationHolder &IdenticalResults() - { - return identicalResults_; - } - - RelationHolder &AssignableResults() - { - return assignableResults_; - } - - RelationHolder &ComparableResults() - { - return comparableResults_; - } - - std::unordered_set &TypeStack() - { - return typeStack_; - } - - std::unordered_map &NodeCache() - { - return nodeCache_; - } - - void StartChecker(); - - Type *CheckTypeCached(const ir::Expression *expr); - - [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); - [[noreturn]] void ThrowTypeError(std::initializer_list list, - const lexer::SourcePosition &pos); + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; // Util - static bool InAssignment(const ir::AstNode *node); + static bool InAssignment(ir::AstNode *node); static bool IsAssignmentOperator(lexer::TokenType op); static bool IsLiteralType(const Type *type); - static const ir::AstNode *FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type); - static const ir::AstNode *FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop); + static ir::AstNode *FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop); static bool MaybeTypeOfKind(const Type *type, TypeFlag flags); static bool MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind); - static bool IsConstantMemberAccess(const ir::Expression *expr); - static bool IsStringLike(const ir::Expression *expr); - static const ir::TSQualifiedName *ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName); - static const ir::MemberExpression *ResolveLeftMostMemberExpression(const ir::MemberExpression *expr); + static bool IsConstantMemberAccess(ir::Expression *expr); + static bool IsStringLike(ir::Expression *expr); + static ir::MemberExpression *ResolveLeftMostMemberExpression(ir::MemberExpression *expr); // Helpers void CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo); Type *CheckNonNullType(Type *type, lexer::SourcePosition lineInfo); Type *GetBaseTypeOfLiteralType(Type *type); - void CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, + void CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, const char *invalidOptionalChainMsg); - void CheckTestingKnownTruthyCallableOrAwaitableType(const ir::Expression *condExpr, Type *type, - const ir::AstNode *body); + void CheckTestingKnownTruthyCallableOrAwaitableType(ir::Expression *condExpr, Type *type, ir::AstNode *body); Type *ExtractDefinitelyFalsyTypes(Type *type); Type *RemoveDefinitelyFalsyTypes(Type *type); TypeFlag GetFalsyFlags(Type *type); - bool IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar); - bool FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); - bool IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar); + bool FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); [[noreturn]] void ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo); [[noreturn]] void ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType = false); - void ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos); - void InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator); - Type *GetTypeOfVariable(binder::Variable *var); + void ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos); + void InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator); + Type *GetTypeOfVariable(binder::Variable *var) override; Type *GetUnaryResultType(Type *operandType); - Type *GetTypeFromClassOrInterfaceReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromClassOrInterfaceReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var); // Type creation Type *CreateNumberLiteralType(double value); @@ -379,12 +296,12 @@ public: Type *CreateObjectTypeWithConstructSignature(Signature *constructSignature); // Object - void ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, bool isInterface); + void ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface); void ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations); - void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); + ArenaVector &signatureDeclarations); + void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); void ResolveDeclaredMembers(InterfaceType *type); bool ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, const lexer::SourcePosition &locInfo); @@ -393,142 +310,64 @@ public: binder::Variable *GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, binder::VariableFlags propagateFlags); void CheckIndexConstraints(Type *type); - void ResolveStructuredTypeMembers(Type *type); void ResolveUnionTypeMembers(UnionType *type); void ResolveObjectTypeMembers(ObjectType *type); void ResolveInterfaceOrClassTypeMembers(InterfaceType *type); - Type *CheckComputedPropertyName(const ir::Expression *key); + Type *CheckComputedPropertyName(ir::Expression *key); Type *GetPropertyTypeForIndexType(Type *type, Type *indexType); IndexInfo *GetApplicableIndexInfo(Type *type, Type *indexType); ArenaVector GetBaseTypes(InterfaceType *type); + void ResolveStructuredTypeMembers(Type *type) override; // Function - Type *HandleFunctionReturn(const ir::ScriptFunction *func); + Type *HandleFunctionReturn(ir::ScriptFunction *func); void CheckFunctionParameterDeclarations(const ArenaVector ¶ms, SignatureInfo *signatureInfo); std::tuple CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo); + ir::Expression *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionIdentifierParameter( - const ir::Identifier *param); + ir::Identifier *param); std::tuple CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param); + ir::AssignmentExpression *param); std::tuple CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo); + ir::SpreadElement *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param); + ir::ArrayExpression *param); std::tuple CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param); + ir::ObjectExpression *param); void InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar); - void CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes); - void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, lexer::SourcePosition lineInfo, + void CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes); + void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, lexer::SourcePosition lineInfo, const char *errMsg); - void CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss); - void ThrowReturnTypeCircularityError(const ir::ScriptFunction *func); + void CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss); + void ThrowReturnTypeCircularityError(ir::ScriptFunction *func); ArgRange GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, uint32_t callArgsSize, bool *haveSignatureWithRest); bool CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError); Type *resolveCallOrNewExpression(const ArenaVector &signatures, ArenaVector arguments, const lexer::SourcePosition &errPos); - Type *CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType); - Type *CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, Type *inferedType); - - // Type relation - bool IsTypeIdenticalTo(Type *source, Type *target); - bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target); - bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target); - bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool AreTypesComparable(Type *source, Type *target); - bool IsTypeEqualityComparableTo(Type *source, Type *target); - bool IsAllTypesAssignableTo(Type *source, Type *target); + Type *CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType); + Type *CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType); // Binary like expression - Type *CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr); - Type *CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr); - void CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, Type *valueType); - - friend class ScopeContext; - friend class SavedCheckerContext; + Type *CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, ir::AstNode *expr); + Type *CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr); + void CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType); private: - ArenaAllocator *allocator_; - binder::Binder *binder_; - const ir::BlockStatement *rootNode_; - binder::Scope *scope_; - CheckerContext context_; - GlobalTypesHolder *globalTypes_; - NumberLiteralPool numberLiteralMap_; StringLiteralPool stringLiteralMap_; StringLiteralPool bigintLiteralMap_; - - TypeRelation *relation_; - - RelationHolder identicalResults_; - RelationHolder assignableResults_; - RelationHolder comparableResults_; - - std::unordered_set typeStack_; - std::unordered_map nodeCache_; - std::vector scopeStack_; }; -class ScopeContext { -public: - explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) - { - checker_->scope_ = newScope; - } - - ~ScopeContext() - { - checker_->scope_ = prevScope_; - } - - NO_COPY_SEMANTIC(ScopeContext); - NO_MOVE_SEMANTIC(ScopeContext); - -private: - Checker *checker_; - binder::Scope *prevScope_; -}; - -class SavedCheckerContext { -public: - explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) - : checker_(checker), prev_(checker->context_) - { - checker_->context_ = CheckerContext(newStatus); - } - - NO_COPY_SEMANTIC(SavedCheckerContext); - DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); - - ~SavedCheckerContext() - { - checker_->context_ = prev_; - } - -private: - Checker *checker_; - CheckerContext prev_; -}; } // namespace panda::es2panda::checker #endif /* CHECKER_H */ diff --git a/typescript/core/typeRelation.cpp b/checker/checker.cpp similarity index 55% rename from typescript/core/typeRelation.cpp rename to checker/checker.cpp index 4bd2675be..cb3453ef9 100644 --- a/typescript/core/typeRelation.cpp +++ b/checker/checker.cpp @@ -13,11 +13,77 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" - -#include +#include "checker.h" + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#include +#include +#include namespace panda::es2panda::checker { +Checker::Checker() + : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), + context_(CheckerStatus::NO_OPTS), + globalTypes_(allocator_.New(&allocator_)), + relation_(allocator_.New(this)) +{ +} + +void Checker::Initialize(binder::Binder *binder) +{ + binder_ = binder; + scope_ = binder_->TopScope(); + program_ = binder_->Program(); +} + +void Checker::ThrowTypeError(std::initializer_list list, const lexer::SourcePosition &pos) +{ + std::stringstream ss; + + for (const auto &it : list) { + if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << TokenToString(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss); + } else if (std::holds_alternative(it)) { + std::get(it).GetType()->ToStringAsSrc(ss); + } else if (std::holds_alternative(it)) { + ss << std::to_string(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss, nullptr, true); + } else { + UNREACHABLE(); + } + } + + std::string err = ss.str(); + ThrowTypeError(err, pos); +} + +void Checker::ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos) +{ + lexer::LineIndex index(program_->SourceCode()); + lexer::SourceLocation loc = index.GetLocation(pos); + + throw Error {ErrorType::TYPE, program_->SourceFile().Utf8(), message, loc.line, loc.col}; +} + bool Checker::IsAllTypesAssignableTo(Type *source, Type *target) { if (source->TypeFlags() == TypeFlag::UNION) { @@ -114,4 +180,20 @@ bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target) { return target->HasTypeFlag(TypeFlag::NULLABLE) || IsTypeComparableTo(source, target); } + +parser::Program *Checker::Program() const +{ + return program_; +} + +void Checker::SetProgram(parser::Program *program) +{ + program_ = program; +} + +binder::Binder *Checker::Binder() const +{ + return binder_; +} + } // namespace panda::es2panda::checker diff --git a/checker/checker.h b/checker/checker.h new file mode 100644 index 000000000..10f58f80d --- /dev/null +++ b/checker/checker.h @@ -0,0 +1,268 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_CHECKER_H +#define ES2PANDA_CHECKER_CHECKER_H + +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/checker/checkerContext.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "macros.h" + +#include +#include +#include +#include + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::ir { +class AstNode; +class Expression; +class BlockStatement; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class ETSChecker; +class InterfaceType; +class GlobalTypesHolder; + +using StringLiteralPool = std::unordered_map; +using NumberLiteralPool = std::unordered_map; +using FunctionParamsResolveResult = std::variant &, bool>; +using InterfacePropertyMap = std::unordered_map>; +using TypeOrNode = std::variant; +using IndexInfoTypePair = std::pair; +using PropertyMap = std::unordered_map; +using ArgRange = std::pair; + +class Checker { +public: + explicit Checker(); + ~Checker() = default; + NO_COPY_SEMANTIC(Checker); + NO_MOVE_SEMANTIC(Checker); + + ArenaAllocator *Allocator() + { + return &allocator_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + CheckerContext &Context() + { + return context_; + } + + bool HasStatus(CheckerStatus status) + { + return (context_.Status() & status) != 0; + } + + void RemoveStatus(CheckerStatus status) + { + context_.Status() &= ~status; + } + + void AddStatus(CheckerStatus status) + { + context_.Status() |= status; + } + + TypeRelation *Relation() const + { + return relation_; + } + + GlobalTypesHolder *GetGlobalTypesHolder() const + { + return globalTypes_; + } + + RelationHolder &IdenticalResults() + { + return identicalResults_; + } + + RelationHolder &AssignableResults() + { + return assignableResults_; + } + + RelationHolder &ComparableResults() + { + return comparableResults_; + } + + std::unordered_set &TypeStack() + { + return typeStack_; + } + + ETSChecker *AsETSChecker() + { + return reinterpret_cast(this); + } + + virtual bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) = 0; + virtual Type *CheckTypeCached(ir::Expression *expr) = 0; + virtual Type *GetTypeOfVariable(binder::Variable *var) = 0; + virtual void ResolveStructuredTypeMembers(Type *type) = 0; + + [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); + [[noreturn]] void ThrowTypeError(std::initializer_list list, + const lexer::SourcePosition &pos); + + bool IsTypeIdenticalTo(Type *source, Type *target); + bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target); + bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target); + bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool AreTypesComparable(Type *source, Type *target); + bool IsTypeEqualityComparableTo(Type *source, Type *target); + bool IsAllTypesAssignableTo(Type *source, Type *target); + + friend class ScopeContext; + friend class TypeStackElement; + friend class SavedCheckerContext; + +protected: + void Initialize(binder::Binder *binder); + parser::Program *Program() const; + void SetProgram(parser::Program *program); + binder::Binder *Binder() const; + +private: + ArenaAllocator allocator_; + CheckerContext context_; + GlobalTypesHolder *globalTypes_; + TypeRelation *relation_; + binder::Binder *binder_ {}; + parser::Program *program_ {}; + binder::Scope *scope_ {}; + + RelationHolder identicalResults_; + RelationHolder assignableResults_; + RelationHolder comparableResults_; + + std::unordered_set typeStack_; +}; + +class TypeStackElement { +public: + explicit TypeStackElement(Checker *checker, void *element, std::initializer_list list, + const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(list, pos); + } + } + + explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(err, pos); + } + } + + ~TypeStackElement() + { + checker_->typeStack_.erase(element_); + } + + NO_COPY_SEMANTIC(TypeStackElement); + NO_MOVE_SEMANTIC(TypeStackElement); + +private: + Checker *checker_; + void *element_; +}; + +class ScopeContext { +public: + explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) + { + checker_->scope_ = newScope; + } + + ~ScopeContext() + { + checker_->scope_ = prevScope_; + } + + NO_COPY_SEMANTIC(ScopeContext); + NO_MOVE_SEMANTIC(ScopeContext); + +private: + Checker *checker_; + binder::Scope *prevScope_; +}; + +class SavedCheckerContext { +public: + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) + : SavedCheckerContext(checker, newStatus, nullptr) + { + } + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, ETSObjectType *containingClass) + : checker_(checker), prev_(checker->context_) + { + checker_->context_ = CheckerContext(newStatus, containingClass); + } + + NO_COPY_SEMANTIC(SavedCheckerContext); + DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); + + ~SavedCheckerContext() + { + checker_->context_ = prev_; + } + +private: + Checker *checker_; + CheckerContext prev_; +}; +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/typescript/core/checkerContext.cpp b/checker/checkerContext.cpp similarity index 100% rename from typescript/core/checkerContext.cpp rename to checker/checkerContext.cpp diff --git a/checker/checkerContext.h b/checker/checkerContext.h new file mode 100644 index 000000000..877b00dcb --- /dev/null +++ b/checker/checkerContext.h @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_CHECKER_CONTEXT_H +#define ES2PANDA_CHECKER_CHECKER_CONTEXT_H + +#include +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include + +namespace panda::es2panda::checker { + +class ETSObjectType; +class Signature; + +enum class CheckerStatus : uint32_t { + NO_OPTS = 0U, + FORCE_TUPLE = 1U << 0U, + IN_CONST_CONTEXT = 1U << 1U, + KEEP_LITERAL_TYPE = 1U << 2U, + IN_PARAMETER = 1U << 3U, + IN_CLASS = 1U << 4U, + IN_INTERFACE = 1U << 5U, + IN_ABSTRACT = 1U << 6U, + IN_STATIC_CONTEXT = 1U << 7U, + IN_CONSTRUCTOR = 1U << 8U, + IN_STATIC_BLOCK = 1U << 9U, + INNER_CLASS = 1U << 10U, + IN_ENUM = 1U << 11U, + BUILTINS_INITIALIZED = 1U << 12U, +}; + +DEFINE_BITOPS(CheckerStatus) + +class CheckerContext { +public: + explicit CheckerContext(CheckerStatus newStatus) : CheckerContext(newStatus, nullptr) {} + explicit CheckerContext(CheckerStatus newStatus, ETSObjectType *containingClass) + : status_(newStatus), containingClass_(containingClass) + { + } + + const CheckerStatus &Status() const + { + return status_; + } + + ETSObjectType *ContainingClass() const + { + return containingClass_; + } + + Signature *ContainingSignature() const + { + return containingSignature_; + } + + CheckerStatus &Status() + { + return status_; + } + + void SetContainingSignature(Signature *containingSignature) + { + containingSignature_ = containingSignature; + } + + void SetContainingClass(ETSObjectType *containingClass) + { + containingClass_ = containingClass; + } + + DEFAULT_COPY_SEMANTIC(CheckerContext); + DEFAULT_MOVE_SEMANTIC(CheckerContext); + ~CheckerContext() = default; + +private: + CheckerStatus status_; + ETSObjectType *containingClass_ {}; + Signature *containingSignature_ {nullptr}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/aliveAnalyzer.cpp b/checker/ets/aliveAnalyzer.cpp new file mode 100644 index 000000000..2132fb8f0 --- /dev/null +++ b/checker/ets/aliveAnalyzer.cpp @@ -0,0 +1,422 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "aliveAnalyzer.h" +#include + +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/doWhileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forUpdateStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forOfStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/ifStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/throwStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchCaseStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +void AliveAnalyzer::AnalyzeNodes(const ir::AstNode *node) +{ + node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); }); +} + +void AliveAnalyzer::AnalyzeNode(const ir::AstNode *node) +{ + if (node == nullptr) { + return; + } + + switch (node->Type()) { + case ir::AstNodeType::EXPRESSION_STATEMENT: { + AnalyzeNode(node->AsExpressionStatement()->GetExpression()); + break; + } + case ir::AstNodeType::CLASS_DECLARATION: { + AnalyzeClassDecl(node->AsClassDeclaration()); + break; + } + case ir::AstNodeType::CLASS_DEFINITION: { + AnalyzeClassDef(node->AsClassDefinition()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + AnalyzeMethodDef(node->AsMethodDefinition()); + break; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + AnalyzeVarDef(node->AsVariableDeclaration()); + break; + } + case ir::AstNodeType::BLOCK_STATEMENT: { + AnalyzeStats(node->AsBlockStatement()->Statements()); + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: { + AnalyzeDoLoop(node->AsDoWhileStatement()); + break; + } + case ir::AstNodeType::WHILE_STATEMENT: { + AnalyzeWhileLoop(node->AsWhileStatement()); + break; + } + case ir::AstNodeType::FOR_UPDATE_STATEMENT: { + AnalyzeForLoop(node->AsForUpdateStatement()); + break; + } + case ir::AstNodeType::FOR_OF_STATEMENT: { + AnalyzeForOfLoop(node->AsForOfStatement()); + break; + } + case ir::AstNodeType::IF_STATEMENT: { + AnalyzeIf(node->AsIfStatement()); + break; + } + case ir::AstNodeType::LABELLED_STATEMENT: { + AnalyzeLabelled(node->AsLabelledStatement()); + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + AnalyzeNewClass(node->AsETSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::CALL_EXPRESSION: { + AnalyzeCall(node->AsCallExpression()); + break; + } + case ir::AstNodeType::THROW_STATEMENT: { + AnalyzeThrow(node->AsThrowStatement()); + break; + } + case ir::AstNodeType::SWITCH_STATEMENT: { + AnalyzeSwitch(node->AsSwitchStatement()); + break; + } + case ir::AstNodeType::TRY_STATEMENT: { + AnalyzeTry(node->AsTryStatement()); + break; + } + case ir::AstNodeType::BREAK_STATEMENT: { + AnalyzeBreak(node->AsBreakStatement()); + break; + } + case ir::AstNodeType::CONTINUE_STATEMENT: { + AnalyzeContinue(node->AsContinueStatement()); + break; + } + case ir::AstNodeType::RETURN_STATEMENT: { + AnalyzeReturn(node->AsReturnStatement()); + break; + } + default: { + break; + } + } +} + +void AliveAnalyzer::AnalyzeDef(const ir::AstNode *node) +{ + AnalyzeStat(node); + if (node != nullptr && node->IsClassStaticBlock() && status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Initializer must be able to complete normally.", node->Start()); + } +} + +void AliveAnalyzer::AnalyzeStat(const ir::AstNode *node) +{ + if (node == nullptr) { + return; + } + + if (status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Unreachable statement.", node->Start()); + } + + if (node->IsClassStaticBlock()) { + AnalyzeNodes(node); + return; + } + + AnalyzeNode(node); +} + +void AliveAnalyzer::AnalyzeStats(const ArenaVector &stats) +{ + for (const auto *it : stats) { + AnalyzeStat(it); + } +} + +static bool IsStaticMember(const ir::AstNode *node) +{ + switch (node->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + return node->IsStatic(); + } + case ir::AstNodeType::CLASS_DECLARATION: { + return node->AsClassDeclaration()->Definition()->IsStatic(); + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return node->IsStatic(); + } + default: { + return false; + } + } +} + +void AliveAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl) +{ + for (const auto *it : classDecl->Definition()->Body()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeClassDef(const ir::ClassDefinition *classDef) +{ + if (classDef->Variable() == nullptr) { + return; + } + + LivenessStatus prevStatus = status_; + SetOldPendingExits(PendingExits()); + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && !IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsClassStaticBlock()) { + AnalyzeDef(it); + break; + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsMethodDefinition()) { + AnalyzeNode(it); + } + } + + SetPendingExits(OldPendingExits()); + status_ = prevStatus; +} + +void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) +{ + auto *func = methodDef->Function(); + + if (func->Body() == nullptr) { + return; + } + + status_ = LivenessStatus::ALIVE; + AnalyzeStat(func->Body()); + ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType()); + + if (status_ == LivenessStatus::ALIVE && + !methodDef->TsType()->AsETSFunctionType()->FindSignature(func)->ReturnType()->IsETSVoidType()) { + checker_->ThrowTypeError("Function with a non void return type must return a value.", func->Id()->Start()); + } + + ClearPendingExits(); +} + +void AliveAnalyzer::AnalyzeVarDef(const ir::VariableDeclaration *varDef) +{ + for (auto *it : varDef->Declarators()) { + if (it->Init() == nullptr) { + continue; + } + + AnalyzeNode(it->Init()); + } +} + +void AliveAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhile) +{ + SetOldPendingExits(PendingExits()); + AnalyzeStat(doWhile->Body()); + status_ = Or(status_, ResolveContinues(doWhile)); + AnalyzeNode(doWhile->Test()); + ASSERT(doWhile->Test()->TsType() && doWhile->Test()->TsType()->IsETSBooleanType()); + auto *condType = doWhile->Test()->TsType()->AsETSBooleanType(); + status_ = + And(status_, static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); + status_ = Or(status_, ResolveBreaks(doWhile)); +} + +void AliveAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt) +{ + SetOldPendingExits(PendingExits()); + AnalyzeNode(whileStmt->Test()); + ASSERT(whileStmt->Test()->TsType() && whileStmt->Test()->TsType()->IsETSBooleanType()); + auto *condType = whileStmt->Test()->TsType()->AsETSBooleanType(); + status_ = And(status_, + static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue()))); + AnalyzeStat(whileStmt->Body()); + status_ = Or(status_, ResolveContinues(whileStmt)); + status_ = Or(ResolveBreaks(whileStmt), From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt) +{ + AnalyzeNode(forStmt->Init()); + SetOldPendingExits(PendingExits()); + const ETSBooleanType *condType {}; + if (forStmt->Test() != nullptr) { + AnalyzeNode(forStmt->Test()); + ASSERT(forStmt->Test()->TsType() && forStmt->Test()->TsType()->IsETSBooleanType()); + condType = forStmt->Test()->TsType()->AsETSBooleanType(); + status_ = From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue())); + } else { + status_ = LivenessStatus::ALIVE; + } + + AnalyzeStat(forStmt->Body()); + status_ = Or(status_, ResolveContinues(forStmt)); + AnalyzeNode(forStmt->Update()); + status_ = Or(ResolveBreaks(forStmt), + From(condType != nullptr && !(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt) +{ + ASSERT(forOfStmt->Left()->IsVariableDeclaration()); + AnalyzeVarDef(forOfStmt->Left()->AsVariableDeclaration()); + AnalyzeNode(forOfStmt->Right()); + SetOldPendingExits(PendingExits()); + AnalyzeStat(forOfStmt->Body()); + status_ = Or(status_, ResolveContinues(forOfStmt)); + ResolveBreaks(forOfStmt); + status_ = LivenessStatus::ALIVE; +} + +void AliveAnalyzer::AnalyzeIf(const ir::IfStatement *ifStmt) +{ + AnalyzeNode(ifStmt->Test()); + AnalyzeStat(ifStmt->Consequent()); + if (ifStmt->Alternate() != nullptr) { + LivenessStatus prevStatus = status_; + status_ = LivenessStatus::ALIVE; + AnalyzeStat(ifStmt->Alternate()); + status_ = Or(status_, prevStatus); + } else { + status_ = LivenessStatus::ALIVE; + } +} + +void AliveAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt) +{ + SetOldPendingExits(PendingExits()); + AnalyzeStat(labelledStmt->Body()); + status_ = Or(status_, ResolveBreaks(labelledStmt)); +} + +void AliveAnalyzer::AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass) +{ + for (const auto *it : newClass->GetArguments()) { + AnalyzeNode(it); + } + + if (newClass->ClassDefinition() != nullptr) { + AnalyzeNode(newClass->ClassDefinition()); + } +} + +void AliveAnalyzer::AnalyzeCall(const ir::CallExpression *callExpr) +{ + AnalyzeNode(callExpr->Callee()); + for (const auto *it : callExpr->Arguments()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt) +{ + AnalyzeNode(throwStmt->Argument()); + MarkDead(); +} + +void AliveAnalyzer::AnalyzeSwitch([[maybe_unused]] const ir::SwitchStatement *switchStmt) +{ + // TODO(aszilagyi): fix analysis to be correct + /* + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeNode(switchStmt->Discriminant()); + + std::vector constants; + for (const auto *it : switchStmt->Cases()) { + status_ = LivenessStatus::ALIVE; + AnalyzeNode(it->Test()); + AnalyzeStats(it->Consequent()); + } + + status_ = Or(status_, ResolveBreaks(switchStmt, oldPendingExits)); + */ +} + +void AliveAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt) +{ + RecordExit(PendingExit(breakStmt)); +} + +void AliveAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt) +{ + RecordExit(PendingExit(contStmt)); +} + +void AliveAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt) +{ + AnalyzeNode(retStmt->Argument()); + RecordExit(PendingExit(retStmt)); +} + +void AliveAnalyzer::AnalyzeTry([[maybe_unused]] const ir::TryStatement *tryStmt) +{ + // TODO(user): +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/aliveAnalyzer.h b/checker/ets/aliveAnalyzer.h new file mode 100644 index 000000000..7a5bce9d6 --- /dev/null +++ b/checker/ets/aliveAnalyzer.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ALIVE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_ALIVE_ANALYZER_H + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/baseAnalyzer.h" + +#include "utils/arena_containers.h" + +namespace panda::es2panda::ir { +class AstNode; +class Statement; +class ClassDefinition; +class MethodDefinition; +class DoWhileStatement; +class VariableDeclaration; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class AliveAnalyzer : public BaseAnalyzer { +public: + // NOLINTNEXTLINE(readability-redundant-member-init) + AliveAnalyzer(const ir::AstNode *node, ETSChecker *checker) : BaseAnalyzer(), checker_(checker) + { + AnalyzeNodes(node); + } + + void MarkDead() override + { + status_ = LivenessStatus::DEAD; + } + + LivenessStatus Or(LivenessStatus left, LivenessStatus right) + { + return static_cast(left | right); + } + + LivenessStatus And(LivenessStatus left, LivenessStatus right) + { + return static_cast(left & right); + } + +private: + void AnalyzeNodes(const ir::AstNode *node); + void AnalyzeNode(const ir::AstNode *node); + void AnalyzeDef(const ir::AstNode *node); + void AnalyzeStat(const ir::AstNode *node); + void AnalyzeStats(const ArenaVector &stats); + void AnalyzeClassDecl(const ir::ClassDeclaration *classDecl); + void AnalyzeClassDef(const ir::ClassDefinition *classDef); + void AnalyzeMethodDef(const ir::MethodDefinition *methodDef); + void AnalyzeVarDef(const ir::VariableDeclaration *varDef); + void AnalyzeDoLoop(const ir::DoWhileStatement *doWhile); + void AnalyzeWhileLoop(const ir::WhileStatement *whileStmt); + void AnalyzeForLoop(const ir::ForUpdateStatement *forStmt); + void AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt); + void AnalyzeIf(const ir::IfStatement *ifStmt); + void AnalyzeLabelled(const ir::LabelledStatement *labelledStmt); + void AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass); + void AnalyzeCall(const ir::CallExpression *callExpr); + void AnalyzeThrow(const ir::ThrowStatement *throwStmt); + void AnalyzeSwitch(const ir::SwitchStatement *switchStmt); + void AnalyzeTry(const ir::TryStatement *tryStmt); + void AnalyzeBreak(const ir::BreakStatement *breakStmt); + void AnalyzeContinue(const ir::ContinueStatement *contStmt); + void AnalyzeReturn(const ir::ReturnStatement *retStmt); + + ETSChecker *checker_; + LivenessStatus status_ {LivenessStatus::ALIVE}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/arithmetic.cpp b/checker/ets/arithmetic.cpp new file mode 100644 index 000000000..b51a74683 --- /dev/null +++ b/checker/ets/arithmetic.cpp @@ -0,0 +1,349 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "arithmetic.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +Type *ETSChecker::NegateNumericType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + TypeFlag typeKind = ETSType(type); + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(-(type->AsByteType()->GetValue())); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(-(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(-(type->AsShortType()->GetValue())); + break; + } + case TypeFlag::INT: { + result = CreateIntType(-(type->AsIntType()->GetValue())); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(-(type->AsLongType()->GetValue())); + break; + } + case TypeFlag::FLOAT: { + result = CreateFloatType(-(type->AsFloatType()->GetValue())); + break; + } + case TypeFlag::DOUBLE: { + result = CreateDoubleType(-(type->AsDoubleType()->GetValue())); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *ETSChecker::BitwiseNegateIntegralType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL)); + + TypeFlag typeKind = ETSType(type); + + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(static_cast(~static_cast(type->AsByteType()->GetValue()))); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(~(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(static_cast(~static_cast(type->AsShortType()->GetValue()))); + break; + } + case TypeFlag::INT: { + result = CreateIntType(static_cast(~static_cast(type->AsIntType()->GetValue()))); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(static_cast(~static_cast(type->AsLongType()->GetValue()))); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + return PerformRelationOperationOnTypes(left, right, operationType); +} + +std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos) +{ + checker::Type *leftType = left->Check(this); + checker::Type *rightType = right->Check(this); + checker::Type *tsType {}; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (promotedType == nullptr && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + if (leftType->IsETSStringType() || rightType->IsETSStringType()) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + if (leftType->IsETSStringType() || rightType->IsETSStringType()) { + tsType = HandleStringConcatenation(leftType, rightType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (promotedType == nullptr && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type or String.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + leftType = ApplyUnaryOperatorPromotion(leftType, false); + rightType = ApplyUnaryOperatorPromotion(rightType, false); + + if (leftType == nullptr || !leftType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL) || + rightType == nullptr || !rightType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { + ThrowTypeError("Bad operand type, the types of the operands must be integral type.", pos); + } + + if (leftType->HasTypeFlag(TypeFlag::CONSTANT) && rightType->HasTypeFlag(TypeFlag::CONSTANT)) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + switch (ETSType(leftType)) { + case TypeFlag::INT: { + tsType = GlobalIntType(); + break; + } + case TypeFlag::LONG: { + tsType = GlobalLongType(); + break; + } + default: { + UNREACHABLE(); + } + } + + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + Type *unboxedL = ETSBuiltinTypeAsPrimitiveType(leftType); + Type *unboxedR = ETSBuiltinTypeAsPrimitiveType(rightType); + if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr && + unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { + tsType = HandleBooleanLogicalOperators(unboxedL, unboxedR, operationType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_INTEGRAL); + + if (promotedType == nullptr && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be integral type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + Type *unboxedL = ETSBuiltinTypeAsPrimitiveType(leftType); + Type *unboxedR = ETSBuiltinTypeAsPrimitiveType(rightType); + if (unboxedL == nullptr || !unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) || unboxedR == nullptr || + !unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { + ThrowTypeError("Bad operand type, the types of the operands must be boolean type.", pos); + } + + tsType = HandleBooleanLogicalOperators(unboxedL, unboxedR, operationType); + break; + } + + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + if ((leftType->IsETSObjectType() && rightType->IsETSObjectType()) || + (leftType->IsETSStringType() && rightType->IsETSStringType())) { + tsType = GlobalETSBooleanType(); + auto *opType = GlobalETSObjectType(); + return {tsType, opType}; + } + + Type *unboxedL = ETSBuiltinTypeAsPrimitiveType(leftType); + Type *unboxedR = ETSBuiltinTypeAsPrimitiveType(rightType); + if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr && + unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { + if (unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && + unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + bool res = unboxedL->AsETSBooleanType()->GetValue() == unboxedR->AsETSBooleanType()->GetValue(); + + tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res); + break; + } + + tsType = GlobalETSBooleanType(); + break; + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (promotedType == nullptr && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = GlobalETSBooleanType(); + auto *opType = promotedType; + return {tsType, opType}; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + if (!leftType->HasTypeFlag(checker::TypeFlag::ETS_OBJECT) || + !rightType->HasTypeFlag(checker::TypeFlag::ETS_OBJECT)) { + ThrowTypeError("Bad operand type, the types of the operands must be same type.", pos); + } + + tsType = GlobalETSBooleanType(); + auto *opType = GlobalETSObjectType(); + return {tsType, opType}; + } + default: { + // TODO(user): + UNREACHABLE(); + break; + } + } + + return {tsType, tsType}; +} + +Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + return PerformArithmeticOperationOnTypes(left, right, operationType); +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/arithmetic.h b/checker/ets/arithmetic.h new file mode 100644 index 000000000..919b78c5c --- /dev/null +++ b/checker/ets/arithmetic.h @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H +#define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsBooleanType.h" + +namespace panda::es2panda::checker { + +template +typename TargetType::UType ETSChecker::GetOperand(Type *type) +{ + switch (ETSType(type)) { + case TypeFlag::BYTE: { + return type->AsByteType()->GetValue(); + } + case TypeFlag::CHAR: { + return type->AsCharType()->GetValue(); + } + case TypeFlag::SHORT: { + return type->AsShortType()->GetValue(); + } + case TypeFlag::INT: { + return type->AsIntType()->GetValue(); + } + case TypeFlag::LONG: { + return type->AsLongType()->GetValue(); + } + case TypeFlag::FLOAT: { + return type->AsFloatType()->GetValue(); + } + case TypeFlag::DOUBLE: { + return type->AsDoubleType()->GetValue(); + } + default: { + UNREACHABLE(); + } + } +} + +template +Type *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + + bool result {}; + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + result = leftValue < rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + result = leftValue <= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + result = leftValue > rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + result = leftValue >= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_EQUAL: { + result = leftValue == rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + result = leftValue != rightValue; + break; + } + default: { + UNREACHABLE(); + } + } + + return CreateETSBooleanType(result); +} + +template +Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + auto result = leftValue; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + result = leftValue + rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + result = leftValue - rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + result = leftValue / rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + result = leftValue * rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + result = HandleModulo(leftValue, rightValue); + break; + } + default: { + result = HandleBitWiseArithmetic(leftValue, rightValue, operationType); + } + } + + return Allocator()->New(result); +} + +template <> +inline IntType::UType panda::es2panda::checker::ETSChecker::HandleModulo(IntType::UType leftValue, + IntType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline LongType::UType panda::es2panda::checker::ETSChecker::HandleModulo(LongType::UType leftValue, + LongType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline FloatType::UType panda::es2panda::checker::ETSChecker::HandleModulo( + FloatType::UType leftValue, FloatType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template <> +inline DoubleType::UType panda::es2panda::checker::ETSChecker::HandleModulo( + DoubleType::UType leftValue, DoubleType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template +UType ETSChecker::HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType) +{ + auto unsignedLeftValue = static_cast::type>(leftValue); + auto unsignedRightValue = static_cast::type>(rightValue); + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + return unsignedLeftValue & unsignedRightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + return unsignedLeftValue | unsignedRightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + return unsignedLeftValue ^ unsignedRightValue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + return unsignedLeftValue << unsignedRightValue; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { + // NOLINTNEXTLINE(hicpp-signed-bitwise) + return leftValue >> (rightValue & (std::numeric_limits::digits - 1)); + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + static_assert(sizeof(UType) == 4 || sizeof(UType) == 8); + return unsignedLeftValue >> (unsignedRightValue & (std::numeric_limits::digits - 1U)); + } + default: { + UNREACHABLE(); + } + } +} + +template <> +inline FloatType::UType ETSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] FloatType::UType leftValue, [[maybe_unused]] FloatType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} + +template <> +inline DoubleType::UType ETSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] DoubleType::UType leftValue, [[maybe_unused]] DoubleType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/baseAnalyzer.cpp b/checker/ets/baseAnalyzer.cpp new file mode 100644 index 000000000..5c7d472be --- /dev/null +++ b/checker/ets/baseAnalyzer.cpp @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "baseAnalyzer.h" +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" + +namespace panda::es2panda::checker { +void BaseAnalyzer::ClearPendingExits() +{ + pendingExits_.clear(); +} + +PendingExitsVector &BaseAnalyzer::PendingExits() +{ + return pendingExits_; +} + +void BaseAnalyzer::SetPendingExits(const PendingExitsVector &pendingExits) +{ + pendingExits_ = pendingExits; +} + +PendingExitsVector &BaseAnalyzer::OldPendingExits() +{ + return oldPendingExits_; +} + +void BaseAnalyzer::SetOldPendingExits(const PendingExitsVector &oldPendingExits) +{ + oldPendingExits_ = oldPendingExits; +} + +const ir::AstNode *BaseAnalyzer::GetJumpTarget(const ir::AstNode *node) const +{ + if (node->IsBreakStatement()) { + return node->AsBreakStatement()->Target(); + } + + ASSERT(node->IsContinueStatement()); + return node->AsContinueStatement()->Target(); +} + +LivenessStatus BaseAnalyzer::ResolveJump(const ir::AstNode *node, ir::AstNodeType jumpKind) +{ + bool resolved = false; + PendingExitsVector exits = pendingExits_; + pendingExits_ = oldPendingExits_; + + for (auto &it : exits) { + if (it.Node()->Type() == jumpKind && node == GetJumpTarget(it.Node())) { + it.ResolveJump(); + resolved = true; + } else { + pendingExits_.push_back(it); + } + } + + return From(resolved); +} + +LivenessStatus BaseAnalyzer::ResolveContinues(const ir::AstNode *node) +{ + oldPendingExits_.clear(); + return ResolveJump(node, ir::AstNodeType::CONTINUE_STATEMENT); +} + +LivenessStatus BaseAnalyzer::ResolveBreaks(const ir::AstNode *node) +{ + return ResolveJump(node, ir::AstNodeType::BREAK_STATEMENT); +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/baseAnalyzer.h b/checker/ets/baseAnalyzer.h new file mode 100644 index 000000000..de0168f82 --- /dev/null +++ b/checker/ets/baseAnalyzer.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_BASE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_BASE_ANALYZER_H + +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::ir { +class AstNode; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class ETSChecker; + +enum class LivenessStatus { DEAD, ALIVE }; + +DEFINE_BITOPS(LivenessStatus) + +class PendingExit { +public: + using JumpResolver = std::function; + + explicit PendingExit( + const ir::AstNode *node, JumpResolver jumpResolver = [] {}) + : node_(node), jumpResolver_(std::move(jumpResolver)) + { + } + ~PendingExit() = default; + + DEFAULT_COPY_SEMANTIC(PendingExit); + DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PendingExit); + + void ResolveJump() const + { + jumpResolver_(); + } + + const ir::AstNode *Node() const + { + return node_; + } + +private: + const ir::AstNode *node_; + JumpResolver jumpResolver_; +}; + +using PendingExitsVector = std::vector; + +class BaseAnalyzer { +public: + explicit BaseAnalyzer() = default; + + virtual void MarkDead() = 0; + + void RecordExit(const PendingExit &pe) + { + pendingExits_.push_back(pe); + MarkDead(); + } + + LivenessStatus From(bool value) + { + return value ? LivenessStatus::ALIVE : LivenessStatus::DEAD; + } + + LivenessStatus ResolveJump(const ir::AstNode *node, ir::AstNodeType jumpKind); + LivenessStatus ResolveContinues(const ir::AstNode *node); + LivenessStatus ResolveBreaks(const ir::AstNode *node); + const ir::AstNode *GetJumpTarget(const ir::AstNode *node) const; + +protected: + void ClearPendingExits(); + PendingExitsVector &PendingExits(); + void SetPendingExits(const PendingExitsVector &pendingExits); + PendingExitsVector &OldPendingExits(); + void SetOldPendingExits(const PendingExitsVector &oldPendingExits); + +private: + PendingExitsVector pendingExits_; + PendingExitsVector oldPendingExits_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/ets/boxingConverter.cpp b/checker/ets/boxingConverter.cpp new file mode 100644 index 000000000..051421e0a --- /dev/null +++ b/checker/ets/boxingConverter.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/ets/primitiveWrappers.h" + +namespace panda::es2panda::checker { + +void BoxingConverter::ETSTypeFromSource(Type *source) +{ + auto typeKind = checker::ETSChecker::TypeKind(source); + + auto wrapMap = Checker()->PrimitiveWrapper(); + + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_BOOLEAN_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::BYTE: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_BYTE_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::SHORT: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_SHORT_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::CHAR: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_CHAR_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::INT: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_INT_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::LONG: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_LONG_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::FLOAT: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_FLOAT_CLASS); + SetResult(res->second.first); + break; + } + case checker::TypeFlag::DOUBLE: { + auto res = wrapMap.find(compiler::Signatures::BUILTIN_DOUBLE_CLASS); + SetResult(res->second.first); + break; + } + default: + UNREACHABLE(); + } +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/boxingConverter.h b/checker/ets/boxingConverter.h new file mode 100644 index 000000000..4ab31c527 --- /dev/null +++ b/checker/ets/boxingConverter.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_BOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_BOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class BoxingConverter : public TypeConverter { +public: + BoxingConverter(ETSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!target->IsETSObjectType() || relation->IsTrue()) { + return; + } + + if (!source->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + Relation()->Result(false); + return; + } + + ETSTypeFromSource(source); + + Relation()->Result(relation->IsAssignableTo(Result(), target)); + } + + void ETSTypeFromSource(Type *source); +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/function.cpp b/checker/ets/function.cpp new file mode 100644 index 000000000..14aee0012 --- /dev/null +++ b/checker/ets/function.cpp @@ -0,0 +1,634 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsMethodReferenceExpression.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +bool ETSChecker::ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags) +{ + if ((arguments.size() < signature->MinArgCount()) || + (arguments.size() > signature->MinArgCount() && signature->RestVar() == nullptr)) { + if ((initialFlags & TypeRelationFlag::NO_THROW) == 0) { + ThrowTypeError({"Expected ", signature->MinArgCount(), " arguments, got ", arguments.size(), " ."}, pos); + } + + return false; + } + + uint32_t index = 0; + bool validateRest = false; + + for (; index < arguments.size(); index++) { + if (index >= signature->MinArgCount()) { + ASSERT(signature->RestVar()); + validateRest = true; + break; + } + + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + Relation(), arguments[index], argType, signature->Params()[index]->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's type at that index"}, + initialFlags); + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } + + if (((initialFlags & TypeRelationFlag::SELF_REFERENCE) != 0) && + !signature->HasSignatureFlag(SignatureFlags::STATIC | SignatureFlags::CONSTRUCTOR) && + (HasStatus(CheckerStatus::IN_STATIC_CONTEXT))) { + return false; + } + + if (!validateRest) { + return true; + } + + do { + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + Relation(), arguments[index], argType, signature->RestVar()->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's rest parameter type"}, + initialFlags); + index++; + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } while (index < arguments.size()); + + return true; +} + +Signature *ETSChecker::ValidateSignatures(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags) +{ + for (auto *sig : signatures) { + if (ValidateSignature(sig, arguments, pos, + flags | TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | + TypeRelationFlag::NO_BOXING)) { + return sig; + } + } + + for (auto *sig : signatures) { + if (ValidateSignature(sig, arguments, pos, flags | TypeRelationFlag::NO_THROW)) { + return sig; + } + } + + if ((flags & TypeRelationFlag::WIDENING) != 0) { + ThrowTypeError({"No matching ", signatureKind, " signature"}, pos); + } + + return nullptr; +} + +Signature *ETSChecker::ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, bool isIdentifier) +{ + auto flag = isIdentifier ? TypeRelationFlag::SELF_REFERENCE : TypeRelationFlag::NONE; + + auto *sig = ValidateSignatures(signatures, arguments, pos, "call", flag); + + if (sig != nullptr) { + return sig; + } + + return ValidateSignatures(signatures, arguments, pos, "call", flag | TypeRelationFlag::WIDENING); +} + +Signature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos) +{ + auto *sig = ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::NONE); + + if (sig != nullptr) { + return sig; + } + + return ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::WIDENING); +} + +checker::ETSFunctionType *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) +{ + if (method->TsType() != nullptr) { + return method->TsType()->AsETSFunctionType(); + } + + bool isConstructSig = method->IsConstructor(); + + auto *funcType = BuildFunctionSignature(method->Function(), isConstructSig); + + auto overloadList = method->Overloads(); + + for (size_t baseFuncCounter = 0; baseFuncCounter < overloadList.size(); baseFuncCounter++) { + auto *currentFunc = overloadList.at(baseFuncCounter); + auto *overloadType = BuildFunctionSignature(currentFunc->Function(), isConstructSig); + CheckIdenticalOverloads(funcType, overloadType, currentFunc->Start()); + for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloadList.size(); + compareFuncCounter++) { + auto *compareFunc = overloadList.at(compareFuncCounter); + auto *compareOverloadType = BuildFunctionSignature(compareFunc->Function(), isConstructSig); + CheckIdenticalOverloads(overloadType, compareOverloadType, compareFunc->Start()); + } + currentFunc->SetTsType(overloadType); + funcType->AddCallSignature(currentFunc->Function()->Signature()); + } + + method->Id()->Variable()->SetTsType(funcType); + return funcType; +} + +void ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, + const lexer::SourcePosition &overloadStart) +{ + SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + Relation()->IsIdenticalTo(func, overload); + if (Relation()->IsTrue()) { + ThrowTypeError("Function already declared.", overloadStart); + } +} + +checker::ETSFunctionType *ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) +{ + auto *nameVar = func->Id()->Variable(); + + auto *signatureInfo = CreateSignatureInfo(); + signatureInfo->restVar = nullptr; + signatureInfo->minArgCount = 0; + + if ((func->IsConstructor() || !func->IsStatic()) && + !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + auto *thisVar = func->Scope()->ParamScope()->Params().front(); + thisVar->SetTsType(Context().ContainingClass()); + } + + for (auto *it : func->Params()) { + if (it->IsRestElement()) { + auto *restParam = it->AsRestElement(); + ASSERT(restParam->Argument()->IsIdentifier()); + + auto *restIdent = restParam->Argument()->AsIdentifier(); + + ASSERT(restIdent->Variable()); + signatureInfo->restVar = restIdent->Variable()->AsLocalVariable(); + + ASSERT(restParam->TypeAnnotation()); + signatureInfo->restVar->SetTsType(restParam->TypeAnnotation()->GetType(this)); + break; + } + + ASSERT(it->IsIdentifier()); + auto *paramIdent = it->AsIdentifier(); + + ASSERT(paramIdent->Variable()); + binder::Variable *paramVar = paramIdent->Variable(); + + ASSERT(paramIdent->TypeAnnotation()); + paramVar->SetTsType(paramIdent->TypeAnnotation()->GetType(this)); + signatureInfo->params.push_back(paramVar->AsLocalVariable()); + signatureInfo->minArgCount++; + } + + auto *returnTypeAnnotation = func->ReturnTypeAnnotation(); + checker::Type *returnType {}; + + ASSERT(returnTypeAnnotation || func->IsConstructor() || func->IsStaticBlock()); + + if (returnTypeAnnotation != nullptr) { + returnType = returnTypeAnnotation->GetType(this); + returnTypeAnnotation->SetTsType(returnType); + } else { + returnType = GlobalVoidType(); + } + + auto *signature = CreateSignature(signatureInfo, returnType, func); + signature->SetOwner(Context().ContainingClass()); + + if (isConstructSig) { + signature->AddSignatureFlag(SignatureFlags::CONSTRUCT); + } else { + signature->AddSignatureFlag(SignatureFlags::CALL); + } + + auto *funcType = CreateETSFunctionType(signature); + func->SetSignature(signature); + funcType->SetVariable(nameVar); + + if (func->IsAbstract()) { + signature->AddSignatureFlag(SignatureFlags::ABSTRACT); + signature->AddSignatureFlag(SignatureFlags::VIRTUAL); + } + + if (func->IsStatic()) { + signature->AddSignatureFlag(SignatureFlags::STATIC); + } + + if (func->IsConstructor()) { + signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR); + } + + if (func->IsOpen()) { + if (!(func->Signature()->Owner()->GetDeclNode()->IsOpen() || + func->Signature()->Owner()->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT))) { + ThrowTypeError("Only open or abstract classes can have open method", func->Start()); + } + signature->AddSignatureFlag(SignatureFlags::OPEN); + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } + + if (func->IsPublic()) { + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } else if (func->IsProtected()) { + signature->AddSignatureFlag(SignatureFlags::PROTECTED); + } else if (func->IsPrivate()) { + signature->AddSignatureFlag(SignatureFlags::PRIVATE); + } + + nameVar->SetTsType(funcType); + + return funcType; +} + +Signature *ETSChecker::CheckEveryAbstractSignatureIsOverriden(ETSFunctionType *target, ETSFunctionType *source) +{ + for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) { + if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + continue; + } + + bool isOverridden = false; + for (auto sourceSig : source->CallSignatures()) { + Relation()->IsIdenticalTo(*targetSig, sourceSig); + if (Relation()->IsTrue() && (*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name()) { + target->CallSignatures().erase(targetSig); + isOverridden = true; + break; + } + sourceSig++; + } + + if (!isOverridden) { + return *targetSig; + } + } + + return nullptr; +} + +bool ETSChecker::IsOverridableIn(Signature *signature) +{ + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return false; + } + + if (signature->HasSignatureFlag(SignatureFlags::PUBLIC)) { + return FindAncestorGivenByType(signature->Function(), ir::AstNodeType::TS_INTERFACE_DECLARATION) == nullptr || + signature->HasSignatureFlag(SignatureFlags::STATIC); + } + + return signature->HasSignatureFlag(SignatureFlags::PROTECTED); +} + +bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source) +{ + if (source->Function()->IsConstructor()) { + return false; + } + + if (target == source) { + return true; + } + + if (IsOverridableIn(target)) { + SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + Relation()->IsIdenticalTo(target, source); + if (Relation()->IsTrue()) { + if (!source->Function()->IsOverride()) { + ThrowTypeError("Method overriding requires 'override' modifier", source->Function()->Start()); + } + return true; + } + } + + return false; +} + +std::tuple ETSChecker::CheckOverride(Signature *signature, Signature *other) +{ + if (signature->HasSignatureFlag(SignatureFlags::STATIC) != other->HasSignatureFlag(SignatureFlags::STATIC)) { + return {false, OverrideErrorCode::OVERRIDING_STATIC}; + } + + if (!(other->HasSignatureFlag(SignatureFlags::OPEN) || other->Function()->IsOverride())) { + return {false, OverrideErrorCode::OVERRIDEN_NOT_OPEN}; + } + + if (!IsTypeAssignableTo(signature->ReturnType(), other->ReturnType())) { + return {false, OverrideErrorCode::INCOMPATIBLE_RETURN}; + } + + if (signature->ProtectionFlag() > other->ProtectionFlag()) { + return {false, OverrideErrorCode::OVERRIDEN_WEAKER}; + } + + return {true, OverrideErrorCode::NO_ERROR}; +} + +bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) +{ + auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD); + bool isOverridingAnySignature = false; + + if (target == nullptr) { + return isOverridingAnySignature; + } + + for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + isOverridingAnySignature = true; + continue; + } + + if (!IsMethodOverridesOther(it, signature)) { + continue; + } + + auto [success, errorCode] = CheckOverride(signature, it); + + if (!success) { + const char *reason {}; + switch (errorCode) { + case OverrideErrorCode::OVERRIDING_STATIC: { + reason = "overriding method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_STATIC: { + reason = "overriden method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_NOT_OPEN: { + reason = "overriden method is not open."; + break; + } + case OverrideErrorCode::INCOMPATIBLE_RETURN: { + reason = "overriding return type is not compatible with the other return type."; + break; + } + case OverrideErrorCode::OVERRIDEN_WEAKER: { + reason = "overriden method has weaker access privilage."; + break; + } + default: { + UNREACHABLE(); + } + } + + ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " cannot override ", it->Function()->Id()->Name(), it, " in ", it->Owner(), " because ", + reason}, + signature->Function()->Start()); + } + + isOverridingAnySignature = true; + it->AddSignatureFlag(SignatureFlags::VIRTUAL); + signature->AddSignatureFlag(SignatureFlags::OPEN); + } + + return isOverridingAnySignature; +} + +void ETSChecker::CheckOverride(Signature *signature) +{ + auto *owner = signature->Owner(); + bool isOverriding = false; + + if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::ENUM)) { + return; + } + + ETSObjectType *iter = owner->SuperType(); + + for (auto *it : owner->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + while (iter != nullptr) { + isOverriding |= CheckOverride(signature, iter); + + for (auto *it : iter->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + iter = iter->SuperType(); + } + + if (!isOverriding && signature->Function()->IsOverride()) { + ThrowTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " not overriding any method"}, + signature->Function()->Start()); + } +} + +Signature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef) +{ + ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType()); + + for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) { + if (it->Function() == methodDef->Function()) { + return it; + } + } + + return nullptr; +} + +void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, Signature *signature, + const lexer::SourcePosition &pos) +{ + if (!signature->HasSignatureFlag(SignatureFlags::CONSTRUCTOR) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT) && + !signature->HasSignatureFlag(SignatureFlags::STATIC)) { + ThrowTypeError( + {"Can not reference ", signature->Function()->Id()->Name(), " instance method in a static context."}, pos); + } + + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + if (Context().ContainingClass() == callee && callee->IsSignatureInherited(signature)) { + return; + } + + auto *currentOutermost = Context().ContainingClass()->OutermostClass(); + auto *objOutermost = callee->OutermostClass(); + + if (currentOutermost != nullptr && objOutermost != nullptr && currentOutermost == objOutermost && + callee->IsSignatureInherited(signature)) { + return; + } + + ThrowTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos); + } +} + +void ETSChecker::ResolveLambdaObject(ir::ETSMethodReferenceExpression *methodRef, ETSObjectType *functionalInterface) +{ + auto *signatureRef = methodRef->ComputedSignature(); + auto *targetType = methodRef->TargetType(); + auto *lambdaObject = methodRef->LambdaObject(); + + auto *field = lambdaObject->Body()[0]->AsClassProperty(); + auto *fieldVar = field->Key()->AsIdentifier()->Variable(); + field->SetTsType(targetType); + fieldVar->SetTsType(targetType); + + auto *ctorFunc = lambdaObject->Body()[1]->AsMethodDefinition()->Function(); + ctorFunc->Params()[0]->AsIdentifier()->Variable()->SetTsType(targetType); + + auto *lambdaObjectType = Allocator()->New(Allocator(), lambdaObject->Ident()->Name(), + lambdaObject->Ident()->Name(), lambdaObject, + checker::ETSObjectFlags::CLASS); + lambdaObjectType->AddInterface(functionalInterface); + lambdaObject->SetTsType(lambdaObjectType); + + lambdaObjectType->AddProperty(fieldVar->AsLocalVariable()); + + ResolveLambdaObjectCtor(lambdaObject); + ResolveLambdaObjectInvoke(lambdaObject, signatureRef); +} + +void ETSChecker::ResolveLambdaObjectCtor(ir::ClassDefinition *lambdaObject) +{ + auto *ctorFunc = lambdaObject->Body()[1]->AsMethodDefinition()->Function(); + ETSObjectType *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType(); + + auto *thisVar = ctorFunc->Scope()->ParamScope()->Params().front(); + thisVar->SetTsType(lambdaObjectType); + + auto *ctorSignatureInfo = CreateSignatureInfo(); + ctorSignatureInfo->restVar = nullptr; + ctorSignatureInfo->minArgCount = 1; + ctorSignatureInfo->params.push_back(ctorFunc->Params()[0]->AsIdentifier()->Variable()->AsLocalVariable()); + auto *ctorSignature = CreateSignature(ctorSignatureInfo, GlobalVoidType(), ctorFunc); + ctorSignature->SetOwner(lambdaObjectType); + ctorSignature->AddSignatureFlag(checker::SignatureFlags::CONSTRUCTOR | checker::SignatureFlags::CONSTRUCT); + lambdaObjectType->AddConstructSignature(ctorSignature); + + auto *ctorType = CreateETSFunctionType(ctorSignature); + ctorFunc->SetSignature(ctorSignature); + ctorFunc->Id()->Variable()->SetTsType(ctorType); + + auto *savedClass = Context().ContainingClass(); + Context().SetContainingClass(lambdaObjectType); + ctorFunc->Body()->Check(this); + Context().SetContainingClass(savedClass); +} + +void ETSChecker::ResolveLambdaObjectInvoke(ir::ClassDefinition *lambdaObject, Signature *signatureRef) +{ + auto *invokeFunc = lambdaObject->Body()[2]->AsMethodDefinition()->Function(); + ETSObjectType *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType(); + + auto *thisVar = invokeFunc->Scope()->ParamScope()->Params().front(); + thisVar->SetTsType(lambdaObjectType); + + auto *invokeSignatureInfo = CreateSignatureInfo(); + invokeSignatureInfo->restVar = nullptr; + + for (auto *it : signatureRef->Params()) { + auto paramCtx = + binder::LexicalScope::Enter(Binder(), invokeFunc->Scope()->ParamScope(), false); + + auto *paramIdent = Allocator()->New(it->Name(), Allocator()); + auto [_, var] = Binder()->AddParamDecl(paramIdent); + (void)_; + var->SetTsType(it->TsType()); + paramIdent->SetVariable(var); + invokeFunc->Params().push_back(paramIdent); + invokeSignatureInfo->minArgCount++; + invokeSignatureInfo->params.push_back(var->AsLocalVariable()); + } + + auto *invokeSignature = CreateSignature(invokeSignatureInfo, signatureRef->ReturnType(), invokeFunc); + invokeSignature->SetOwner(lambdaObjectType); + invokeSignature->AddSignatureFlag(checker::SignatureFlags::CALL); + + auto *invokeType = CreateETSFunctionType(invokeSignature); + invokeFunc->SetSignature(invokeSignature); + invokeFunc->Id()->Variable()->SetTsType(invokeType); + lambdaObjectType->AddProperty( + invokeFunc->Id()->Variable()->AsLocalVariable()); + + invokeFunc->Body()->AsBlockStatement()->Statements().push_back( + ResolveLambdaObjectInvokeFuncBody(lambdaObject, signatureRef)); +} + +ir::Statement *ETSChecker::ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition *lambdaObject, Signature *signatureRef) +{ + auto *fieldProp = lambdaObject->Body()[0]->AsClassProperty()->Key()->AsIdentifier()->Variable(); + auto *fieldPropType = fieldProp->TsType()->AsETSObjectType(); + auto *fieldIdent = Allocator()->New("field0", Allocator()); + fieldIdent->SetVariable(fieldProp); + fieldIdent->SetTsType(fieldPropType); + + auto *funcIdent = Allocator()->New(signatureRef->Function()->Id()->Name(), Allocator()); + auto *callee = Allocator()->New(fieldIdent, funcIdent, + ir::MemberExpressionKind::ELEMENT_ACCESS, false, false); + auto *found = + fieldPropType->GetProperty(signatureRef->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD); + callee->SetPropVar(found); + callee->SetObjectType(fieldPropType); + callee->SetTsType(found->TsType()); + + auto *invokeFunc = lambdaObject->Body()[2]->AsMethodDefinition()->Function(); + ArenaVector callParams(Allocator()->Adapter()); + for (size_t idx = 0; idx != signatureRef->Params().size(); idx++) { + auto *param = Allocator()->New(signatureRef->Params()[idx]->Name(), Allocator()); + param->SetVariable(invokeFunc->Params()[idx]->AsIdentifier()->Variable()); + param->SetTsType(invokeFunc->Params()[idx]->AsIdentifier()->Variable()->TsType()); + callParams.push_back(param); + } + + auto *resolvedCall = Allocator()->New(callee, std::move(callParams), nullptr, false); + resolvedCall->SetTsType(signatureRef->ReturnType()); + resolvedCall->SetSignature(signatureRef); + + return Allocator()->New(resolvedCall); +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/helpers.cpp b/checker/ets/helpers.cpp new file mode 100644 index 000000000..504780f9c --- /dev/null +++ b/checker/ets/helpers.cpp @@ -0,0 +1,998 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/binder/variableFlags.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/checkerContext.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/lexer/token/tokenType.h" +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchCaseStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/literals/charLiteral.h" +#include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsMethodReferenceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +void ETSChecker::CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos) +{ + auto *unboxedType = ETSBuiltinTypeAsPrimitiveType(type); + + if (unboxedType == nullptr || !unboxedType->IsETSBooleanType()) { + ThrowTypeError("Condition must be of type boolean", pos); + } +} + +Type *ETSChecker::GetDefaultTypeFromPrimitiveType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + return type; + } + + if (type->HasTypeFlag(TypeFlag::LONG)) { + return GlobalLongType(); + } + + if (type->HasTypeFlag(TypeFlag::ETS_INTEGRAL)) { + return GlobalIntType(); + } + + if (type->HasTypeFlag(TypeFlag::FLOAT | TypeFlag::DOUBLE)) { + return GlobalDoubleType(); + } + + if (type->IsETSBooleanType()) { + return GlobalETSBooleanType(); + } + return type; +} + +bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type) +{ + return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression())); +} + +Type *ETSChecker::GetTypeOfVariable(binder::Variable *var) +{ + if (var->TsType() != nullptr) { + return var->TsType(); + } + + binder::Decl *decl = var->Declaration(); + + switch (decl->Type()) { + case binder::DeclType::CLASS: { + auto *classDef = decl->Node()->AsClassDefinition(); + BuildClassProperties(classDef); + return classDef->TsType(); + } + case binder::DeclType::ENUM_LITERAL: + case binder::DeclType::CONST: + case binder::DeclType::LET: + case binder::DeclType::VAR: { + auto *declNode = decl->Node(); + + if (decl->Node()->IsIdentifier()) { + declNode = declNode->Parent(); + } + + return declNode->Check(this); + } + case binder::DeclType::FUNC: { + return decl->Node()->Check(this); + } + default: { + UNREACHABLE(); + } + } + + return var->TsType(); +} + +void ETSChecker::ValidatePropertyAccess(binder::Variable *var, ETSObjectType *obj, const lexer::SourcePosition &pos) +{ + if (var->HasFlag(binder::VariableFlags::METHOD)) { + return; + } + + if (var->HasFlag(binder::VariableFlags::PROPERTY) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT) && + !var->HasFlag(binder::VariableFlags::STATIC)) { + ThrowTypeError({"Can not reference ", var->Name(), " instance field in a static context."}, pos); + } + + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + if (Context().ContainingClass() == obj && obj->IsPropertyInherited(var)) { + return; + } + + auto *currentOutermost = Context().ContainingClass()->OutermostClass(); + auto *objOutermost = obj->OutermostClass(); + + if (currentOutermost != nullptr && objOutermost != nullptr && currentOutermost == objOutermost && + obj->IsPropertyInherited(var)) { + return; + } + + ThrowTypeError({"Property ", var->Name(), " is not visible here."}, pos); + } +} + +std::tuple ETSChecker::GetClassScopeFromClass(ETSObjectType *classType) +{ + auto *currentClsScope = classType->GetDeclNode()->IsClassDefinition() + ? classType->GetDeclNode()->AsClassDefinition()->Scope() + : classType->GetDeclNode()->AsTSInterfaceDeclaration()->Scope(); + return {currentClsScope, classType->HasObjectFlag(ETSObjectFlags::INNER)}; +} + +binder::Variable *ETSChecker::FindVariableInClass(util::StringView name) +{ + binder::Variable *resolved = nullptr; + ETSObjectType *classIter = Context().ContainingClass(); + auto *scopeIter = Scope(); + + auto [currentClsScope, inInnerClass] = GetClassScopeFromClass(classIter); + + while (scopeIter != nullptr) { + resolved = scopeIter->FindLocal(name, binder::ResolveBindingOptions::ALL); + + if (resolved != nullptr) { + break; + } + + if (scopeIter == currentClsScope) { + if (classIter->SuperType() != nullptr) { + resolved = classIter->SuperType()->GetProperty(name, PropertySearchFlags::SEARCH_ALL | + PropertySearchFlags::SEARCH_IN_BASE | + PropertySearchFlags::SEARCH_IN_INTERFACES); + } + + if (!inInnerClass || resolved != nullptr) { + return resolved; + } + + classIter = classIter->EnclosingType(); + std::tie(currentClsScope, inInnerClass) = GetClassScopeFromClass(classIter); + } + + scopeIter = scopeIter->Parent(); + } + + return resolved; +} + +Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) +{ + binder::Variable *resolved = FindVariableInClass(ident->Name()); + + if (resolved == nullptr) { + // If the reference is not found already in the current class, then it is not bound to the class, so we have to + // find the reference in the global class first, then in the global scope + auto *scopeIter = Scope(); + while (!scopeIter->Parent()->IsGlobalScope()) { + scopeIter = scopeIter->Parent(); + } + + resolved = scopeIter->FindLocal(ident->Name(), binder::ResolveBindingOptions::ALL); + + if (resolved == nullptr) { + resolved = scopeIter->Parent()->FindLocal(ident->Name(), binder::ResolveBindingOptions::ALL); + } + } + + if (resolved == nullptr) { + ThrowTypeError({"Unresolved reference ", ident->Name()}, ident->Start()); + } + + auto *resolvedType = GetTypeOfVariable(resolved); + + switch (ident->Parent()->Type()) { + case ir::AstNodeType::CALL_EXPRESSION: { + if (ident->Parent()->AsCallExpression()->Callee() == ident && !resolvedType->IsETSFunctionType()) { + resolved = nullptr; + } + + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + if (ident->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == ident && + !resolved->HasFlag(binder::VariableFlags::CLASS_OR_INTERFACE)) { + resolved = nullptr; + } + + break; + } + case ir::AstNodeType::ETS_METHOD_REFERENCE_EXPRESSION: { + if (ident->Parent()->AsETSMethodReferenceExpression()->Base() == nullptr && + !resolvedType->IsETSFunctionType()) { + resolved = nullptr; + } + + break; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + if (ident->Parent()->AsMemberExpression()->IsComputed()) { + if (!resolved->Declaration()->PossibleTDZ()) { + resolved = nullptr; + } + + break; + } + + if (!resolvedType->IsETSObjectType() && !resolvedType->IsETSArrayType()) { + resolved = nullptr; + } + + break; + } + case ir::AstNodeType::BINARY_EXPRESSION: { + auto *binaryExpr = ident->Parent()->AsBinaryExpression(); + if (binaryExpr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF && binaryExpr->Right() == ident) { + if (!resolvedType->IsETSObjectType()) { + resolved = nullptr; + } + + break; + } + + [[fallthrough]]; + } + case ir::AstNodeType::UPDATE_EXPRESSION: + case ir::AstNodeType::UNARY_EXPRESSION: { + if (!resolved->Declaration()->PossibleTDZ()) { + resolved = nullptr; + } + + break; + } + case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { + auto *assignmentExpr = ident->Parent()->AsAssignmentExpression(); + + if (assignmentExpr->Left() == ident && !resolved->Declaration()->PossibleTDZ()) { + resolved = nullptr; + break; + } + + if (assignmentExpr->Right() == ident) { + auto *targetType = assignmentExpr->Left()->TsType(); + ASSERT(targetType != nullptr); + + if (targetType->IsETSObjectType() && + targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { + if (!resolvedType->IsETSFunctionType()) { + resolved = nullptr; + } + + break; + } + + if (!resolved->Declaration()->PossibleTDZ()) { + resolved = nullptr; + break; + } + } + + break; + } + default: { + if (!resolved->Declaration()->PossibleTDZ() && !resolvedType->IsETSFunctionType()) { + resolved = nullptr; + } + + break; + } + } + + if (resolved == nullptr) { + ThrowTypeError({"Unresolved reference ", ident->Name()}, ident->Start()); + } + + if (resolved->HasFlag(binder::VariableFlags::METHOD)) { + ASSERT(resolved->TsType()->IsETSFunctionType() && + !resolved->TsType()->AsETSFunctionType()->CallSignatures().empty()); + auto *funcType = resolved->TsType()->AsETSFunctionType(); + + // In the case of function references, it is not enough to find the first method field and use it's function + // type, beause at the position of the call we should be able to work with every possible signature, even with + // ones that came from base classes. + resolved = funcType->CallSignatures()[0]->Owner()->CreateSyntheticVarFromEverySignature( + ident->Name(), PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_IN_BASE); + } + + ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start()); + ident->SetVariable(resolved); + return resolved->TsType(); +} + +void ETSChecker::ValidateUnaryOperatorOperand(binder::Variable *variable) +{ + if (variable->Declaration()->IsConstDecl()) { + if (HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) && + !variable->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + ThrowTypeError({"Cannot reassign constant field ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + if (!HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK)) { + ThrowTypeError({"Cannot assign to a constant variable ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + } +} + +std::tuple ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test) +{ + Type *unboxedL = ETSBuiltinTypeAsPrimitiveType(left); + Type *unboxedR = ETSBuiltinTypeAsPrimitiveType(right); + + if (unboxedL == nullptr || unboxedR == nullptr) { + return {nullptr, false}; + } + + if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) { + return {nullptr, false}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT)) { + return {nullptr, true}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::ETS_NUMERIC) && unboxedR->HasTypeFlag(TypeFlag::ETS_NUMERIC)) { + if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) { + return {GlobalDoubleType(), false}; + } + + if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) { + return {GlobalFloatType(), false}; + } + + if (unboxedL->IsLongType() || unboxedR->IsLongType()) { + return {GlobalLongType(), false}; + } + + return {GlobalIntType(), false}; + } + + if (IsTypeIdenticalTo(unboxedL, unboxedR)) { + return {unboxedL, false}; + } + + return {GlobalETSObjectType(), false}; +} + +Type *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, bool createConst) +{ + Type *unboxedType = ETSBuiltinTypeAsPrimitiveType(type); + + if (unboxedType == nullptr) { + return nullptr; + } + + switch (ETSType(unboxedType)) { + case TypeFlag::BYTE: + case TypeFlag::SHORT: + case TypeFlag::CHAR: { + if (!createConst) { + return GlobalIntType(); + } + + return CreateIntTypeFromType(unboxedType); + } + default: { + return unboxedType; + } + } +} + +Type *ETSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType) +{ + using UType = typename ETSBooleanType::UType; + ASSERT(leftType->IsETSBooleanType() && rightType->IsETSBooleanType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalETSBooleanType(); + } + + UType leftValue = leftType->AsETSBooleanType()->GetValue(); + UType rightValue = rightType->AsETSBooleanType()->GetValue(); + + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + return CreateETSBooleanType(leftValue ^ rightValue); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + return CreateETSBooleanType((static_cast(leftValue) & static_cast(rightValue)) != 0); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + return CreateETSBooleanType((static_cast(leftValue) | static_cast(rightValue)) != 0); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + return CreateETSBooleanType(leftValue || rightValue); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + return CreateETSBooleanType(leftValue && rightValue); + } + default: { + break; + } + } + + UNREACHABLE(); + return nullptr; +} + +checker::Type *ETSChecker::CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation, + ir::Expression *init, ir::ModifierFlags flags) +{ + const util::StringView &varName = ident->Name(); + ASSERT(ident->Variable()); + binder::Variable *bindingVar = ident->Variable(); + checker::Type *annotationType = nullptr; + + bool isConst = (flags & ir::ModifierFlags::CONST) != 0; + + if (typeAnnotation != nullptr) { + annotationType = typeAnnotation->GetType(this); + bindingVar->SetTsType(annotationType); + } + + if (init == nullptr) { + return annotationType; + } + + checker::Type *initType = init->Check(this); + + if (annotationType != nullptr) { + AssignmentContext(Relation(), init, initType, annotationType, init->Start(), + {"Initializers type is not assignable to the target type"}); + if (isConst && initType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + bindingVar->SetTsType(init->TsType()); + } + } else { + bindingVar->SetTsType(isConst ? initType : GetDefaultTypeFromPrimitiveType(initType)); + + if (bindingVar->TsType()->IsETSNullType()) { + ThrowTypeError({"Cannot infer type for variable '", varName, "'."}, init->Start()); + } + + if (initType->IsETSObjectType() && initType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::ENUM) && + !init->IsMemberExpression()) { + ThrowTypeError( + {"Cannot assign type '", initType->AsETSObjectType()->Name(), "' for variable ", varName, "."}, + init->Start()); + } + } + + return bindingVar->TsType(); +} + +Type *ETSChecker::GetTypeFromInterfaceReference(binder::Variable *var) +{ + if (var->TsType() != nullptr) { + return var->TsType(); + } + + auto *interfaceType = BuildInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); + var->SetTsType(interfaceType); + return interfaceType; +} + +Type *ETSChecker::GetTypeFromClassReference(binder::Variable *var) +{ + if (var->TsType() != nullptr) { + return var->TsType(); + } + + auto *classType = BuildClassProperties(var->Declaration()->Node()->AsClassDefinition()); + var->SetTsType(classType); + return classType; +} + +Type *ETSChecker::GetTypeFromEnumReference([[maybe_unused]] binder::Variable *var) +{ + if (var->TsType() != nullptr) { + return var->TsType(); + } + + return CreateETSEnumType(var->Declaration()->Node()->AsTSEnumDeclaration()); +} + +Type *ETSChecker::GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos) +{ + if (HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError({"Cannot make a static reference to the non-static type ", var->Name()}, pos); + } + + auto *typeParam = var->TsType()->AsETSTypeParameter(); + return CreateTypeReference(typeParam->GetTypeRef(), typeParam->GetAssemblerTypeRef(), var); +} + +Type *ETSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name) +{ + // TODO(user): + return nullptr; +} + +Type *ETSChecker::GetReferencedTypeBase(ir::Expression *name) +{ + if (name->IsTSQualifiedName()) { + // TODO(user): + return nullptr; + } + + ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable()); + auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable(); + + switch (refVar->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return GetTypeFromInterfaceReference(refVar); + } + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: { + return GetTypeFromClassReference(refVar); + } + case ir::AstNodeType::TS_ENUM_DECLARATION: { + return GetTypeFromEnumReference(refVar); + } + case ir::AstNodeType::TS_TYPE_PARAMETER: { + return GetTypeFromTypeParameterReference(refVar, name->Start()); + } + default: { + UNREACHABLE(); + } + } +} + +void ETSChecker::ConcantConstantString(util::UString &target, Type *type) +{ + switch (ETSType(type)) { + case TypeFlag::ETS_OBJECT: { + ASSERT(type->IsETSStringType()); + target.Append(type->AsETSStringType()->GetValue()); + break; + } + case TypeFlag::ETS_BOOLEAN: { + ETSBooleanType::UType value = type->AsETSBooleanType()->GetValue(); + target.Append(value ? "true" : "false"); + break; + } + case TypeFlag::BYTE: { + ByteType::UType value = type->AsByteType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::CHAR: { + CharType::UType value = type->AsCharType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::SHORT: { + ShortType::UType value = type->AsShortType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::INT: { + IntType::UType value = type->AsIntType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::LONG: { + LongType::UType value = type->AsLongType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::FLOAT: { + FloatType::UType value = type->AsFloatType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::DOUBLE: { + DoubleType::UType value = type->AsDoubleType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + default: { + UNREACHABLE(); + } + } +} + +Type *ETSChecker::HandleStringConcatenation(Type *leftType, Type *rightType) +{ + ASSERT(leftType->IsETSStringType() || rightType->IsETSStringType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalETSStringLiteralType(); + } + + util::UString concatenated(Allocator()); + ConcantConstantString(concatenated, leftType); + ConcantConstantString(concatenated, rightType); + + return CreateETSStringLiteralType(concatenated.View()); +} + +ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView name, + ArenaVector &list) +{ + for (auto *it : list) { + if (it->Name() == name) { + return it; + } + } + + return nullptr; +} + +bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + Relation()->IsIdenticalTo(it, signature); + if (Relation()->IsTrue()) { + return true; + } + } + + return false; +} + +void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + Relation()->IsIdenticalTo(it, signature); + if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { + std::stringstream ss; + it->ToString(ss, nullptr, true); + auto sigStr1 = ss.str(); + ss.str(std::string {}); // Clear buffer + signature->ToString(ss, nullptr, true); + auto sigStr2 = ss.str(); + ThrowTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(), + "' is redeclared with different signature '", signature->Function()->Id()->Name(), + sigStr2.c_str(), "'"}, + signature->Function()->ReturnTypeAnnotation()->Start()); + } + } +} + +void ETSChecker::MergeSignatures(ETSFunctionType *target, ETSFunctionType *source) +{ + for (auto *s : source->CallSignatures()) { + if (IsFunctionContainsSignature(target, s)) { + continue; + } + + CheckFunctionContainsClashingSignature(target, s); + target->AddCallSignature(s); + } +} + +void ETSChecker::MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t) +{ + for (auto *curr : current) { + auto name = curr->Name(); + auto *found = FindFunctionInVectorGivenByName(name, merged); + if (found != nullptr) { + MergeSignatures(found, curr); + continue; + } + + merged.push_back(curr); + } +} + +ir::AstNode *ETSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type) +{ + auto *iter = node->Parent(); + + while (iter != nullptr) { + if (iter->Type() == type) { + return iter; + } + + iter = iter->Parent(); + } + + return nullptr; +} + +util::StringView ETSChecker::GetContainingObjectNameFromSignature(Signature *signature) +{ + ASSERT(signature->Function()); + auto *iter = signature->Function()->Parent(); + + while (iter != nullptr) { + if (iter->IsClassDefinition()) { + return iter->AsClassDefinition()->Ident()->Name(); + } + + if (iter->IsTSInterfaceDeclaration()) { + return iter->AsTSInterfaceDeclaration()->Id()->Name(); + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return {""}; +} + +bool ETSChecker::IsTypeBuiltinType(Type *type) +{ + if (!type->IsETSObjectType()) { + return false; + } + + switch (type->AsETSObjectType()->BuiltInKind()) { + case ETSObjectFlags::BUILTIN_BOOLEAN: + case ETSObjectFlags::BUILTIN_BYTE: + case ETSObjectFlags::BUILTIN_SHORT: + case ETSObjectFlags::BUILTIN_CHAR: + case ETSObjectFlags::BUILTIN_INT: + case ETSObjectFlags::BUILTIN_LONG: + case ETSObjectFlags::BUILTIN_FLOAT: + case ETSObjectFlags::BUILTIN_DOUBLE: { + return true; + } + default: + return false; + } +} + +const ir::AstNode *ETSChecker::FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, + const ir::Identifier *target) +{ + const auto *iter = node->Parent(); + + while (iter != nullptr) { + switch (iter->Type()) { + case ir::AstNodeType::LABELLED_STATEMENT: { + const auto *labelled = iter->AsLabelledStatement(); + if (labelled->Ident() == target) { + if (nodeType == ir::AstNodeType::CONTINUE_STATEMENT) { + return labelled->GetReferencedStatement(); + } + + return labelled; + } + + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: + case ir::AstNodeType::WHILE_STATEMENT: + case ir::AstNodeType::FOR_UPDATE_STATEMENT: + case ir::AstNodeType::FOR_OF_STATEMENT: + case ir::AstNodeType::SWITCH_CASE_STATEMENT: + case ir::AstNodeType::SWITCH_STATEMENT: { + if (target == nullptr) { + return iter; + } + break; + } + default: { + break; + } + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return nullptr; +} + +binder::VariableFlags ETSChecker::GetAccessFlagFromNode(const ir::AstNode *node) +{ + if (node->IsPrivate()) { + return binder::VariableFlags::PRIVATE; + } + + if (node->IsProtected()) { + return binder::VariableFlags::PROTECTED; + } + + return binder::VariableFlags::PUBLIC; +} + +void ETSChecker::CheckSwitchDiscriminant(ir::Expression *discriminant) +{ + ASSERT(discriminant->TsType()); + + auto discriminantType = discriminant->TsType(); + if (discriminantType->HasTypeFlag(TypeFlag::VALID_SWITCH_TYPE)) { + return; + } + + if (discriminantType->IsETSObjectType() && + discriminantType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::VALID_SWITCH_TYPE)) { + return; + } + + ThrowTypeError({"Incompatible types. Found: ", discriminantType, + ", required: char , byte , short , int, long , Char , Byte , Short , Int, Long , String " + "or an enum type"}, + discriminant->Start()); +} + +Type *ETSChecker::ETSBuiltinTypeAsPrimitiveType(Type *objectType) +{ + if (objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + return objectType; + } + + if (!objectType->IsETSObjectType() || + !objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) { + return nullptr; + } + + auto savedResult = Relation()->IsTrue(); + Relation()->Result(false); + + UnboxingConverter converter = UnboxingConverter(AsETSChecker(), Relation(), objectType, objectType); + Relation()->Result(savedResult); + return converter.Result(); +} + +Type *ETSChecker::PrimitiveTypeAsETSBuiltinType(Type *objectType) +{ + if (objectType->IsETSObjectType() && objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE)) { + return objectType; + } + + if (!objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + return nullptr; + } + + auto savedResult = Relation()->IsTrue(); + Relation()->Result(false); + + BoxingConverter converter = BoxingConverter(AsETSChecker(), Relation(), objectType, objectType); + Relation()->Result(savedResult); + return converter.Result(); +} + +void ETSChecker::CheckForSameSwitchCases(ArenaVector *cases) +{ + for (size_t caseNum = 0; caseNum < cases->size(); caseNum++) { + for (size_t compareCase = caseNum + 1; compareCase < cases->size(); compareCase++) { + auto caseTest = cases->at(caseNum)->Test(); + auto compareCaseTest = cases->at(compareCase)->Test(); + if (caseTest == nullptr || compareCaseTest == nullptr) { + continue; + } + + caseTest = caseTest->IsMemberExpression() ? caseTest->AsMemberExpression()->Property() : caseTest; + compareCaseTest = compareCaseTest->IsMemberExpression() ? compareCaseTest->AsMemberExpression()->Property() + : compareCaseTest; + + if (caseTest->IsIdentifier()) { + CheckIdentifierSwitchCase(caseTest, compareCaseTest, cases->at(caseNum)->Start()); + continue; + } + + if (compareCaseTest->IsIdentifier()) { + CheckIdentifierSwitchCase(compareCaseTest, caseTest, cases->at(compareCase)->Start()); + continue; + } + + if (GetStringViewFromLiteral(caseTest).Compare(GetStringViewFromLiteral(compareCaseTest)) != 0) { + continue; + } + + ThrowTypeError("Case duplicate", cases->at(compareCase)->Start()); + } + } +} + +util::StringView ETSChecker::GetStringViewFromIdentifierValue(ir::Expression *identifier) +{ + ASSERT(identifier->AsIdentifier()->Variable()->TsType()); + auto identifierType = identifier->AsIdentifier()->Variable()->TsType(); + auto identifierTypeKind = ETSChecker::TypeKind(identifierType); + switch (identifierTypeKind) { + case TypeFlag::BYTE: { + return util::StringView(std::to_string(identifierType->AsByteType()->GetValue())); + } + case TypeFlag::SHORT: { + return util::StringView(std::to_string(identifierType->AsShortType()->GetValue())); + } + case TypeFlag::CHAR: { + return util::StringView(std::to_string(identifierType->AsCharType()->GetValue())); + } + case TypeFlag::INT: { + return util::StringView(std::to_string(identifierType->AsIntType()->GetValue())); + } + case TypeFlag::LONG: { + return util::StringView(std::to_string(identifierType->AsLongType()->GetValue())); + } + default: { + UNREACHABLE(); + } + } +} + +bool ETSChecker::CompareIdentifiersValuesAreDifferent(ir::Expression *identifier, ir::Expression *compareValue) +{ + auto caseValue = GetStringViewFromIdentifierValue(identifier); + if (compareValue->IsIdentifier() && compareValue->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) { + auto compareCaseValue = GetStringViewFromIdentifierValue(compareValue); + return caseValue.Compare(compareCaseValue) != 0; + } + + return caseValue.Compare(GetStringViewFromLiteral(compareValue)) != 0; +} + +void ETSChecker::CheckIdentifierSwitchCase(ir::Expression *currentCase, ir::Expression *compareCase, + const lexer::SourcePosition &pos) +{ + if (!currentCase->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) { + ThrowTypeError("Constant expression required", pos); + } + if (!CompareIdentifiersValuesAreDifferent(currentCase, compareCase)) { + ThrowTypeError("Variable has same value with another switch case", pos); + } +} + +util::StringView ETSChecker::GetStringViewFromLiteral(ir::Expression *caseTest) +{ + switch (caseTest->Type()) { + case ir::AstNodeType::CHAR_LITERAL: { + return util::StringView(std::to_string(caseTest->AsCharLiteral()->Char())); + } + case ir::AstNodeType::STRING_LITERAL: + case ir::AstNodeType::NUMBER_LITERAL: { + return util::Helpers::LiteralToPropName(caseTest); + } + default: + UNREACHABLE(); + } +} + +bool ETSChecker::IsSameDeclarationType(binder::LocalVariable *target, binder::LocalVariable *compare) +{ + if (target->Declaration()->Type() != compare->Declaration()->Type()) { + return false; + } + + if ((target->HasFlag(binder::VariableFlags::METHOD_REFERENCE) && + !compare->HasFlag(binder::VariableFlags::METHOD_REFERENCE)) || + (!target->HasFlag(binder::VariableFlags::METHOD_REFERENCE) && + compare->HasFlag(binder::VariableFlags::METHOD_REFERENCE))) { + return false; + } + + return true; +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingConverter.cpp b/checker/ets/narrowingConverter.cpp new file mode 100644 index 000000000..cb70ab143 --- /dev/null +++ b/checker/ets/narrowingConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "narrowingConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingConverter.h b/checker/ets/narrowingConverter.h new file mode 100644 index 000000000..c1d4e0afd --- /dev/null +++ b/checker/ets/narrowingConverter.h @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +class NarrowingConverter : public TypeConverter { +public: + explicit NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + if (!relation->ApplyNarrowing()) { + return; + } + + ASSERT(relation->GetNode()); + + switch (ETSChecker::ETSChecker::ETSType(target)) { + case TypeFlag::BYTE: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_BYTE); + break; + } + case TypeFlag::CHAR: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_CHAR); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_FLOAT); + break; + } + + default: { + break; + } + } + } + +private: + template + void ApplyNarrowing(TypeFlag flag) + { + if (!Source()->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(Source())) { + case TypeFlag::CHAR: { + ApplyNarrowing(); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(); + break; + } + case TypeFlag::DOUBLE: { + ApplyNarrowing(); + break; + } + default: { + break; + } + } + } + + template + void ApplyNarrowing() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(Source())->GetValue(); + + if (util::Helpers::IsTargetFitInSourceRange(value)) { + Relation()->GetNode()->SetTsType(Checker()->Allocator()->New(static_cast(value))); + Relation()->Result(true); + } else { + Relation()->Result(RelationResult::ERROR); + } + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/narrowingWideningConverter.cpp b/checker/ets/narrowingWideningConverter.cpp new file mode 100644 index 000000000..f79174d7f --- /dev/null +++ b/checker/ets/narrowingWideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingWideningConverter.h b/checker/ets/narrowingWideningConverter.h new file mode 100644 index 000000000..a20960981 --- /dev/null +++ b/checker/ets/narrowingWideningConverter.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/wideningConverter.h" + +namespace panda::es2panda::checker { +class NarrowingWideningConverter : public NarrowingConverter { +public: + explicit NarrowingWideningConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : NarrowingConverter(checker, relation, target, source) + { + if (Relation()->IsTrue() || Relation()->IsError()) { + return; + } + + WideningConverter(checker, relation, target, source); + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/object.cpp b/checker/ets/object.cpp new file mode 100644 index 000000000..6af955bb2 --- /dev/null +++ b/checker/ets/object.cpp @@ -0,0 +1,1039 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "plugins/ecmascript/es2panda/binder/variableFlags.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/superExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumMember.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReferencePart.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::checker { +ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) { + return type->SuperType(); + } + + ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition()); + auto *classDef = type->GetDeclNode()->AsClassDefinition(); + + if (classDef->Super() == nullptr) { + type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER); + if (type != GlobalETSObjectType()) { + type->SetSuperType(GlobalETSObjectType()); + } + return GlobalETSObjectType(); + } + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, classDef->Ident()->Start()); + + Type *superType = classDef->Super()->AsTypeNode()->GetType(this); + + if (!superType->IsETSObjectType() || !superType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + ThrowTypeError("Super type is not extensible.", classDef->Super()->Start()); + } + + ETSObjectType *superObj = superType->AsETSObjectType(); + + if (!(superObj->GetDeclNode()->IsOpen() || superObj->GetDeclNode()->IsAbstract())) { + ThrowTypeError("Cannot inherit without 'open'.", classDef->Super()->Start()); + } + + type->SetSuperType(superObj); + GetSuperType(superObj); + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER); + return type->SuperType(); +} + +void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface, + std::unordered_set *extendsSet, const lexer::SourcePosition &pos) +{ + if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + ThrowTypeError("Interface expected here.", pos); + } + + if (!extendsSet->insert(interface).second) { + ThrowTypeError("Repeated interface.", pos); + } + + type->AddInterface(interface->AsETSObjectType()); + GetInterfacesOfInterface(interface->AsETSObjectType()); +} + +ArenaVector ETSChecker::GetInterfacesOfClass(ETSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsClassDefinition(); + + std::unordered_set extendsSet; + for (auto *it : declNode->Implements()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector ETSChecker::GetInterfacesOfInterface(ETSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration(); + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, declNode->Id()->Start()); + + std::unordered_set extendsSet; + for (auto *it : declNode->Extends()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector ETSChecker::GetInterfaces(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) { + return type->Interfaces(); + } + + ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration()); + + if (type->GetDeclNode()->IsClassDefinition()) { + GetInterfacesOfClass(type); + } else { + GetInterfacesOfInterface(type); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES); + return type->Interfaces(); +} + +void ETSChecker::SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType) +{ + auto *var = typeParam->Name()->Variable(); + auto *typeParamType = CreateTypeParameter(assemblerType); + typeParamType->SetVariable(var); + var->SetTsType(typeParamType); +} + +void ETSChecker::CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) { + return; + } + + checker::ScopeContext scopeCtx(this, typeParams->Scope()); + + for (auto *param : typeParams->Params()) { + Type *paramType = GlobalETSObjectType(); + + if (param->Constraint() != nullptr) { + if (param->Constraint()->IsETSTypeReference() && + param->Constraint()->AsETSTypeReference()->Part()->Name()->IsIdentifier() && + param->Name()->Name() == + param->Constraint()->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name()) { + ThrowTypeError({"Type variable '", param->Name()->Name(), "' cannot depend on itself"}, + param->Constraint()->Start()); + } + + auto *constraintType = param->Constraint()->GetType(this); + if (!constraintType->IsETSObjectType() || !constraintType->IsETSTypeParameter()) { + ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start()); + } + + paramType = constraintType; + } + + SetTypeParameterType(param, paramType); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS); +} + +void ETSChecker::CreateTypeForInterfaceTypeParameters(ETSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +void ETSChecker::CreateTypeForClassTypeParameters(ETSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +ETSObjectType *ETSChecker::BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl) +{ + auto *var = interfaceDecl->Id()->Variable(); + ASSERT(var); + + checker::ETSObjectType *interfaceType {}; + if (var->TsType() == nullptr) { + interfaceType = CreateETSObjectType(var->Name(), interfaceDecl, + checker::ETSObjectFlags::INTERFACE | checker::ETSObjectFlags::ABSTRACT); + interfaceType->SetVariable(var); + var->SetTsType(interfaceType); + } else { + interfaceType = var->TsType()->AsETSObjectType(); + } + + if (interfaceDecl->TypeParams() != nullptr) { + CreateTypeForInterfaceTypeParameters(interfaceType); + } + + GetInterfacesOfInterface(interfaceType); + + checker::ScopeContext scopeCtx(this, interfaceDecl->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_INTERFACE, interfaceType); + + ResolveDeclaredMembersOfObject(interfaceType); + + return interfaceType; +} + +ETSObjectType *ETSChecker::BuildClassProperties(ir::ClassDefinition *classDef) +{ + if (classDef->IsOpen() && classDef->IsAbstract()) { + ThrowTypeError("Cannot use both 'open' and 'abstract' modifiers.", classDef->Start()); + } + + auto *var = classDef->Ident()->Variable(); + ASSERT(var); + + const util::StringView &className = classDef->Ident()->Name(); + auto *classScope = classDef->Scope(); + + checker::ETSObjectType *classType {}; + if (var->TsType() == nullptr) { + classType = CreateETSObjectType(className, classDef, checker::ETSObjectFlags::CLASS); + classType->SetVariable(var); + var->SetTsType(classType); + if (classDef->IsAbstract()) { + classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT); + } + } else { + classType = var->TsType()->AsETSObjectType(); + } + + classDef->SetTsType(classType); + + if (classDef->TypeParams() != nullptr) { + CreateTypeForClassTypeParameters(classType); + } + + if (!classType->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) { + GetSuperType(classType); + GetInterfacesOfClass(classType); + } + + if (classType->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) { + return classType; + } + + checker::ScopeContext scopeCtx(this, classScope); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType) +{ + auto classType = CreateETSObjectType(classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS); + classDef->SetTsType(classType); + classType->SetSuperType(superType); + classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER); + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +void ETSChecker::BuildEnumProperties(ETSObjectType *enumType) +{ + checker::ScopeContext scopeCtx(this, Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_ENUM, enumType); + + if (enumType->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) { + return; + } + + auto *declNode = enumType->GetDeclNode(); + auto *enumDecl = declNode->AsTSEnumDeclaration(); + + auto *valuesVar = binder::Scope::CreateVar(Allocator(), compiler::Signatures::ENUM_VALUES, + binder::VariableFlags::STATIC, declNode); + valuesVar->AddFlag(binder::VariableFlags::METHOD); + + valuesVar->SetTsType(CreateETSArrayType(enumType)); + enumType->AddProperty(valuesVar); + + for (auto *it : enumDecl->Members()) { + if (it->IsTSEnumMember()) { + auto *element = it->AsTSEnumMember(); + auto *var = element->Key()->AsIdentifier()->Variable(); + + enumType->AddProperty(var->AsLocalVariable()); + var->SetTsType(enumType); + } else if (it->IsMethodDefinition()) { + auto *method = it->AsMethodDefinition(); + BuildMethodSignature(method); + } else { + auto *func = it->AsScriptFunction(); + BuildFunctionSignature(func, true); + } + } + + enumType->AddObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS); +} + +void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) { + return; + } + + auto *declNode = type->GetDeclNode(); + binder::ClassScope *scope = declNode->IsTSInterfaceDeclaration() + ? declNode->AsTSInterfaceDeclaration()->Scope()->AsClassScope() + : declNode->AsClassDefinition()->Scope()->AsClassScope(); + + for (auto &[_, it] : scope->InstanceFieldScope()->Bindings()) { + (void)_; + ASSERT(it->Declaration()->Node()->IsClassProperty()); + auto *classProp = it->Declaration()->Node()->AsClassProperty(); + it->AddFlag(GetAccessFlagFromNode(classProp)); + type->AddProperty(it->AsLocalVariable()); + + if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) { + type->AddProperty(it->AsLocalVariable()); + it->AddFlag(binder::VariableFlags::METHOD_REFERENCE); + } + } + + for (auto &[_, it] : scope->StaticFieldScope()->Bindings()) { + (void)_; + ASSERT(it->Declaration()->Node()->IsClassProperty()); + auto *classProp = it->Declaration()->Node()->AsClassProperty(); + it->AddFlag(GetAccessFlagFromNode(classProp)); + type->AddProperty(it->AsLocalVariable()); + + if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) { + type->AddProperty(it->AsLocalVariable()); + it->AddFlag(binder::VariableFlags::METHOD_REFERENCE); + } + } + + for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) { + (void)_; + auto *node = it->Declaration()->Node()->AsMethodDefinition(); + it->AddFlag(GetAccessFlagFromNode(node)); + auto *funcType = BuildMethodSignature(node); + it->SetTsType(funcType); + funcType->SetVariable(it); + node->SetTsType(funcType); + type->AddProperty(it->AsLocalVariable()); + } + + for (auto &[_, it] : scope->StaticMethodScope()->Bindings()) { + (void)_; + if (!it->Declaration()->Node()->IsMethodDefinition()) { + continue; + } + auto *node = it->Declaration()->Node()->AsMethodDefinition(); + it->AddFlag(GetAccessFlagFromNode(node)); + auto *funcType = BuildMethodSignature(node); + it->SetTsType(funcType); + funcType->SetVariable(it); + node->SetTsType(funcType); + + if (node->IsConstructor()) { + type->AddConstructSignature(funcType->CallSignatures()); + continue; + } + + type->AddProperty(it->AsLocalVariable()); + } + + for (auto &[_, it] : scope->InstanceDeclScope()->Bindings()) { + (void)_; + it->AddFlag(GetAccessFlagFromNode(it->Declaration()->Node())); + type->AddProperty(it->AsLocalVariable()); + } + + for (auto &[_, it] : scope->StaticDeclScope()->Bindings()) { + (void)_; + it->AddFlag(GetAccessFlagFromNode(it->Declaration()->Node())); + type->AddProperty(it->AsLocalVariable()); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS); +} + +std::vector ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *objType) +{ + std::vector abstracts; + for (const auto &prop : objType->Methods()) { + GetTypeOfVariable(prop); + + if (!prop->TsType()->IsETSFunctionType()) { + continue; + } + + for (auto *sig : prop->TsType()->AsETSFunctionType()->CallSignatures()) { + if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) { + abstracts.push_back(sig); + } + } + } + + return abstracts; +} + +void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target) +{ + for (auto *it : abstracts) { + auto name = it->Function()->Id()->Name(); + auto *found = FindFunctionInVectorGivenByName(name, *target); + if (found != nullptr) { + found->AddCallSignature(it); + continue; + } + + auto *created = CreateETSFunctionType(it); + created->AddTypeFlag(TypeFlag::SYNTHETIC); + target->push_back(created); + } +} + +void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType) +{ + auto cached = cachedComputedAbstracts_.find(interfaceType); + if (cached != cachedComputedAbstracts_.end()) { + return; + } + + for (auto *it : interfaceType->Interfaces()) { + ComputeAbstractsFromInterface(it); + } + + ArenaVector merged(Allocator()->Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged); + std::unordered_set abstractInheritanceTarget; + + for (auto *interface : interfaceType->Interfaces()) { + auto found = cachedComputedAbstracts_.find(interface); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *base : found->second.second) { + abstractInheritanceTarget.insert(base); + } + } + + cachedComputedAbstracts_.insert({interfaceType, {merged, abstractInheritanceTarget}}); +} + +ArenaVector &ETSChecker::GetAbstractsForClass(ETSObjectType *classType) +{ + ArenaVector merged(Allocator()->Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged); + + std::unordered_set abstractInheritanceTarget; + if (classType->SuperType() != nullptr) { + auto base = cachedComputedAbstracts_.find(classType->SuperType()); + ASSERT(base != cachedComputedAbstracts_.end()); + MergeComputedAbstracts(merged, base->second.first); + + abstractInheritanceTarget.insert(base->first); + for (auto *it : base->second.second) { + abstractInheritanceTarget.insert(it); + } + } + + for (auto *it : classType->Interfaces()) { + ComputeAbstractsFromInterface(it); + auto found = cachedComputedAbstracts_.find(it); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *interface : found->second.second) { + abstractInheritanceTarget.insert(interface); + } + } + + return cachedComputedAbstracts_.insert({classType, {merged, abstractInheritanceTarget}}).first->second.first; +} + +void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos) +{ + if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) { + return; + } + + bool throwError = true; + if (classType->HasObjectFlag(ETSObjectFlags::ABSTRACT)) { + throwError = false; + } + + if (classType->SuperType() != nullptr) { + ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start()); + } + + auto &abstractsToBeImplemented = GetAbstractsForClass(classType); + std::vector implementedSignatures; + + auto *superIter = classType; + do { + for (auto &it : abstractsToBeImplemented) { + for (const auto &prop : superIter->Methods()) { + GetTypeOfVariable(prop); + AddImplementedSignature(&implementedSignatures, prop, it); + } + } + superIter = superIter->SuperType(); + } while (superIter != nullptr); + + SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); + bool functionOverridden; + bool foundSignature; + for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) { + functionOverridden = false; + for (auto abstractSignature = (*it)->CallSignatures().begin(); + abstractSignature != (*it)->CallSignatures().end();) { + foundSignature = false; + for (auto implemented : implementedSignatures) { + if (Relation()->IsIdenticalTo(*abstractSignature, implemented) && + (*abstractSignature)->Function()->Id()->Name() == implemented->Function()->Id()->Name() && + IsTypeAssignableTo(implemented->ReturnType(), (*abstractSignature)->ReturnType())) { + if (!implemented->Function()->IsOverride() && (implemented->Owner() == classType)) { + ThrowTypeError("Method overriding is only allowed with 'override' modifier", + implemented->Function()->Start()); + } + + if ((*it)->CallSignatures().size() > 1) { + abstractSignature = (*it)->CallSignatures().erase(abstractSignature); + foundSignature = true; + } else { + it = abstractsToBeImplemented.erase(it); + functionOverridden = true; + } + + implemented->AddSignatureFlag(SignatureFlags::OPEN); + break; + } + } + + if (functionOverridden) { + break; + } + + if (!foundSignature) { + abstractSignature++; + } + } + + if (!functionOverridden) { + it++; + } + } + + if (!abstractsToBeImplemented.empty() && throwError) { + auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front(); + ThrowTypeError({classType->Name(), " is not abstract and does not override abstract method ", + unimplementedSignature->Function()->Id()->Name(), unimplementedSignature, " in ", + GetContainingObjectNameFromSignature(unimplementedSignature)}, + pos); + } + + classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS); +} + +void ETSChecker::AddImplementedSignature(std::vector *implementedSignatures, + binder::LocalVariable *function, ETSFunctionType *it) +{ + if (!function->TsType()->IsETSFunctionType()) { + return; + } + + for (auto signature : function->TsType()->AsETSFunctionType()->CallSignatures()) { + if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) { + continue; + } + + if (signature->Function()->Id()->Name() == it->Name()) { + implementedSignatures->emplace_back(signature); + } + } +} + +void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) +{ + auto *classType = classDef->TsType()->AsETSObjectType(); + auto *enclosingClass = Context().ContainingClass(); + auto newStatus = checker::CheckerStatus::IN_CLASS; + classType->SetEnclosingType(enclosingClass); + + if (!classDef->IsStatic() && enclosingClass != nullptr && !enclosingClass->HasObjectFlag(ETSObjectFlags::GLOBAL)) { + newStatus |= CheckerStatus::INNER_CLASS; + classType->AddObjectFlag(checker::ETSObjectFlags::INNER); + } + + if (classDef->IsGlobal()) { + classType->AddObjectFlag(checker::ETSObjectFlags::GLOBAL); + } + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = SavedCheckerContext(this, newStatus, classType); + + if (classDef->IsAbstract()) { + AddStatus(checker::CheckerStatus::IN_ABSTRACT); + classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT); + } + + if (classDef->IsStatic() && !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) { + AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT); + } + + for (auto *it : classDef->Body()) { + if (it->IsClassProperty()) { + it->Check(this); + } + } + + for (auto *it : classDef->Body()) { + if (!it->IsClassProperty()) { + it->Check(this); + } + } + + if (classDef->IsGlobal()) { + return; + } + + for (auto *it : classType->ConstructSignatures()) { + CheckCyclicContructorCall(it); + CheckImplicitSuper(classType, it); + } + + ValidateOverriding(classType, classDef->Start()); + CheckValidInheritance(classType, classDef); + CheckConstFields(classType); +} + +void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig) +{ + if (classType == GlobalETSObjectType()) { + return; + } + + auto &stmts = ctorSig->Function()->Body()->AsBlockStatement()->Statements(); + const auto superExpr = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { + return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() && + stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression(); + }); + + // There is no super expression + if (superExpr == stmts.end()) { + const auto superTypeCtorSigs = classType->SuperType()->ConstructSignatures(); + const auto superTypeCtorSig = std::find_if(superTypeCtorSigs.begin(), superTypeCtorSigs.end(), + [](const Signature *sig) { return sig->Params().empty(); }); + + // Super type has no parameterless ctor + if (superTypeCtorSig == superTypeCtorSigs.end()) { + ThrowTypeError("Must call super constructor", ctorSig->Function()->Start()); + } + + auto *newSuperExpr = Allocator()->New(); + newSuperExpr->SetTsType(classType->SuperType()); + auto *newCallExpr = Allocator()->New( + newSuperExpr->AsExpression(), ArenaVector {Allocator()->Adapter()}, nullptr, false); + newCallExpr->SetSignature(*superTypeCtorSig); + newCallExpr->SetTsType(GlobalVoidType()); + auto *newExprStmt = Allocator()->New(newCallExpr->AsExpression()); + stmts.insert(stmts.begin(), newExprStmt); + } +} + +void ETSChecker::CheckConstFields(const ETSObjectType *classType) +{ + for (const auto &prop : classType->Fields()) { + if (!prop->Declaration()->IsConstDecl() || !prop->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + continue; + } + CheckConstFieldInitialized(classType, prop); + } +} + +void ETSChecker::CheckConstFieldInitialized(const ETSObjectType *classType, binder::LocalVariable *classVar) +{ + const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic(); + for (const auto &prop : classType->Methods()) { + const auto &callSigs = prop->TsType()->AsETSFunctionType()->CallSignatures(); + for (const auto *signature : callSigs) { + if ((signature->Function()->IsConstructor() && !classVarStatic) || + (signature->Function()->IsStaticBlock() && classVarStatic)) { + CheckConstFieldInitialized(signature, classVar); + } + } + } +} + +void ETSChecker::FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) { + if (initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might already have been initialized"}, + node->Start()); + } + + initialized = true; + return; + } + + FindAssignments(node, classVar, initialized); +} + +void ETSChecker::FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + node->Iterate( + [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); }); +} + +void ETSChecker::CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *classVar) +{ + bool initialized = false; + const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements(); + const auto it = stmts.begin(); + + if (it != stmts.end()) { + if (const auto *first = *it; + first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() && + first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) { + initialized = true; + } + } + + // TODO(szd) control flow + FindAssignments(signature->Function()->Body(), classVar, initialized); + if (!initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might not have been initialized"}, + signature->Function()->End()); + } + + classVar->RemoveFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED); +} + +void ETSChecker::CheckInnerClassMembers(const ETSObjectType *classType) +{ + for (const auto &[_, it] : classType->StaticMethods()) { + (void)_; + ThrowTypeError("Inner class cannot have static methods", it->Declaration()->Node()->Start()); + } + + for (const auto &[_, it] : classType->StaticFields()) { + (void)_; + if (!it->Declaration()->IsConstDecl()) { + ThrowTypeError("Inner class cannot have non-const static properties", it->Declaration()->Node()->Start()); + } + } +} + +Type *ETSChecker::ValidateArrayIndex(ir::Expression *expr) +{ + Type *indexType = ApplyUnaryOperatorPromotion(expr->Check(this)); + + if (indexType == nullptr || !indexType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX)) { + ThrowTypeError("Only intergal types can be used as index.", expr->Start()); + } + + return indexType; +} + +Type *ETSChecker::CheckArrayElementAccess(ir::MemberExpression *expr) +{ + Type *arrayType = expr->Object()->Check(this); + + if (!arrayType->IsETSArrayType()) { + ThrowTypeError("Indexed access expression can only be used in array type.", expr->Object()->Start()); + } + + ValidateArrayIndex(expr->Property()); + expr->SetUnboxedPropertyType(ETSBuiltinTypeAsPrimitiveType(expr->Property()->TsType())); + + // TODO(user): apply capture conversion on this type + return arrayType->AsETSArrayType()->ElementType(); +} + +ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg) +{ + if (node->Parent()->IsCallExpression() && (node->Parent()->AsCallExpression()->Callee() == node)) { + if (Context().ContainingSignature() == nullptr) { + ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start()); + } + + auto *sig = Context().ContainingSignature(); + ASSERT(sig->Function()->Body() && sig->Function()->Body()->IsBlockStatement()); + + if (!sig->HasSignatureFlag(checker::SignatureFlags::CONSTRUCT)) { + ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start()); + } + + if (sig->Function()->Body()->AsBlockStatement()->Statements().front() != node->Parent()->Parent()) { + ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start()); + } + } + + if (HasStatus(checker::CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError({"'", msg, "' cannot be referenced from a static context"}, node->Start()); + } + + if (classType->GetDeclNode()->AsClassDefinition()->IsGlobal()) { + ThrowTypeError({"Cannot reference '", msg, "' in this context."}, node->Start()); + } + + return classType; +} + +void ETSChecker::CheckCyclicContructorCall(Signature *signature) +{ + ASSERT(signature->Function()); + + if (signature->Function()->Body() == nullptr) { + return; + } + + auto *funcBody = signature->Function()->Body()->AsBlockStatement(); + + TypeStackElement tse(this, signature, "Recursive constructor invocation", signature->Function()->Start()); + + if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() && + funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() && + funcBody->Statements()[0] + ->AsExpressionStatement() + ->GetExpression() + ->AsCallExpression() + ->Callee() + ->IsThisExpression()) { + auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression(); + ASSERT(constructorCall->Signature()); + CheckCyclicContructorCall(constructorCall->Signature()); + } +} + +ETSObjectType *ETSChecker::CheckExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + auto *exceptionType = + CheckException(type, pos, GlobalBuiltinExceptionType(), compiler::Signatures::BUILTIN_EXCEPTION_CLASS); + + if (Relation()->IsAssignableTo(exceptionType, GlobalBuiltinExceptionType())) { + ThrowTypeError({"Recover clause must be used for any instance of '", exceptionType->Name(), "'"}, pos); + } + + return exceptionType; +} + +ETSObjectType *ETSChecker::CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + return CheckException(type, pos, GlobalBuiltinPanicType(), compiler::Signatures::BUILTIN_PANIC_CLASS); +} + +ETSObjectType *ETSChecker::CheckException(checker::Type *type, lexer::SourcePosition pos, ETSObjectType *expected, + std::string_view msg) +{ + if (!type->IsETSObjectType() || !Relation()->IsAssignableTo(type, expected)) { + ThrowTypeError({"Argument must be an instance of '", msg, "'"}, pos); + } + + return type->AsETSObjectType(); +} + +Type *ETSChecker::TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes) +{ + // TODO(user): Handle generic functions + if (type->IsETSTypeReference() || type->IsETSFunctionType() || + (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNCOMPLETE_INSTANTIATION))) { + return type->Instantiate(allocator, relation, globalTypes); + } + + return type; +} + +binder::LocalVariable *ETSChecker::ResolveMemberReference(const ir::MemberExpression *memberExpr, ETSObjectType *target) +{ + auto searchFlag = PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_METHOD; + + switch (memberExpr->Parent()->Type()) { + case ir::AstNodeType::CALL_EXPRESSION: { + if (memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) { + searchFlag = PropertySearchFlags::SEARCH_METHOD; + } + + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + if (memberExpr->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == memberExpr) { + searchFlag = PropertySearchFlags::SEARCH_DECL; + } + + break; + } + + case ir::AstNodeType::MEMBER_EXPRESSION: { + searchFlag = PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL; + break; + } + case ir::AstNodeType::UPDATE_EXPRESSION: + case ir::AstNodeType::UNARY_EXPRESSION: + case ir::AstNodeType::BINARY_EXPRESSION: { + searchFlag = PropertySearchFlags::SEARCH_FIELD; + break; + } + case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { + auto *assignmentExpr = memberExpr->Parent()->AsAssignmentExpression(); + + if (assignmentExpr->Left() == memberExpr) { + searchFlag = PropertySearchFlags::SEARCH_FIELD; + break; + } + + if (assignmentExpr->Right() == memberExpr) { + auto *targetType = assignmentExpr->Left()->TsType(); + ASSERT(targetType != nullptr); + + if (targetType->IsETSObjectType() && + targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { + searchFlag = PropertySearchFlags::SEARCH_METHOD; + break; + } + + searchFlag = PropertySearchFlags::SEARCH_FIELD; + break; + } + } + default: { + break; + } + } + + const binder::Variable *targetRef {}; + if (memberExpr->Object()->IsIdentifier()) { + targetRef = memberExpr->Object()->AsIdentifier()->Variable(); + } else if (memberExpr->Object()->IsMemberExpression()) { + targetRef = memberExpr->Object()->AsMemberExpression()->PropVar(); + } + + if (targetRef != nullptr && targetRef->HasFlag(binder::VariableFlags::CLASS_OR_INTERFACE)) { + searchFlag &= ~(PropertySearchFlags::SEARCH_INSTANCE_FIELD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | + PropertySearchFlags::SEARCH_INSTANCE_DECL); + } + + searchFlag |= PropertySearchFlags::SEARCH_IN_BASE | checker::PropertySearchFlags::SEARCH_IN_INTERFACES; + auto *prop = target->GetProperty(memberExpr->Property()->AsIdentifier()->Name(), searchFlag); + + if (prop == nullptr) { + const char *propKind = ((searchFlag & checker::PropertySearchFlags::SEARCH_METHOD) != 0) ? "Method " : "Field "; + ThrowTypeError({propKind, memberExpr->Property()->AsIdentifier()->Name(), " does not exist on this type."}, + memberExpr->Property()->Start()); + } + + return prop; +} + +void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefinition *classDef) +{ + if (classType->SuperType() == nullptr) { + return; + } + + const auto &allProps = classType->GetAllProperties(); + + for (auto *it : allProps) { + auto *found = classType->SuperType()->GetProperty( + it->Name(), PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE | + PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION); + + if (found == nullptr) { + continue; + } + + if (!IsSameDeclarationType(it, found)) { + const char *targetType {}; + + if (it->HasFlag(binder::VariableFlags::PROPERTY)) { + targetType = "field"; + } else if (it->HasFlag(binder::VariableFlags::METHOD)) { + targetType = "method"; + } else if (it->HasFlag(binder::VariableFlags::CLASS)) { + targetType = "class"; + } else if (it->HasFlag(binder::VariableFlags::INTERFACE)) { + targetType = "interface"; + } else { + targetType = "enum"; + } + + ThrowTypeError({"Cannot inherit from class ", classType->SuperType()->Name(), ", because ", targetType, " ", + it->Name(), " is inherited with a different declaration type"}, + classDef->Super()->Start()); + } + } +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/primitiveWrappers.cpp b/checker/ets/primitiveWrappers.cpp new file mode 100644 index 000000000..fba7f28cc --- /dev/null +++ b/checker/ets/primitiveWrappers.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "primitiveWrappers.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/primitiveWrappers.h b/checker/ets/primitiveWrappers.h new file mode 100644 index 000000000..d4da71c31 --- /dev/null +++ b/checker/ets/primitiveWrappers.h @@ -0,0 +1,58 @@ + +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_PRIMITIVEWRAPPERS_H +#define ES2PANDA_COMPILER_CHECKER_ETS_PRIMITIVEWRAPPERS_H + +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class ETSObjectType; + +using WrapperDesc = ArenaUnorderedMap>; + +class PrimitiveWrappers { +public: + explicit PrimitiveWrappers(ArenaAllocator *allocator) : wrappers_(allocator->Adapter()) + { + wrappers_.insert({"Boolean", {nullptr, ETSObjectFlags::BUILTIN_BOOLEAN}}); + wrappers_.insert({"Byte", {nullptr, ETSObjectFlags::BUILTIN_BYTE}}); + wrappers_.insert({"Char", {nullptr, ETSObjectFlags::BUILTIN_CHAR}}); + wrappers_.insert({"Short", {nullptr, ETSObjectFlags::BUILTIN_SHORT}}); + wrappers_.insert({"Int", {nullptr, ETSObjectFlags::BUILTIN_INT}}); + wrappers_.insert({"Long", {nullptr, ETSObjectFlags::BUILTIN_LONG}}); + wrappers_.insert({"Float", {nullptr, ETSObjectFlags::BUILTIN_FLOAT}}); + wrappers_.insert({"Double", {nullptr, ETSObjectFlags::BUILTIN_DOUBLE}}); + } + NO_COPY_SEMANTIC(PrimitiveWrappers); + NO_MOVE_SEMANTIC(PrimitiveWrappers); + ~PrimitiveWrappers() = default; + + WrapperDesc &Wrappers() + { + return wrappers_; + } + + const WrapperDesc &Wrappers() const + { + return wrappers_; + } + +private: + WrapperDesc wrappers_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/ets/typeConverter.cpp b/checker/ets/typeConverter.cpp new file mode 100644 index 000000000..dc32dee4b --- /dev/null +++ b/checker/ets/typeConverter.cpp @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "typeConverter.h" + +namespace panda::es2panda::checker { +TypeConverter::TypeConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : checker_(checker), relation_(relation), target_(target), source_(source) +{ +} + +Type *TypeConverter::Result() const +{ + return result_; +} + +void TypeConverter::SetResult(Type *result) +{ + result_ = result; +} + +Type *TypeConverter::Source() const +{ + return source_; +} + +Type *TypeConverter::Target() const +{ + return target_; +} + +TypeRelation *TypeConverter::Relation() const +{ + return relation_; +} + +ETSChecker *TypeConverter::Checker() const +{ + return checker_; +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/typeConverter.h b/checker/ets/typeConverter.h new file mode 100644 index 000000000..6f90280a9 --- /dev/null +++ b/checker/ets/typeConverter.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_TYPE_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSChecker; + +class TypeConverter { +public: + TypeConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source); + Type *Result() const; + void SetResult(Type *result); + Type *Source() const; + Type *Target() const; + TypeRelation *Relation() const; + ETSChecker *Checker() const; + +private: + ETSChecker *checker_; + TypeRelation *relation_; + Type *target_; + Type *source_; + Type *result_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/typeCreation.cpp b/checker/ets/typeCreation.cpp new file mode 100644 index 000000000..62ca2e79d --- /dev/null +++ b/checker/ets/typeCreation.cpp @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsScript.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +ByteType *ETSChecker::CreateByteType(int8_t value) +{ + return Allocator()->New(value); +} + +ETSBooleanType *ETSChecker::CreateETSBooleanType(bool value) +{ + return Allocator()->New(value); +} + +DoubleType *ETSChecker::CreateDoubleType(double value) +{ + return Allocator()->New(value); +} + +FloatType *ETSChecker::CreateFloatType(float value) +{ + return Allocator()->New(value); +} + +IntType *ETSChecker::CreateIntType(int32_t value) +{ + return Allocator()->New(value); +} + +IntType *ETSChecker::CreateIntTypeFromType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::CONSTANT)) { + return GlobalIntType()->AsIntType(); + } + + if (type->IsIntType()) { + return type->AsIntType(); + } + + switch (ETSType(type)) { + case TypeFlag::CHAR: { + return CreateIntType(static_cast(type->AsCharType()->GetValue())); + } + case TypeFlag::BYTE: { + return CreateIntType(static_cast(type->AsByteType()->GetValue())); + } + case TypeFlag::SHORT: { + return CreateIntType(static_cast(type->AsShortType()->GetValue())); + } + default: { + return nullptr; + } + } +} + +LongType *ETSChecker::CreateLongType(int64_t value) +{ + return Allocator()->New(value); +} + +ShortType *ETSChecker::CreateShortType(int16_t value) +{ + return Allocator()->New(value); +} + +CharType *ETSChecker::CreateCharType(char16_t value) +{ + return Allocator()->New(value); +} + +ETSStringType *ETSChecker::CreateETSStringLiteralType(util::StringView value) +{ + return Allocator()->New(Allocator(), GlobalBuiltinETSStringType(), value); +} + +ETSArrayType *ETSChecker::CreateETSArrayType(Type *elementType) +{ + auto res = arrayTypes_.find(elementType); + + if (res != arrayTypes_.end()) { + return res->second; + } + + auto *arrayType = Allocator()->New(elementType); + arrayTypes_.insert({elementType, arrayType}); + + return arrayType; +} + +ETSFunctionType *ETSChecker::CreateETSFunctionType(ArenaVector &signatures) +{ + auto *funcType = Allocator()->New(signatures[0]->Function()->Id()->Name(), Allocator()); + + for (auto *it : signatures) { + funcType->AddCallSignature(it); + } + + return funcType; +} + +ETSFunctionType *ETSChecker::CreateETSFunctionType(Signature *signature) +{ + return Allocator()->New(signature->Function()->Id()->Name(), signature, Allocator()); +} + +Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func) +{ + return Allocator()->New(info, returnType, func); +} + +Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName) +{ + return Allocator()->New(info, returnType, internalName); +} + +SignatureInfo *ETSChecker::CreateSignatureInfo() +{ + return Allocator()->New(Allocator()); +} + +ETSTypeParameter *ETSChecker::CreateTypeParameter(Type *assemblerType) +{ + return Allocator()->New(assemblerType); +} + +ETSTypeReference *ETSChecker::CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar) +{ + return Allocator()->New(ref, assemblerRef, refVar); +} + +ETSFunctionType *ETSChecker::CreateETSFunctionType(util::StringView name) +{ + return Allocator()->New(name, Allocator()); +} + +ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, + ETSObjectFlags flags) +{ + if (name == compiler::Signatures::BUILTIN_STRING_CLASS) { + if (GlobalBuiltinETSStringType() != nullptr) { + return GlobalBuiltinETSStringType(); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_STRING_BUILTIN)] = + CreateNewETSObjectType(name, declNode, flags | ETSObjectFlags::BUILTIN_STRING | ETSObjectFlags::STRING); + + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_STRING)] = + Allocator()->New(Allocator(), GlobalBuiltinETSStringType()); + return GlobalBuiltinETSStringType(); + } + + auto *objType = CreateNewETSObjectType(name, declNode, flags); + + if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { + if (GlobalETSObjectType() != nullptr) { + return GlobalETSObjectType(); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_OBJECT_BUILTIN)] = objType; + } else if (name == compiler::Signatures::BUILTIN_EXCEPTION_CLASS) { + if (GlobalBuiltinExceptionType() != nullptr) { + return GlobalBuiltinExceptionType(); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_EXCEPTION_BUILTIN)] = objType; + } else if (name == compiler::Signatures::BUILTIN_PANIC_CLASS) { + if (GlobalBuiltinPanicType() != nullptr) { + return GlobalBuiltinPanicType(); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_PANIC_BUILTIN)] = objType; + } else if (name == compiler::Signatures::BUILTIN_TYPE_CLASS) { + if (GlobalBuiltinTypeType() != nullptr) { + return GlobalBuiltinTypeType(); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_TYPE_BUILTIN)] = objType; + } else if (name == compiler::Signatures::BUILTIN_ENUM_CLASS) { + // TODO(user): + if (globalBuiltinEnumType_ != nullptr) { + return globalBuiltinEnumType_; + } + globalBuiltinEnumType_ = objType; + } + + return objType; +} + +ETSObjectType *ETSChecker::CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags) +{ + auto res = primitiveWrappers_.Wrappers().find(name); + if (res == primitiveWrappers_.Wrappers().end()) { + return CreateETSObjectTypeCheckBuiltins(name, declNode, flags); + } + + if (res->second.first != nullptr) { + return res->second.first; + } + + auto *objType = CreateNewETSObjectType(name, declNode, flags | res->second.second); + primitiveWrappers_.Wrappers().at(name).first = objType; + return objType; +} + +ETSObjectType *ETSChecker::CreateETSEnumType(ir::TSEnumDeclaration *enumDecl) +{ + binder::Variable *enumVar = enumDecl->Key()->Variable(); + ASSERT(enumVar); + + auto *enumType = + CreateETSObjectType(enumDecl->Key()->Name(), enumDecl, (ETSObjectFlags::ENUM | ETSObjectFlags::RESOLVED_SUPER)); + enumType->SetSuperType(globalBuiltinEnumType_); + enumType->SetVariable(enumVar); + enumVar->SetTsType(enumType); + + BuildEnumProperties(enumType); + + return enumType; +} + +ETSObjectType *ETSChecker::CreateNewETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags) +{ + util::StringView assemblerName = name; + util::StringView prefix {}; + + auto *containingObjType = util::Helpers::GetContainingObjectType(declNode->Parent()); + + if (containingObjType != nullptr) { + prefix = containingObjType->AssemblerName(); + } else { + auto *program = static_cast(declNode->GetTopStatement())->Program(); + prefix = program->GetPackageName(); + } + + if (!prefix.Empty()) { + util::UString fullPath(prefix, Allocator()); + fullPath.Append('.'); + fullPath.Append(name); + assemblerName = fullPath.View(); + } + + return Allocator()->New(Allocator(), name, assemblerName, declNode, flags); +} + +std::tuple ETSChecker::CreateBuiltinArraySignatureInfo(ETSArrayType *arrayType, + size_t dim) +{ + std::stringstream ss; + arrayType->ToAssemblerTypeWithRank(ss); + ss << compiler::Signatures::METHOD_SEPARATOR << compiler::Signatures::CTOR << compiler::Signatures::MANGLE_BEGIN; + arrayType->ToAssemblerTypeWithRank(ss); + + auto *info = CreateSignatureInfo(); + info->minArgCount = dim; + + for (size_t i = 0; i < dim; i++) { + util::UString param(std::to_string(i), Allocator()); + auto *paramVar = binder::Scope::CreateVar(Allocator(), param.View(), binder::VariableFlags::NONE, nullptr); + paramVar->SetTsType(GlobalIntType()); + + info->params.push_back(paramVar); + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_INT; + } + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_VOID + << compiler::Signatures::MANGLE_SEPARATOR; + auto internalName = util::UString(ss.str(), Allocator()).View(); + + return {internalName, info}; +} + +Signature *ETSChecker::CreateBuiltinArraySignature(ETSArrayType *arrayType, size_t dim) +{ + auto res = globalArraySignatures_.find(arrayType); + + if (res != globalArraySignatures_.end()) { + return res->second; + } + + auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim); + auto *signature = CreateSignature(info, GlobalVoidType(), internalName); + globalArraySignatures_.insert({arrayType, signature}); + + return signature; +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/typeRelationContext.cpp b/checker/ets/typeRelationContext.cpp new file mode 100644 index 000000000..fa9adc62f --- /dev/null +++ b/checker/ets/typeRelationContext.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "typeRelationContext.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsArrayType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" + +namespace panda::es2panda::checker { +void AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, + ETSArrayType *target) +{ + for (uint32_t index = 0; index < node->Elements().size(); index++) { + ir::Expression *currentArrayElem = node->Elements()[index]; + AssignmentContext(relation, currentArrayElem, currentArrayElem->Check(relation->GetChecker()->AsETSChecker()), + target->ElementType(), currentArrayElem->Start(), + {"Array element at index ", index, " is not compatible with the target array element type."}); + } +} + +bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) +{ + if (typeParamDecl != nullptr && typeArgs == nullptr) { + checker_->ThrowTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos); + } + + if (typeParamDecl == nullptr && typeArgs != nullptr) { + checker_->ThrowTypeError({"Type '", type, "' is not generic."}, pos); + } + + if (typeArgs == nullptr) { + result_ = type; + return true; + } + + ASSERT(typeParamDecl != nullptr && typeArgs != nullptr); + if (typeParamDecl->Params().size() != typeArgs->Params().size()) { + checker_->ThrowTypeError({"Type '", type, "' has ", typeParamDecl->Params().size(), + " number of type parameters, but ", typeArgs->Params().size(), + " type arguments were provided."}, + pos); + } + + return false; +} + +util::StringView InstantiationContext::GetHashFromTypeArguments(ArenaVector &typeArgTypes) +{ + std::stringstream ss; + + for (auto *it : typeArgTypes) { + // TODO(user): this is not the best solution, since A and A will produce the same string in their ToString + // method, but they are two different types + it->ToString(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + return util::UString(ss.str(), checker_->Allocator()).View(); +} + +void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs) +{ + ArenaVector typeArgTypes(checker_->Allocator()->Adapter()); + typeArgTypes.reserve(typeArgs->Params().size()); + + auto flags = ETSObjectFlags::NO_OPTS; + + for (auto *it : typeArgs->Params()) { + auto *paramType = it->GetType(checker_); + typeArgTypes.push_back(it->GetType(checker_)); + + if (paramType->IsETSTypeReference()) { + flags |= ETSObjectFlags::UNCOMPLETE_INSTANTIATION; + } + } + + InstantiateType(type, typeParamDecl, typeArgTypes); + result_->AddObjectFlag(flags); +} + +void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes) +{ + util::StringView hash = GetHashFromTypeArguments(typeArgTypes); + auto *found = type->GetInstantiatedType(hash); + + if (found != nullptr) { + result_ = found; + return; + } + + checker::ScopeContext scopeCtx(checker_, typeParamDecl->Scope()); + + for (size_t idx = 0; idx < typeParamDecl->Params().size(); idx++) { + auto *paramVar = typeParamDecl->Params()[idx]->Name()->Variable()->AsLocalVariable(); + auto *typeParam = paramVar->TsType()->AsETSTypeParameter(); + + typeParam->SetType(typeArgTypes[idx]); + typeArgVars_.push_back(paramVar); + } + + result_ = type->Instantiate(checker_->Allocator(), checker_->Relation(), checker_->GetGlobalTypesHolder()) + ->AsETSObjectType(); + result_->SetTypeArguments(std::move(typeArgTypes)); + type->GetInstantiationMap().insert({hash, result_}); + + for (auto *it : typeArgVars_) { + it->TsType()->AsETSTypeParameter()->SetType(nullptr); + } +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/typeRelationContext.h b/checker/ets/typeRelationContext.h new file mode 100644 index 000000000..61f2579c2 --- /dev/null +++ b/checker/ets/typeRelationContext.h @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H +#define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +class ETSChecker; + +class AssignmentContext { +public: + AssignmentContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag flags = TypeRelationFlag::NONE) + { + flags_ |= ((flags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING; + flags_ |= ((flags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING; + flags_ |= ((flags & TypeRelationFlag::NO_WIDENING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::WIDENING; + + if (node->IsArrayExpression() && target->IsETSArrayType()) { + ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsETSArrayType()); + return; + } + + flags_ |= flags; + relation->SetNode(node); + + if (source->HasTypeFlag(TypeFlag::CONSTANT)) { + flags_ |= TypeRelationFlag::NARROWING; + } + + relation->SetFlags(flags_); + + if (!relation->IsAssignableTo(source, target)) { + if (((flags_ & TypeRelationFlag::UNBOXING) != 0) && source->IsETSObjectType() && !relation->IsTrue()) { + auto unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source); + auto unboxedTargetType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedSourceType != nullptr && unboxedTargetType != nullptr) { + relation->IsAssignableTo(unboxedSourceType, unboxedTargetType); + } + } + } + + if (!relation->IsTrue() && (flags_ & TypeRelationFlag::NO_THROW) == 0) { + relation->RaiseError(list, pos); + } + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + assignable_ = true; + } + + bool IsAssigable() const + { + return assignable_; + } + + void ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, ETSArrayType *target); + +private: + TypeRelationFlag flags_ = TypeRelationFlag::IN_ASSIGNMENT_CONTEXT; + bool assignable_ {false}; +}; + +class InvocationContext { +public: + InvocationContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag initialFlags = TypeRelationFlag::NONE) + { + flags_ |= + ((initialFlags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING; + flags_ |= + ((initialFlags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING; + relation->SetNode(node); + + relation->SetFlags(flags_ | initialFlags); + + bool assignable = relation->IsAssignableTo(source, target); + if (!assignable && ((flags_ & TypeRelationFlag::UNBOXING) != 0)) { + if (source->IsETSObjectType() && !relation->IsTrue()) { + auto unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source); + relation->SetFlags(flags_ | TypeRelationFlag::WIDENING); + if (unboxedSourceType != nullptr) { + assignable = relation->IsAssignableTo(unboxedSourceType, target); + } + } + } + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + + if (!assignable) { + if ((initialFlags & TypeRelationFlag::NO_THROW) == 0) { + relation->RaiseError(list, pos); + } + return; + } + + invocable_ = true; + } + + bool IsInvocable() const + { + return invocable_; + } + +private: + TypeRelationFlag flags_ = TypeRelationFlag::NONE; + bool invocable_ {false}; +}; + +class InstantiationContext { +public: + InstantiationContext(ETSChecker *checker, ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(ETSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else if (type->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + if (ValidateTypeArguments(type, typeParamDecl, typeArgs, pos)) { + return; + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + InstantiationContext(ETSChecker *checker, ETSObjectType *type, ArenaVector &typeArgs) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(ETSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else if (type->HasObjectFlag(ETSObjectFlags::ENUM)) { + return; + } else { + ASSERT(type->HasObjectFlag(ETSObjectFlags::INTERFACE)); + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + ETSObjectType *Result() + { + return result_; + } + +private: + bool ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, const lexer::SourcePosition &pos); + void InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs); + + void InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes); + util::StringView GetHashFromTypeArguments(ArenaVector &typeArgTypes); + + ETSChecker *checker_; + ArenaVector typeArgVars_; + ETSObjectType *result_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/unboxingConverter.cpp b/checker/ets/unboxingConverter.cpp new file mode 100644 index 000000000..68d37f283 --- /dev/null +++ b/checker/ets/unboxingConverter.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +checker::Type *UnboxingConverter::GlobalTypeFromSource(ETSObjectFlags type) +{ + switch (type) { + case ETSObjectFlags::BUILTIN_BOOLEAN: { + return Checker()->GlobalETSBooleanType(); + } + case ETSObjectFlags::BUILTIN_BYTE: { + return Checker()->GlobalByteType(); + } + case ETSObjectFlags::BUILTIN_SHORT: { + return Checker()->GlobalShortType(); + } + case ETSObjectFlags::BUILTIN_CHAR: { + return Checker()->GlobalCharType(); + } + case ETSObjectFlags::BUILTIN_INT: { + return Checker()->GlobalIntType(); + } + case ETSObjectFlags::BUILTIN_LONG: { + return Checker()->GlobalLongType(); + } + case ETSObjectFlags::BUILTIN_FLOAT: { + return Checker()->GlobalFloatType(); + } + case ETSObjectFlags::BUILTIN_DOUBLE: { + return Checker()->GlobalDoubleType(); + } + default: + return Source(); + } +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/unboxingConverter.h b/checker/ets/unboxingConverter.h new file mode 100644 index 000000000..e82d4efe6 --- /dev/null +++ b/checker/ets/unboxingConverter.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_UNBOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_UNBOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { + +class UnboxingConverter : public TypeConverter { +public: + UnboxingConverter(ETSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + SetResult(Source()); + + if (!Source()->IsETSObjectType() || relation->IsTrue()) { + return; + } + + SetResult(GlobalTypeFromSource(Source()->AsETSObjectType()->BuiltInKind())); + + Relation()->Result(Result()->TypeFlags() == target->TypeFlags()); + } + + checker::Type *GlobalTypeFromSource(ETSObjectFlags type); +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/wideningConverter.cpp b/checker/ets/wideningConverter.cpp new file mode 100644 index 000000000..0c7e36c5d --- /dev/null +++ b/checker/ets/wideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/wideningConverter.h b/checker/ets/wideningConverter.h new file mode 100644 index 000000000..2381a438b --- /dev/null +++ b/checker/ets/wideningConverter.h @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +class WideningConverter : public TypeConverter { +public: + explicit WideningConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!Relation()->ApplyWidening()) { + return; + } + + if (!Source()->HasTypeFlag(TypeFlag::CONSTANT)) { + ApplyGlobalWidening(); + } else { + ApplyConstWidening(); + } + } + +private: + void ApplyConstWidening() + { + switch (ETSChecker::ETSChecker::ETSType(Target())) { + case TypeFlag::SHORT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening() + { + switch (ETSChecker::ETSChecker::ETSType(Target())) { + case TypeFlag::SHORT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening(TypeFlag flag) + { + if (!Source()->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(Source())) { + case TypeFlag::BYTE: { + Relation()->GetNode()->SetTsType(Checker()->GlobalByteType()); + break; + } + case TypeFlag::SHORT: { + Relation()->GetNode()->SetTsType(Checker()->GlobalShortType()); + break; + } + case TypeFlag::CHAR: { + Relation()->GetNode()->SetTsType(Checker()->GlobalCharType()); + break; + } + case TypeFlag::INT: { + Relation()->GetNode()->SetTsType(Checker()->GlobalIntType()); + break; + } + case TypeFlag::LONG: { + Relation()->GetNode()->SetTsType(Checker()->GlobalLongType()); + break; + } + case TypeFlag::FLOAT: { + Relation()->GetNode()->SetTsType(Checker()->GlobalFloatType()); + break; + } + case TypeFlag::DOUBLE: { + Relation()->GetNode()->SetTsType(Checker()->GlobalDoubleType()); + break; + } + default: { + return; + } + } + + Relation()->Result(true); + } + + template + void ApplyWidening(TypeFlag flag) + { + if (!Source()->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(Source())) { + case TypeFlag::BYTE: { + ApplyWidening(); + break; + } + case TypeFlag::CHAR: { + ApplyWidening(); + break; + } + case TypeFlag::SHORT: { + ApplyWidening(); + break; + } + case TypeFlag::INT: { + ApplyWidening(); + break; + } + case TypeFlag::LONG: { + ApplyWidening(); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(); + break; + } + default: { + return; + } + } + Relation()->Result(true); + } + + template + void ApplyWidening() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(Source())->GetValue(); + + if (!Relation()->OnlyCheckWidening()) { + Relation()->GetNode()->SetTsType(Checker()->Allocator()->New(static_cast(value))); + } + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/core/binaryLikeExpression.cpp b/checker/ts/binaryLikeExpression.cpp similarity index 85% rename from typescript/core/binaryLikeExpression.cpp rename to checker/ts/binaryLikeExpression.cpp index b5009ff7b..425a391e0 100644 --- a/typescript/core/binaryLikeExpression.cpp +++ b/checker/ts/binaryLikeExpression.cpp @@ -16,11 +16,11 @@ #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -90,8 +90,8 @@ Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Ex return resultType; } -Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op) { if (!leftType->HasTypeFlag(TypeFlag::STRING_LIKE) && !rightType->HasTypeFlag(TypeFlag::STRING_LIKE)) { CheckNonNullType(leftType, leftExpr->Start()); @@ -122,8 +122,8 @@ Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expr return resultType; } -Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -138,7 +138,7 @@ Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::E return GlobalAnyType(); } -Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -150,7 +150,7 @@ Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expre return leftType; } -Type *Checker::CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -169,8 +169,8 @@ static bool TypeHasCallOrConstructSignatures(Type *type) (!type->AsObjectType()->CallSignatures().empty() || !type->AsObjectType()->ConstructSignatures().empty()); } -Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr) +Type *TSChecker::CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, + ir::AstNode *expr) { if (leftType->TypeFlags() != TypeFlag::ANY && IsAllTypesAssignableTo(leftType, GlobalPrimitiveType())) { ThrowTypeError({"The left-hand side of an 'instanceof' expression must be of type 'any',", @@ -188,8 +188,8 @@ Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const return GlobalBooleanType(); } -Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr) +Type *TSChecker::CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -209,8 +209,7 @@ Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expr return GlobalBooleanType(); } -void Checker::CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, - Type *valueType) +void TSChecker::CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType) { if (IsAssignmentOperator(op)) { CheckReferenceExpression( diff --git a/typescript/core/destructuringContext.cpp b/checker/ts/destructuringContext.cpp similarity index 95% rename from typescript/core/destructuringContext.cpp rename to checker/ts/destructuringContext.cpp index 046ff5f38..8dd3b23dc 100644 --- a/typescript/core/destructuringContext.cpp +++ b/checker/ts/destructuringContext.cpp @@ -27,12 +27,12 @@ #include "plugins/ecmascript/es2panda/ir/expression.h" namespace panda::es2panda::checker { -void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, +void DestructuringContext::Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc) { if (typeAnnotation != nullptr) { typeAnnotation->Check(checker_); - Type *annotationType = typeAnnotation->AsTypeNode()->GetType(checker_); + Type *annotationType = typeAnnotation->GetType(checker_); if (initializer != nullptr) { checker_->ElaborateElementwise(annotationType, initializer, loc); @@ -52,8 +52,7 @@ void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const i } } -void DestructuringContext::HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, - Type *defaultType) +void DestructuringContext::HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType) { if (ident->Variable() == nullptr) { checker_->ThrowTypeError({"Cannot find name '", ident->Name(), "'."}, ident->Start()); @@ -96,7 +95,7 @@ void DestructuringContext::SetInferedTypeForVariable(binder::Variable *var, Type var->SetTsType(inferedType); } -void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern) +void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern) { for (const auto *sourceProp : obj_type->Properties()) { const util::StringView &sourceName = sourceProp->Name(); @@ -124,7 +123,7 @@ void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const } } -void DestructuringContext::HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, +void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault) { if (!assignmentPattern->Left()->IsArrayPattern()) { @@ -368,7 +367,7 @@ Type *ArrayDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sourc return checker_->CreateUnionType(std::move(tupleUnion)); } -void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ArrayDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); @@ -397,7 +396,7 @@ void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) nextContext.Start(); } -Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -419,7 +418,7 @@ Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir return type; } -static void SetParameterType(const ir::AstNode *parent, Type *type) +static void SetParameterType(ir::AstNode *parent, Type *type) { parent->Iterate([type](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier() && childNode->AsIdentifier()->Variable() != nullptr) { @@ -434,7 +433,7 @@ static void SetParameterType(const ir::AstNode *parent, Type *type) void ArrayDestructuringContext::SetRemainingPatameterTypes() { do { - const auto *it = id_->AsArrayPattern()->Elements()[index_]; + auto *it = id_->AsArrayPattern()->Elements()[index_]; ASSERT(it); SetParameterType(it, checker_->GlobalAnyType()); } while (++index_ != id_->AsArrayPattern()->Elements().size()); @@ -448,7 +447,7 @@ void ArrayDestructuringContext::Start() util::StringView name = util::Helpers::ToStringView(checker_->Allocator(), 0); - for (const auto *it : id_->AsArrayPattern()->Elements()) { + for (auto *it : id_->AsArrayPattern()->Elements()) { if (it->IsRestElement()) { HandleRest(it->AsRestElement()); break; @@ -521,7 +520,7 @@ void ObjectDestructuringContext::ValidateInferedType() ValidateObjectLiteralType(inferedType_->AsObjectType(), id_->AsObjectPattern()); } -void ObjectDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ObjectDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); ASSERT(rest->Argument()->IsIdentifier()); @@ -577,7 +576,7 @@ Type *ObjectDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sour checker_->ThrowTypeError("Rest types may only be created from object types.", loc); } -Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -589,7 +588,7 @@ Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const i ASSERT(node->IsProperty()); - const ir::Property *property = node->AsProperty(); + ir::Property *property = node->AsProperty(); if (property->Value()->IsArrayPattern()) { return type; @@ -641,10 +640,10 @@ void ObjectDestructuringContext::Start() ValidateInferedType(); } - for (const auto *it : id_->AsObjectPattern()->Properties()) { + for (auto *it : id_->AsObjectPattern()->Properties()) { switch (it->Type()) { case ir::AstNodeType::PROPERTY: { - const ir::Property *property = it->AsProperty(); + ir::Property *property = it->AsProperty(); if (property->IsComputed()) { // TODO(aszilagyi) diff --git a/typescript/core/destructuringContext.h b/checker/ts/destructuringContext.h similarity index 64% rename from typescript/core/destructuringContext.h rename to checker/ts/destructuringContext.h index 5e0619773..2f649e859 100644 --- a/typescript/core/destructuringContext.h +++ b/checker/ts/destructuringContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H +#define ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,8 +31,8 @@ class Type; class DestructuringContext { public: - DestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + DestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : checker_(checker), id_(id), inAssignment_(inAssignment), convertTupleToArray_(convertTupleToArray) { Prepare(typeAnnotation, initializer, id->Start()); @@ -53,13 +53,11 @@ public: return inferedType_; } - void ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern); - void HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, Type *defaultType); - void HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, - bool validateDefault); + void ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern); + void HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType); + void HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault); void SetInferedTypeForVariable(binder::Variable *var, Type *inferedType, const lexer::SourcePosition &loc); - void Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, - const lexer::SourcePosition &loc); + void Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc); DEFAULT_COPY_SEMANTIC(DestructuringContext); DEFAULT_MOVE_SEMANTIC(DestructuringContext); @@ -68,14 +66,14 @@ public: virtual void Start() = 0; virtual void ValidateInferedType() = 0; virtual Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) = 0; - virtual void HandleRest(const ir::SpreadElement *rest) = 0; + virtual void HandleRest(ir::SpreadElement *rest) = 0; virtual Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) = 0; - virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) = 0; + virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) = 0; protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; - const ir::Expression *id_; + TSChecker *checker_; + ir::Expression *id_; bool inAssignment_; bool convertTupleToArray_; Type *inferedType_ {}; @@ -87,8 +85,8 @@ protected: class ArrayDestructuringContext : public DestructuringContext { public: - ArrayDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ArrayDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -101,9 +99,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; private: uint32_t index_ {0}; @@ -111,8 +109,8 @@ private: class ObjectDestructuringContext : public DestructuringContext { public: - ObjectDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ObjectDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -122,9 +120,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; }; } // namespace panda::es2panda::checker diff --git a/typescript/core/function.cpp b/checker/ts/function.cpp similarity index 76% rename from typescript/core/function.cpp rename to checker/ts/function.cpp index 479384a3f..2f4738a5c 100644 --- a/typescript/core/function.cpp +++ b/checker/ts/function.cpp @@ -33,22 +33,23 @@ #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/declaration.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/core/destructuringContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ts/destructuringContext.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" #include +#include #include #include #include namespace panda::es2panda::checker { -Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) +Type *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - Type *returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + Type *returnType = func->ReturnTypeAnnotation()->GetType(this); if (func->IsArrow() && func->Body()->IsExpression()) { ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start()); @@ -76,7 +77,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return func->Body()->Check(this); } - ArenaVector returnTypes(allocator_->Adapter()); + ArenaVector returnTypes(Allocator()->Adapter()); CollectTypesFromReturnStatements(func->Body(), &returnTypes); if (returnTypes.empty()) { @@ -96,7 +97,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return CreateUnionType(std::move(returnTypes)); } -void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) +void TSChecker::ThrowReturnTypeCircularityError(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { ThrowTypeError("Return type annotation circularly reference itself", func->ReturnTypeAnnotation()->Start()); @@ -115,8 +116,8 @@ void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) func->Start()); } -std::tuple Checker::CheckFunctionIdentifierParameter( - const ir::Identifier *param) +std::tuple TSChecker::CheckFunctionIdentifierParameter( + ir::Identifier *param) { ASSERT(param->Variable()); binder::Variable *param_var = param->Variable(); @@ -131,11 +132,11 @@ std::tuple Checker::Chec } param->TypeAnnotation()->Check(this); - param_var->SetTsType(param->TypeAnnotation()->AsTypeNode()->GetType(this)); + param_var->SetTsType(param->TypeAnnotation()->GetType(this)); return {param_var->AsLocalVariable(), nullptr, is_optional}; } -Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType) +Type *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; @@ -148,12 +149,13 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return inferedType; } - TupleType *newTuple = inferedTuple->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType()->AsTupleType(); + TupleType *newTuple = + inferedTuple->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType()->AsTupleType(); for (uint32_t index = inferedTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) { - util::StringView memberIndex = util::Helpers::ToStringView(allocator_, index); + util::StringView memberIndex = util::Helpers::ToStringView(Allocator(), index); binder::LocalVariable *newMember = binder::Scope::CreateVar( - allocator_, memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); + Allocator(), memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newMember->SetTsType(GlobalAnyType()); newTuple->AddProperty(newMember); } @@ -161,21 +163,20 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return newTuple; } -Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, - Type *inferedType) +Type *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; } - ObjectType *newObject = inferedType->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType(); + ObjectType *newObject = inferedType->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType(); - for (const auto *it : objectPattern->Properties()) { + for (auto *it : objectPattern->Properties()) { if (it->IsRestElement()) { continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); binder::LocalVariable *foundVar = newObject->GetProperty(prop->Key()->AsIdentifier()->Name(), true); if (foundVar != nullptr) { @@ -187,10 +188,10 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp } ASSERT(prop->Value()->IsAssignmentPattern()); - const ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); + ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); binder::LocalVariable *newProp = - binder::Scope::CreateVar(allocator_, prop->Key()->AsIdentifier()->Name(), + binder::Scope::CreateVar(Allocator(), prop->Key()->AsIdentifier()->Name(), binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right()))); newObject->AddProperty(newProp); @@ -200,17 +201,17 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp return newObject; } -std::tuple Checker::CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param) +std::tuple TSChecker::CheckFunctionAssignmentPatternParameter( + ir::AssignmentExpression *param) { if (param->Left()->IsIdentifier()) { - const ir::Identifier *paramIdent = param->Left()->AsIdentifier(); + ir::Identifier *paramIdent = param->Left()->AsIdentifier(); binder::Variable *paramVar = paramIdent->Variable(); ASSERT(paramVar); if (paramIdent->TypeAnnotation() != nullptr) { paramIdent->TypeAnnotation()->Check(this); - Type *paramType = paramIdent->TypeAnnotation()->AsTypeNode()->GetType(this); + Type *paramType = paramIdent->TypeAnnotation()->GetType(this); paramVar->SetTsType(paramType); ElaborateElementwise(paramType, param->Right(), paramIdent->Start()); return {paramVar->AsLocalVariable(), nullptr, true}; @@ -227,14 +228,14 @@ std::tuple Checker::Chec auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::IN_PARAMETER); if (param->Left()->IsArrayPattern()) { - const ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); + ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); auto context = ArrayDestructuringContext(this, arrayPattern, false, true, arrayPattern->TypeAnnotation(), param->Right()); context.Start(); paramType = CreateParameterTypeForArrayAssignmentPattern(arrayPattern, context.InferedType()); CreatePatternParameterName(param->Left(), ss); } else { - const ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); + ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); auto context = ObjectDestructuringContext(this, objectPattern, false, true, objectPattern->TypeAnnotation(), param->Right()); context.Start(); @@ -242,41 +243,27 @@ std::tuple Checker::Chec CreatePatternParameterName(param->Left(), ss); } - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), Allocator()); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(Allocator(), pn.View(), binder::VariableFlags::NONE, param); patternVar->SetTsType(paramType); patternVar->AddFlag(binder::VariableFlags::OPTIONAL); return {patternVar->AsLocalVariable(), nullptr, true}; } -std::tuple Checker::CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionRestParameter( + ir::SpreadElement *param, SignatureInfo *signatureInfo) { - const ir::Expression *typeAnnotation = nullptr; - switch (param->Argument()->Type()) { - case ir::AstNodeType::IDENTIFIER: { - typeAnnotation = param->Argument()->AsIdentifier()->TypeAnnotation(); - break; - } - case ir::AstNodeType::OBJECT_PATTERN: { - typeAnnotation = param->Argument()->AsArrayPattern()->TypeAnnotation(); - break; - } - case ir::AstNodeType::ARRAY_PATTERN: { - typeAnnotation = param->Argument()->AsObjectPattern()->TypeAnnotation(); - break; - } - default: { - UNREACHABLE(); - } + ir::TypeNode *typeAnnotation = nullptr; + if (param->Argument() != nullptr) { + typeAnnotation = param->Argument()->AsAnnotatedExpression()->TypeAnnotation(); } - Type *restType = allocator_->New(GlobalAnyType()); + Type *restType = Allocator()->New(GlobalAnyType()); if (typeAnnotation != nullptr) { typeAnnotation->Check(this); - restType = typeAnnotation->AsTypeNode()->GetType(this); + restType = typeAnnotation->GetType(this); if (!restType->IsArrayType()) { ThrowTypeError("A rest parameter must be of an array type", param->Start()); } @@ -284,7 +271,7 @@ std::tuple Checker::Chec switch (param->Argument()->Type()) { case ir::AstNodeType::IDENTIFIER: { - const ir::Identifier *restIdent = param->Argument()->AsIdentifier(); + ir::Identifier *restIdent = param->Argument()->AsIdentifier(); ASSERT(restIdent->Variable()); restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType()); return {nullptr, restIdent->Variable()->AsLocalVariable(), false}; @@ -314,14 +301,14 @@ std::tuple Checker::Chec } } -std::tuple Checker::CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param) +std::tuple TSChecker::CheckFunctionArrayPatternParameter( + ir::ArrayExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), Allocator()); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(Allocator(), pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -336,14 +323,14 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param) +std::tuple TSChecker::CheckFunctionObjectPatternParameter( + ir::ObjectExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), Allocator()); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(Allocator(), pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -358,13 +345,12 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionParameter( + ir::Expression *param, SignatureInfo *signatureInfo) { - auto found = nodeCache_.find(param); - if (found != nodeCache_.end()) { - ASSERT(found->second->Variable()); - binder::Variable *var = found->second->Variable(); + if (param->TsType() != nullptr) { + ASSERT(param->TsType()->Variable()); + binder::Variable *var = param->TsType()->Variable(); return {var->AsLocalVariable(), nullptr, var->HasFlag(binder::VariableFlags::OPTIONAL)}; } @@ -399,16 +385,16 @@ std::tuple Checker::Chec } if (cache) { - Type *placeholder = allocator_->New(GlobalAnyType()); + Type *placeholder = Allocator()->New(GlobalAnyType()); placeholder->SetVariable(std::get<0>(result)); - nodeCache_.insert({param, placeholder}); + param->SetTsType(placeholder); } return result; } -void Checker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, - SignatureInfo *signatureInfo) +void TSChecker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, + SignatureInfo *signatureInfo) { signatureInfo->restVar = nullptr; signatureInfo->minArgCount = 0; @@ -433,14 +419,14 @@ void Checker::CheckFunctionParameterDeclarations(const ArenaVectorIsArrayPattern() || prop_value->IsObjectPattern() || (prop_value->IsAssignmentPattern() && (prop_value->AsAssignmentPattern()->Left()->IsArrayPattern() || prop_value->AsAssignmentPattern()->Left()->IsObjectPattern())); } -void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss) +void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss) { switch (node->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -480,7 +466,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr break; } case ir::AstNodeType::PROPERTY: { - const ir::Property *prop = node->AsProperty(); + ir::Property *prop = node->AsProperty(); util::StringView propName; if (prop->Key()->IsIdentifier()) { @@ -488,7 +474,8 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } else { switch (prop->Key()->Type()) { case ir::AstNodeType::NUMBER_LITERAL: { - propName = util::Helpers::ToStringView(allocator_, prop->Key()->AsNumberLiteral()->Number()); + propName = util::Helpers::ToStringView(Allocator(), + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::BIGINT_LITERAL: { @@ -510,14 +497,14 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr if (ShouldCreatePropertyValueName(prop->Value())) { ss << ": "; - Checker::CreatePatternParameterName(prop->Value(), ss); + TSChecker::CreatePatternParameterName(prop->Value(), ss); } break; } case ir::AstNodeType::REST_ELEMENT: { ss << "..."; - Checker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); + TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); break; } default: @@ -525,7 +512,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } } -const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, const ir::ScriptFunction *node) +ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node) { for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) { if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) { @@ -537,22 +524,21 @@ const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, return nullptr; } -void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) +void TSChecker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) { - const ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); + ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); if (bodyDeclaration->IsOverload()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", bodyDeclaration->Id()->Start()); } - ObjectDescriptor *descWithOverload = allocator_->New(allocator_); + ObjectDescriptor *descWithOverload = Allocator()->New(Allocator()); for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) { - const ir::ScriptFunction *func = *it; + ir::ScriptFunction *func = *it; ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement()); - const ir::Statement *subsequentNode = - FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); + ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); ASSERT(subsequentNode); if (!subsequentNode->IsFunctionDeclaration()) { @@ -560,7 +546,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin func->Id()->Start()); } - const ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); + ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); if (subsequentFunc->Id()->Name() != func->Id()->Name()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", @@ -573,26 +559,25 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin ScopeContext scopeCtx(this, func->Scope()); - auto *overloadSignatureInfo = allocator_->New(allocator_); + auto *overloadSignatureInfo = Allocator()->New(Allocator()); CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo); Type *returnType = GlobalAnyType(); if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + returnType = func->ReturnTypeAnnotation()->GetType(this); } - Signature *overloadSignature = allocator_->New(overloadSignatureInfo, returnType); - overloadSignature->SetNode(func); + Signature *overloadSignature = Allocator()->New(overloadSignatureInfo, returnType, func); descWithOverload->callSignatures.push_back(overloadSignature); } ScopeContext scopeCtx(this, bodyDeclaration->Scope()); - auto *signatureInfo = allocator_->New(allocator_); + auto *signatureInfo = Allocator()->New(Allocator()); CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo); - auto *bodyCallSignature = allocator_->New(signatureInfo, GlobalResolvingReturnType()); + auto *bodyCallSignature = Allocator()->New(signatureInfo, GlobalResolvingReturnType()); if (descWithOverload->callSignatures.empty()) { Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature); @@ -603,7 +588,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration)); if (!descWithOverload->callSignatures.empty()) { - Type *funcType = allocator_->New(descWithOverload); + Type *funcType = Allocator()->New(descWithOverload); funcType->SetVariable(funcVar); funcVar->SetTsType(funcType); @@ -611,21 +596,21 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin if (bodyCallSignature->ReturnType()->IsVoidType() || IsTypeAssignableTo(bodyCallSignature->ReturnType(), iter->ReturnType()) || IsTypeAssignableTo(iter->ReturnType(), bodyCallSignature->ReturnType())) { - bodyCallSignature->AssignmentTarget(relation_, iter); + bodyCallSignature->AssignmentTarget(Relation(), iter); - if (relation_->IsTrue()) { + if (Relation()->IsTrue()) { continue; } } - ASSERT(iter->Node() && iter->Node()->IsScriptFunction()); + ASSERT(iter->Function()); ThrowTypeError("This overload signature is not compatible with its implementation signature", - iter->Node()->AsScriptFunction()->Id()->Start()); + iter->Function()->Id()->Start()); } } } -void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes) +void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes) { parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void { if (childNode->IsScriptFunction()) { @@ -647,11 +632,11 @@ void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaV }); } -static bool SearchForReturnOrThrow(const ir::AstNode *parent) +static bool SearchForReturnOrThrow(ir::AstNode *parent) { bool found = false; - parent->Iterate([&found](const ir::AstNode *childNode) -> void { + parent->Iterate([&found](ir::AstNode *childNode) -> void { if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) { found = true; return; @@ -667,8 +652,8 @@ static bool SearchForReturnOrThrow(const ir::AstNode *parent) return found; } -void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, - lexer::SourcePosition lineInfo, const char *errMsg) +void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, + lexer::SourcePosition lineInfo, const char *errMsg) { if (!SearchForReturnOrThrow(func->Body())) { ThrowTypeError(errMsg, lineInfo); @@ -677,8 +662,9 @@ void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFu // noImplicitReturn compiler option for TypeScript we should update this function } -ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, - uint32_t callArgsSize, bool *haveSignatureWithRest) +ArgRange TSChecker::GetArgRange(const ArenaVector &signatures, + ArenaVector *potentialSignatures, uint32_t callArgsSize, + bool *haveSignatureWithRest) { uint32_t minArg = UINT32_MAX; uint32_t maxArg = 0; @@ -704,7 +690,7 @@ ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaV return {minArg, maxArg}; } -bool Checker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) +bool TSChecker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) { for (size_t index = 0; index < args.size(); index++) { checker::Type *sigArgType = nullptr; @@ -739,14 +725,15 @@ bool Checker::CallMatchesSignature(const ArenaVector &args, Si return true; } -Type *Checker::resolveCallOrNewExpression(const ArenaVector &signatures, - ArenaVector arguments, const lexer::SourcePosition &errPos) +Type *TSChecker::resolveCallOrNewExpression(const ArenaVector &signatures, + ArenaVector arguments, + const lexer::SourcePosition &errPos) { if (signatures.empty()) { ThrowTypeError("This expression is not callable.", errPos); } - ArenaVector potentialSignatures(allocator_->Adapter()); + ArenaVector potentialSignatures(Allocator()->Adapter()); bool haveSignatureWithRest = false; auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest); diff --git a/typescript/core/helpers.cpp b/checker/ts/helpers.cpp similarity index 72% rename from typescript/core/helpers.cpp rename to checker/ts/helpers.cpp index 5d57490f2..5ecbb55ae 100644 --- a/typescript/core/helpers.cpp +++ b/checker/ts/helpers.cpp @@ -21,26 +21,27 @@ #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeAliasDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" -#include "plugins/ecmascript/es2panda/typescript/core/typeElaborationContext.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/ts/typeElaborationContext.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -void Checker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) +void TSChecker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsVoidType()) { ThrowTypeError("An expression of type void cannot be tested for truthiness", lineInfo); } } -Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) +Type *TSChecker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsNullType()) { ThrowTypeError("Object is possibly 'null'.", lineInfo); @@ -53,7 +54,7 @@ Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) return type; } -Type *Checker::GetBaseTypeOfLiteralType(Type *type) +Type *TSChecker::GetBaseTypeOfLiteralType(Type *type) { if (HasStatus(CheckerStatus::KEEP_LITERAL_TYPE)) { return type; @@ -77,7 +78,7 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto *it : constituentTypes) { @@ -90,12 +91,12 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) return type; } -void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, - const char *invalidOptionalChainMsg) +void TSChecker::CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, + const char *invalidOptionalChainMsg) { if (expr->IsIdentifier()) { const util::StringView &name = expr->AsIdentifier()->Name(); - binder::ScopeFindResult result = scope_->Find(name); + binder::ScopeFindResult result = Scope()->Find(name); ASSERT(result.variable); if (result.variable->HasFlag(binder::VariableFlags::ENUM_LITERAL)) { @@ -110,14 +111,14 @@ void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *i } } -void Checker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] const ir::Expression *condExpr, - [[maybe_unused]] Type *type, - [[maybe_unused]] const ir::AstNode *body) +void TSChecker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] ir::Expression *condExpr, + [[maybe_unused]] Type *type, + [[maybe_unused]] ir::AstNode *body) { // TODO(aszilagyi) rework this } -Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) +Type *TSChecker::ExtractDefinitelyFalsyTypes(Type *type) { if (type->IsStringType()) { return GlobalEmptyStringType(); @@ -141,7 +142,7 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto &it : constituentTypes) { @@ -154,12 +155,12 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) return GlobalNeverType(); } -Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) +Type *TSChecker::RemoveDefinitelyFalsyTypes(Type *type) { if ((static_cast(GetFalsyFlags(type)) & static_cast(TypeFlag::DEFINITELY_FALSY)) != 0U) { if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); for (auto &it : constituentTypes) { if ((static_cast(GetFalsyFlags(it)) & static_cast(TypeFlag::DEFINITELY_FALSY)) == @@ -185,7 +186,7 @@ Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) return type; } -TypeFlag Checker::GetFalsyFlags(Type *type) +TypeFlag TSChecker::GetFalsyFlags(Type *type) { if (type->IsStringLiteralType()) { return type->AsStringLiteralType()->Value().Empty() ? TypeFlag::STRING_LITERAL : TypeFlag::NONE; @@ -217,14 +218,14 @@ TypeFlag Checker::GetFalsyFlags(Type *type) return static_cast(type->TypeFlags() & TypeFlag::POSSIBLY_FALSY); } -bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { binder::Variable *resultVar = nullptr; if (childNode->IsIdentifier()) { - binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); + binder::ScopeFindResult result = Scope()->Find(childNode->AsIdentifier()->Name()); ASSERT(result.variable); resultVar = result.variable; } @@ -242,13 +243,13 @@ bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::V return found; } -bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier()) { - binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); + binder::ScopeFindResult result = Scope()->Find(childNode->AsIdentifier()->Name()); ASSERT(result.variable); if (result.variable == searchVar) { found = true; @@ -262,7 +263,7 @@ bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, bin return found; } -bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { while (parent->IsBinaryExpression() && parent->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { @@ -276,7 +277,8 @@ bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, b return false; } -void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo) +void TSChecker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, + lexer::SourcePosition lineInfo) { if (!HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", AsSrc(rightType)}, @@ -286,7 +288,7 @@ void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *ri ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", rightType}, lineInfo); } -void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) +void TSChecker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) { if (isAsSrcLeftType || !target->HasTypeFlag(TypeFlag::LITERAL)) { ThrowTypeError({"Type '", AsSrc(source), "' is not assignable to type '", target, "'."}, lineInfo); @@ -295,11 +297,11 @@ void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosi ThrowTypeError({"Type '", source, "' is not assignable to type '", target, "'."}, lineInfo); } -Type *Checker::GetUnaryResultType(Type *operandType) +Type *TSChecker::GetUnaryResultType(Type *operandType) { - if (checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { + if (checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { if (operandType->HasTypeFlag(checker::TypeFlag::UNION_OR_INTERSECTION) && - checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { + checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { return GlobalNumberOrBigintType(); } @@ -309,7 +311,7 @@ Type *Checker::GetUnaryResultType(Type *operandType) return GlobalNumberType(); } -void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos) +void TSChecker::ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::KEEP_LITERAL_TYPE); @@ -332,7 +334,7 @@ void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourc ThrowAssignmentError(sourceType, targetType, pos); } -void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator) +void TSChecker::InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator) { ASSERT(declarator->Id()->IsIdentifier()); @@ -340,7 +342,7 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de ASSERT(var); if (declarator->Id()->AsIdentifier()->TypeAnnotation() != nullptr) { - var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->GetType(this)); return; } @@ -353,20 +355,19 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de declarator->Id()->Start()); } -Type *Checker::GetTypeOfVariable(binder::Variable *var) +Type *TSChecker::GetTypeOfVariable(binder::Variable *var) { if (var->TsType() != nullptr) { return var->TsType(); } - const binder::Decl *decl = var->Declaration(); + binder::Decl *decl = var->Declaration(); - if (!typeStack_.insert(decl->Node()).second) { - ThrowTypeError({"'", var->Name(), - "' is referenced directly or indirectly in its " - "own initializer ot type annotation."}, - decl->Node()->Start()); - } + TypeStackElement tse(this, decl->Node(), + {"'", var->Name(), + "' is referenced directly or indirectly in its " + "own initializer ot type annotation."}, + decl->Node()->Start()); switch (decl->Type()) { case binder::DeclType::CONST: @@ -380,7 +381,8 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) [[fallthrough]]; } case binder::DeclType::VAR: { - const ir::AstNode *declarator = FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); + ir::AstNode *declarator = + util::Helpers::FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); ASSERT(declarator); if (declarator->AsVariableDeclarator()->Id()->IsIdentifier()) { @@ -392,12 +394,12 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PROPERTY: { - var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->GetType(this)); break; } case binder::DeclType::METHOD: { - auto *signatureInfo = allocator_->New(allocator_); - auto *callSignature = allocator_->New(signatureInfo, GlobalAnyType()); + auto *signatureInfo = Allocator()->New(Allocator()); + auto *callSignature = Allocator()->New(signatureInfo, GlobalAnyType()); var->SetTsType(CreateFunctionTypeWithSignature(callSignature)); break; } @@ -407,13 +409,13 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PARAM: { - const ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); + ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); if (declaration->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsIdentifier(); + auto *ident = declaration->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -421,11 +423,11 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } if (declaration->IsAssignmentPattern() && declaration->AsAssignmentPattern()->Left()->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); + ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -458,18 +460,16 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } } - typeStack_.erase(decl->Node()); return var->TsType(); } -Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::TSTypeReference *node, - binder::Variable *var) +Type *TSChecker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); if (resolvedType == nullptr) { - ObjectDescriptor *desc = allocator_->New(allocator_); - resolvedType = allocator_->New(allocator_, var->Name(), desc); + ObjectDescriptor *desc = Allocator()->New(Allocator()); + resolvedType = Allocator()->New(Allocator(), var->Name(), desc); resolvedType->SetVariable(var); var->SetTsType(resolvedType); } @@ -477,27 +477,25 @@ Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::T return resolvedType; } -Type *Checker::GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); - if (resolvedType == nullptr) { - if (!typeStack_.insert(var).second) { - ThrowTypeError({"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - } + if (resolvedType != nullptr) { + return resolvedType; + } - ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); - const ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); - resolvedType = declaration->TypeAnnotation()->AsTypeNode()->GetType(this); - var->SetTsType(resolvedType); + TypeStackElement tse(this, var, {"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - typeStack_.erase(var); - } + ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); + ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); + resolvedType = declaration->TypeAnnotation()->GetType(this); + var->SetTsType(resolvedType); return resolvedType; } -Type *Checker::GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var) { ASSERT(var->Declaration()); binder::Decl *decl = var->Declaration(); diff --git a/typescript/core/object.cpp b/checker/ts/object.cpp similarity index 78% rename from typescript/core/object.cpp rename to checker/ts/object.cpp index d25b48d4f..0c218f1ef 100644 --- a/typescript/core/object.cpp +++ b/checker/ts/object.cpp @@ -22,10 +22,10 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsIndexSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsIndexSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" @@ -34,11 +34,11 @@ #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -void Checker::CheckIndexConstraints(Type *type) +void TSChecker::CheckIndexConstraints(Type *type) { if (!type->IsObjectType()) { return; @@ -80,7 +80,7 @@ void Checker::CheckIndexConstraints(Type *type) } } -void Checker::ResolveStructuredTypeMembers(Type *type) +void TSChecker::ResolveStructuredTypeMembers(Type *type) { if (type->IsObjectType()) { ObjectType *obj_type = type->AsObjectType(); @@ -102,17 +102,17 @@ void Checker::ResolveStructuredTypeMembers(Type *type) } } -void Checker::ResolveUnionTypeMembers(UnionType *type) +void TSChecker::ResolveUnionTypeMembers(UnionType *type) { if (type->MergedObjectType() != nullptr) { return; } - ObjectDescriptor *desc = allocator_->New(allocator_); - ArenaVector stringInfoTypes(allocator_->Adapter()); - ArenaVector numberInfoTypes(allocator_->Adapter()); - ArenaVector callSignatures(allocator_->Adapter()); - ArenaVector constructSignatures(allocator_->Adapter()); + ObjectDescriptor *desc = Allocator()->New(Allocator()); + ArenaVector stringInfoTypes(Allocator()->Adapter()); + ArenaVector numberInfoTypes(Allocator()->Adapter()); + ArenaVector callSignatures(Allocator()->Adapter()); + ArenaVector constructSignatures(Allocator()->Adapter()); for (auto *it : type->AsUnionType()->ConstituentTypes()) { if (!it->IsObjectType()) { @@ -147,19 +147,19 @@ void Checker::ResolveUnionTypeMembers(UnionType *type) desc->constructSignatures = constructSignatures; if (!stringInfoTypes.empty()) { - desc->stringIndexInfo = allocator_->New(CreateUnionType(std::move(stringInfoTypes)), "x", false); + desc->stringIndexInfo = Allocator()->New(CreateUnionType(std::move(stringInfoTypes)), "x", false); } if (!numberInfoTypes.empty()) { - desc->numberIndexInfo = allocator_->New(CreateUnionType(std::move(numberInfoTypes)), "x", false); + desc->numberIndexInfo = Allocator()->New(CreateUnionType(std::move(numberInfoTypes)), "x", false); } - ObjectType *merged_type = allocator_->New(desc); + ObjectType *merged_type = Allocator()->New(desc); merged_type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); type->SetMergedObjectType(merged_type); } -void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) +void TSChecker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; @@ -171,16 +171,16 @@ void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); } -void Checker::ResolveObjectTypeMembers(ObjectType *type) +void TSChecker::ResolveObjectTypeMembers(ObjectType *type) { if (!type->IsObjectLiteralType() || type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; } ASSERT(type->Variable() && type->Variable()->Declaration()->Node()->IsTSTypeLiteral()); - const auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); + ArenaVector signatureDeclarations(Allocator()->Adapter()); + ArenaVector indexDeclarations(Allocator()->Adapter()); for (auto *it : typeLiteral->Members()) { ResolvePropertiesOfObjectType(type, it, signatureDeclarations, indexDeclarations, false); @@ -192,10 +192,9 @@ void Checker::ResolveObjectTypeMembers(ObjectType *type) ResolveIndexInfosOfObjectType(type, indexDeclarations); } -void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, - bool isInterface) +void TSChecker::ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface) { if (member->IsTSPropertySignature()) { binder::Variable *prop = member->AsTSPropertySignature()->Variable(); @@ -228,8 +227,8 @@ void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expressi indexDeclarations.push_back(member->AsTSIndexSignature()); } -void Checker::ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations) +void TSChecker::ResolveSignaturesOfObjectType(ObjectType *type, + ArenaVector &signatureDeclarations) { for (auto *it : signatureDeclarations) { Type *placeholderObj = it->Check(this); @@ -243,8 +242,7 @@ void Checker::ResolveSignaturesOfObjectType(ObjectType *type, type->AddConstructSignature(placeholderObj->AsObjectType()->ConstructSignatures()[0]); } } -void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, - ArenaVector &indexDeclarations) +void TSChecker::ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations) { for (auto *it : indexDeclarations) { Type *placeholderObj = it->Check(this); @@ -270,8 +268,8 @@ void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, } } -binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { if (type->IsObjectType()) { ResolveObjectTypeMembers(type->AsObjectType()); @@ -285,8 +283,8 @@ binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView return nullptr; } -binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { auto found = type->CachedSyntheticPropertis().find(name); @@ -295,7 +293,7 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S } binder::VariableFlags flags = binder::VariableFlags::PROPERTY; - ArenaVector collectedTypes(allocator_->Adapter()); + ArenaVector collectedTypes(Allocator()->Adapter()); for (auto *it : type->ConstituentTypes()) { binder::Variable *prop = GetPropertyOfType(it, name); @@ -341,17 +339,16 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S return nullptr; } - binder::Variable *syntheticProp = binder::Scope::CreateVar(allocator_, name, flags, nullptr); + binder::Variable *syntheticProp = binder::Scope::CreateVar(Allocator(), name, flags, nullptr); syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes))); type->CachedSyntheticPropertis().insert({name, syntheticProp}); return syntheticProp; } -Type *Checker::CheckComputedPropertyName(const ir::Expression *key) +Type *TSChecker::CheckComputedPropertyName(ir::Expression *key) { - auto found = nodeCache_.find(key); - if (found != nodeCache_.end()) { - return found->second; + if (key->TsType() != nullptr) { + return key->TsType(); } Type *keyType = key->Check(this); @@ -364,11 +361,11 @@ Type *Checker::CheckComputedPropertyName(const ir::Expression *key) key->Start()); } - nodeCache_.insert({key, keyType}); + key->SetTsType(keyType); return keyType; } -IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) +IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType) { ResolveStructuredTypeMembers(type); bool getNumberInfo = indexType->HasTypeFlag(TypeFlag::NUMBER_LIKE); @@ -394,7 +391,7 @@ IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) return nullptr; } -Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) +Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType) { if (type->IsArrayType()) { return type->AsArrayType()->ElementType(); @@ -407,7 +404,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) prop = GetPropertyOfType(type, indexType->AsStringLiteralType()->Value()); } else { util::StringView prop_name = - util::Helpers::ToStringView(allocator_, indexType->AsNumberLiteralType()->Value()); + util::Helpers::ToStringView(Allocator(), indexType->AsNumberLiteralType()->Value()); prop = GetPropertyOfType(type, prop_name); } @@ -439,7 +436,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) return nullptr; } -ArenaVector Checker::GetBaseTypes(InterfaceType *type) +ArenaVector TSChecker::GetBaseTypes(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES)) { return type->Bases(); @@ -448,18 +445,16 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - if (!typeStack_.insert(type).second) { - ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."}, - decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); - } + TypeStackElement tse(this, type, {"Type ", type->Name(), " recursively references itself as a base type."}, + decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); for (const auto *declaration : decl->Decls()) { if (declaration->Extends().empty()) { continue; } - for (const auto *extends : declaration->Extends()) { - Type *baseType = extends->Expr()->AsTypeNode()->GetType(this); + for (auto *extends : declaration->Extends()) { + Type *baseType = extends->Expr()->GetType(this); if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) { ThrowTypeError( @@ -497,11 +492,10 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) } type->AddObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES); - typeStack_.erase(type); return type->Bases(); } -void Checker::ResolveDeclaredMembers(InterfaceType *type) +void TSChecker::ResolveDeclaredMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS)) { return; @@ -510,11 +504,11 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + ArenaVector signatureDeclarations(Allocator()->Adapter()); + ArenaVector indexDeclarations(Allocator()->Adapter()); for (const auto *declaration : decl->Decls()) { - for (const auto *member : declaration->Body()->Body()) { + for (auto *member : declaration->Body()->Body()) { ResolvePropertiesOfObjectType(type, member, signatureDeclarations, indexDeclarations, true); } @@ -525,8 +519,8 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) } } -bool Checker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, - const lexer::SourcePosition &locInfo) +bool TSChecker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, + const lexer::SourcePosition &locInfo) { if (prop->HasFlag(binder::VariableFlags::COMPUTED)) { return true; diff --git a/typescript/core/typeCreation.cpp b/checker/ts/typeCreation.cpp similarity index 45% rename from typescript/core/typeCreation.cpp rename to checker/ts/typeCreation.cpp index dde86e22d..edd6fed5d 100644 --- a/typescript/core/typeCreation.cpp +++ b/checker/ts/typeCreation.cpp @@ -13,49 +13,49 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -Type *Checker::CreateNumberLiteralType(double value) +Type *TSChecker::CreateNumberLiteralType(double value) { auto search = numberLiteralMap_.find(value); if (search != numberLiteralMap_.end()) { return search->second; } - auto *newNumLiteralType = allocator_->New(value); + auto *newNumLiteralType = Allocator()->New(value); numberLiteralMap_.insert({value, newNumLiteralType}); return newNumLiteralType; } -Type *Checker::CreateBigintLiteralType(const util::StringView &str, bool negative) +Type *TSChecker::CreateBigintLiteralType(const util::StringView &str, bool negative) { auto search = bigintLiteralMap_.find(str); if (search != bigintLiteralMap_.end()) { return search->second; } - auto *newBigiLiteralType = allocator_->New(str, negative); + auto *newBigiLiteralType = Allocator()->New(str, negative); bigintLiteralMap_.insert({str, newBigiLiteralType}); return newBigiLiteralType; } -Type *Checker::CreateStringLiteralType(const util::StringView &str) +Type *TSChecker::CreateStringLiteralType(const util::StringView &str) { auto search = stringLiteralMap_.find(str); if (search != stringLiteralMap_.end()) { return search->second; } - auto *newStrLiteralType = allocator_->New(str); + auto *newStrLiteralType = Allocator()->New(str); stringLiteralMap_.insert({str, newStrLiteralType}); return newStrLiteralType; } -Type *Checker::CreateUnionType(std::initializer_list constituentTypes) +Type *TSChecker::CreateUnionType(std::initializer_list constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); for (auto *it : constituentTypes) { newConstituentTypes.push_back(it); @@ -64,9 +64,9 @@ Type *Checker::CreateUnionType(std::initializer_list constituentTypes) return CreateUnionType(std::move(newConstituentTypes)); } -Type *Checker::CreateUnionType(ArenaVector &constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -80,24 +80,24 @@ Type *Checker::CreateUnionType(ArenaVector &constituentTypes) newConstituentTypes.push_back(it); } - UnionType::RemoveDuplicatedTypes(relation_, newConstituentTypes); + UnionType::RemoveDuplicatedTypes(Relation(), newConstituentTypes); if (newConstituentTypes.size() == 1) { return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(newConstituentTypes); + auto *newUnionType = Allocator()->New(newConstituentTypes); - return UnionType::HandleUnionType(newUnionType, globalTypes_); + return UnionType::HandleUnionType(newUnionType, GetGlobalTypesHolder()); } -Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &&constituentTypes) { if (constituentTypes.empty()) { return nullptr; } - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(Allocator()->Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -111,63 +111,63 @@ Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) newConstituentTypes.push_back(it); } - UnionType::RemoveDuplicatedTypes(relation_, newConstituentTypes); + UnionType::RemoveDuplicatedTypes(Relation(), newConstituentTypes); if (newConstituentTypes.size() == 1) { return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(std::move(newConstituentTypes)); + auto *newUnionType = Allocator()->New(std::move(newConstituentTypes)); - return UnionType::HandleUnionType(newUnionType, globalTypes_); + return UnionType::HandleUnionType(newUnionType, GetGlobalTypesHolder()); } -Type *Checker::CreateObjectTypeWithCallSignature(Signature *callSignature) +Type *TSChecker::CreateObjectTypeWithCallSignature(Signature *callSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = Allocator()->New(Allocator()->New(Allocator())); objType->AddCallSignature(callSignature); return objType; } -Type *Checker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) +Type *TSChecker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = Allocator()->New(Allocator()->New(Allocator())); objType->AddConstructSignature(constructSignature); return objType; } -Type *Checker::CreateFunctionTypeWithSignature(Signature *callSignature) +Type *TSChecker::CreateFunctionTypeWithSignature(Signature *callSignature) { - auto *funcObjType = allocator_->New(allocator_->New(allocator_)); + auto *funcObjType = Allocator()->New(Allocator()->New(Allocator())); funcObjType->AddCallSignature(callSignature); return funcObjType; } -Type *Checker::CreateConstructorTypeWithSignature(Signature *constructSignature) +Type *TSChecker::CreateConstructorTypeWithSignature(Signature *constructSignature) { - auto *constructObjType = allocator_->New(allocator_->New(allocator_)); + auto *constructObjType = Allocator()->New(Allocator()->New(Allocator())); constructObjType->AddConstructSignature(constructSignature); return constructObjType; } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + desc->stringIndexInfo = Allocator()->New(GlobalAnyType(), "x", readonly); + return Allocator()->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, - NamedTupleMemberPool &&namedMembers) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, + NamedTupleMemberPool &&namedMembers) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); + desc->stringIndexInfo = Allocator()->New(GlobalAnyType(), "x", readonly); if (!namedMembers.empty()) { - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, - readonly, std::move(namedMembers)); + return Allocator()->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, + readonly, std::move(namedMembers)); } - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + return Allocator()->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } } // namespace panda::es2panda::checker diff --git a/typescript/core/typeElaborationContext.cpp b/checker/ts/typeElaborationContext.cpp similarity index 94% rename from typescript/core/typeElaborationContext.cpp rename to checker/ts/typeElaborationContext.cpp index cc448257a..ee616ad67 100644 --- a/typescript/core/typeElaborationContext.cpp +++ b/checker/ts/typeElaborationContext.cpp @@ -26,7 +26,7 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" namespace panda::es2panda::checker { -Type *ElaborationContext::GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode) +Type *ElaborationContext::GetBestMatchingType(Type *indexType, ir::Expression *sourceNode) { ArenaVector bestMatchingType(checker_->Allocator()->Adapter()); Type *sourceType = sourceNode != nullptr ? checker_->CheckTypeCached(sourceNode) : checker_->GlobalAnyType(); @@ -105,7 +105,7 @@ void ObjectElaborationContext::Start() continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); Type *propKeyType = nullptr; if (prop->IsComputed()) { @@ -117,8 +117,8 @@ void ObjectElaborationContext::Start() break; } case ir::AstNodeType::NUMBER_LITERAL: { - propKeyType = - checker_->Allocator()->New(prop->Key()->AsNumberLiteral()->Number()); + propKeyType = checker_->Allocator()->New( + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::STRING_LITERAL: { diff --git a/typescript/core/typeElaborationContext.h b/checker/ts/typeElaborationContext.h similarity index 76% rename from typescript/core/typeElaborationContext.h rename to checker/ts/typeElaborationContext.h index 4dc247ee4..df8925df2 100644 --- a/typescript/core/typeElaborationContext.h +++ b/checker/ts/typeElaborationContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H +#define ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,7 +31,7 @@ class Type; class ElaborationContext { public: - ElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : checker_(checker), targetType_(targetType), @@ -45,14 +45,14 @@ public: virtual void Start() = 0; virtual void RemoveUnnecessaryTypes() = 0; - Type *GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode); + Type *GetBestMatchingType(Type *indexType, ir::Expression *sourceNode); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; + TSChecker *checker_; Type *targetType_; Type *sourceType_; - const ir::Expression *sourceNode_; + ir::Expression *sourceNode_; const lexer::SourcePosition startPos_; ArenaVector potentialTypes_; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -60,7 +60,7 @@ protected: class ArrayElaborationContext : public ElaborationContext { public: - ArrayElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ArrayElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { @@ -75,7 +75,7 @@ private: class ObjectElaborationContext : public ElaborationContext { public: - ObjectElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ObjectElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { diff --git a/typescript/core/util.cpp b/checker/ts/util.cpp similarity index 76% rename from typescript/core/util.cpp rename to checker/ts/util.cpp index 779729f20..0d6f24ba6 100644 --- a/typescript/core/util.cpp +++ b/checker/ts/util.cpp @@ -19,23 +19,12 @@ #include "plugins/ecmascript/es2panda/ir/expressions/templateLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -const ir::TSQualifiedName *Checker::ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName) +ir::MemberExpression *TSChecker::ResolveLeftMostMemberExpression(ir::MemberExpression *expr) { - const ir::TSQualifiedName *iter = qualifiedName; - - while (iter->Left()->IsTSQualifiedName()) { - iter = iter->Left()->AsTSQualifiedName(); - } - - return iter; -} - -const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::MemberExpression *expr) -{ - const ir::MemberExpression *iter = expr; + ir::MemberExpression *iter = expr; while (iter->Object()->IsMemberExpression()) { iter = iter->Object()->AsMemberExpression(); @@ -44,9 +33,9 @@ const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::M return iter; } -bool Checker::InAssignment(const ir::AstNode *node) +bool TSChecker::InAssignment(ir::AstNode *node) { - const ir::AstNode *parent = node; + ir::AstNode *parent = node; while (parent->Parent() != nullptr) { if (parent->Parent()->IsAssignmentExpression()) { @@ -54,7 +43,7 @@ bool Checker::InAssignment(const ir::AstNode *node) } if (parent->Parent()->IsBinaryExpression()) { - const ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); + ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); return IsAssignmentOperator(binaryExpr->OperatorType()) && binaryExpr->Left() == parent; } @@ -67,7 +56,7 @@ bool Checker::InAssignment(const ir::AstNode *node) return false; } -bool Checker::IsAssignmentOperator(lexer::TokenType op) +bool TSChecker::IsAssignmentOperator(lexer::TokenType op) { switch (op) { case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: @@ -91,7 +80,7 @@ bool Checker::IsAssignmentOperator(lexer::TokenType op) } } -bool Checker::IsLiteralType(const Type *type) +bool TSChecker::IsLiteralType(const Type *type) { if (type->IsBooleanType()) { return true; @@ -109,23 +98,7 @@ bool Checker::IsLiteralType(const Type *type) return type->HasTypeFlag(TypeFlag::UNIT); } -const ir::AstNode *Checker::FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type) -{ - node = node->Parent(); - - while (node->Type() != type) { - if (node->Parent() != nullptr) { - node = node->Parent(); - continue; - } - - return nullptr; - } - - return node; -} - -const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop) +ir::AstNode *TSChecker::FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop) { while (node->Parent()->Type() != stop) { if (node->Parent() != nullptr) { @@ -139,7 +112,7 @@ const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, return node; } -bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) +bool TSChecker::MaybeTypeOfKind(const Type *type, TypeFlag flags) { if (type->HasTypeFlag(flags)) { return true; @@ -159,7 +132,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) return false; } -bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) +bool TSChecker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) { if (type->IsObjectType() && type->AsObjectType()->Kind() == kind) { return true; @@ -179,7 +152,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) return false; } -bool Checker::IsConstantMemberAccess(const ir::Expression *expr) +bool TSChecker::IsConstantMemberAccess(ir::Expression *expr) { switch (expr->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -196,7 +169,7 @@ bool Checker::IsConstantMemberAccess(const ir::Expression *expr) } } -bool Checker::IsStringLike(const ir::Expression *expr) +bool TSChecker::IsStringLike(ir::Expression *expr) { if (expr->IsStringLiteral()) { return true; diff --git a/checker/types/ets/byteType.cpp b/checker/types/ets/byteType.cpp new file mode 100644 index 000000000..5d2666015 --- /dev/null +++ b/checker/types/ets/byteType.cpp @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "byteType.h" +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void ByteType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsByteType()) { + relation->Result(true); + } +} + +void ByteType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool ByteType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(relation, + checker::TypeRelationFlag::ONLY_CHECK_WIDENING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *ByteType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/byteType.h b/checker/types/ets/byteType.h new file mode 100644 index 000000000..ad2dc2a06 --- /dev/null +++ b/checker/types/ets/byteType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BYTE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BYTE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ByteType : public Type { +public: + using UType = int8_t; + + ByteType() : Type(TypeFlag::BYTE) {} + explicit ByteType(UType value) : Type(TypeFlag::BYTE | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "byte"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BYTE; + } + +private: + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/charType.cpp b/checker/types/ets/charType.cpp new file mode 100644 index 000000000..dec9e5ea0 --- /dev/null +++ b/checker/types/ets/charType.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "charType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void CharType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsCharType()) { + relation->Result(true); + } +} + +void CharType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool CharType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx( + relation, checker::TypeRelationFlag::ONLY_CHECK_WIDENING | checker::TypeRelationFlag::NARROWING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *CharType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/charType.h b/checker/types/ets/charType.h new file mode 100644 index 000000000..0cb102ae8 --- /dev/null +++ b/checker/types/ets/charType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_CHAR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_CHAR_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class CharType : public Type { +public: + using UType = char16_t; + + CharType() : Type(TypeFlag::CHAR) {} + explicit CharType(UType value) : Type(TypeFlag::CHAR | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "char"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_CHAR; + } + +private: + UType value_ {'\0'}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/doubleType.cpp b/checker/types/ets/doubleType.cpp new file mode 100644 index 000000000..8f3b881be --- /dev/null +++ b/checker/types/ets/doubleType.cpp @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "doubleType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/wideningConverter.h" + +namespace panda::es2panda::checker { +void DoubleType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsDoubleType()) { + relation->Result(true); + } +} + +void DoubleType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + WideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool DoubleType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *DoubleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/doubleType.h b/checker/types/ets/doubleType.h new file mode 100644 index 000000000..d97a694f4 --- /dev/null +++ b/checker/types/ets/doubleType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DOUBLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DOUBLE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class DoubleType : public Type { +public: + using UType = double; + + DoubleType() : Type(TypeFlag::DOUBLE) {} + explicit DoubleType(UType value) : Type(TypeFlag::DOUBLE | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "double"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_DOUBLE; + } + +private: + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsArrayType.cpp b/checker/types/ets/etsArrayType.cpp new file mode 100644 index 000000000..678610cc0 --- /dev/null +++ b/checker/types/ets/etsArrayType.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsArrayType.h" + +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void ETSArrayType::ToString(std::stringstream &ss) const +{ + element_->ToString(ss); + ss << "[]"; +} + +void ETSArrayType::ToAssemblerType(std::stringstream &ss) const +{ + element_->ToAssemblerType(ss); +} + +void ETSArrayType::ToAssemblerTypeWithRank(std::stringstream &ss) const +{ + element_->ToAssemblerType(ss); + + for (uint32_t i = Rank(); i > 0; --i) { + ss << "[]"; + } +} + +uint32_t ETSArrayType::Rank() const +{ + uint32_t rank = 1; + auto iter = element_; + while (iter->IsETSArrayType()) { + iter = iter->AsETSArrayType()->ElementType(); + rank++; + } + + return rank; +} + +void ETSArrayType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSArrayType()) { + relation->IsIdenticalTo(element_, other->AsETSArrayType()->ElementType()); + } +} + +void ETSArrayType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsETSArrayType()) { + relation->IsAssignableTo(source->AsETSArrayType()->ElementType(), element_); + } +} + +Type *ETSArrayType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + return relation->GetChecker()->AsETSChecker()->CreateETSArrayType( + element_->Instantiate(allocator, relation, globalTypes)); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsArrayType.h b/checker/types/ets/etsArrayType.h new file mode 100644 index 000000000..d780055c3 --- /dev/null +++ b/checker/types/ets/etsArrayType.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ARRAY_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSArrayType : public Type { +public: + explicit ETSArrayType(Type *elementType) : Type(TypeFlag::ETS_ARRAY), element_(elementType) {} + + Type *ElementType() + { + return element_; + } + + const Type *ElementType() const + { + return element_; + } + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + void ToAssemblerTypeWithRank(std::stringstream &ss) const override; + + uint32_t Rank() const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type *element_; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_ARRAY_TYPE_H */ diff --git a/checker/types/ets/etsBooleanType.cpp b/checker/types/ets/etsBooleanType.cpp new file mode 100644 index 000000000..e9b355d9e --- /dev/null +++ b/checker/types/ets/etsBooleanType.cpp @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsBooleanType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void ETSBooleanType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSBooleanType()) { + relation->Result(true); + } +} + +void ETSBooleanType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } +} + +bool ETSBooleanType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *ETSBooleanType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsBooleanType.h b/checker/types/ets/etsBooleanType.h new file mode 100644 index 000000000..c9fc78c95 --- /dev/null +++ b/checker/types/ets/etsBooleanType.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BOOLEAN_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSBooleanType : public Type { +public: + using UType = bool; + ETSBooleanType() : Type(TypeFlag::ETS_BOOLEAN) {} + explicit ETSBooleanType(UType value) : Type(TypeFlag::ETS_BOOLEAN | TypeFlag::CONSTANT), value_(value) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + UType GetValue() const + { + return value_; + } + + void ToString(std::stringstream &ss) const override + { + ss << "boolean"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BOOLEAN; + } + +private: + UType value_ {false}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsFunctionType.cpp b/checker/types/ets/etsFunctionType.cpp new file mode 100644 index 000000000..265a44cfc --- /dev/null +++ b/checker/types/ets/etsFunctionType.cpp @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsMethodReferenceExpression.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +Signature *ETSFunctionType::FirstAbstractSignature() +{ + for (auto *it : callSignatures_) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + return it; + } + } + + return nullptr; +} + +void ETSFunctionType::ToString(std::stringstream &ss) const +{ + callSignatures_[0]->ToString(ss, nullptr); +} + +void ETSFunctionType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsETSFunctionType()) { + return; + } + + if (callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE)) { + AssignmentTarget(relation, other); + return; + } + + callSignatures_[0]->Identical(relation, other->AsETSFunctionType()->CallSignatures()[0]); +} + +void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (!source->IsETSFunctionType() && + (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) { + return; + } + + ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE)); + + Signature *target = callSignatures_[0]; + Signature *match {}; + auto *sourceFuncType = source->IsETSFunctionType() ? source->AsETSFunctionType() + : source->AsETSObjectType()->GetFunctionalInterfaceInvokeType(); + + for (auto *it : sourceFuncType->CallSignatures()) { + if (target->MinArgCount() != it->MinArgCount()) { + continue; + } + + if ((target->RestVar() != nullptr && it->RestVar() == nullptr) || + (target->RestVar() == nullptr && it->RestVar() != nullptr)) { + continue; + } + + size_t idx = 0; + for (; idx != target->MinArgCount(); idx++) { + if (!relation->IsIdenticalTo(target->Params()[idx]->TsType(), it->Params()[idx]->TsType())) { + break; + } + } + + if (idx != target->MinArgCount()) { + continue; + } + + if (target->RestVar() != nullptr && + !relation->IsIdenticalTo(target->RestVar()->TsType(), it->RestVar()->TsType())) { + continue; + } + + if (!relation->IsAssignableTo(target->ReturnType(), it->ReturnType())) { + continue; + } + + match = it; + break; + } + + if (match == nullptr) { + relation->Result(false); + return; + } + + ASSERT(relation->GetNode() != nullptr); + if (relation->GetNode()->IsETSMethodReferenceExpression()) { + auto *methodRef = relation->GetNode()->AsETSMethodReferenceExpression(); + methodRef->SetComputedSignature(match); + relation->GetChecker()->AsETSChecker()->ResolveLambdaObject( + relation->GetNode()->AsETSMethodReferenceExpression(), callSignatures_[0]->Owner()); + } + + relation->Result(true); +} + +Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_); + + for (auto *it : callSignatures_) { + copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsFunctionType.h b/checker/types/ets/etsFunctionType.h new file mode 100644 index 000000000..ec4c9f433 --- /dev/null +++ b/checker/types/ets/etsFunctionType.h @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FUNCTION_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +class ETSFunctionType : public Type { +public: + explicit ETSFunctionType(util::StringView name, Signature *signature, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + callSignatures_.push_back(signature); + } + + explicit ETSFunctionType(util::StringView name, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + } + + ArenaVector &CallSignatures() + { + return callSignatures_; + } + + const ArenaVector &CallSignatures() const + { + return callSignatures_; + } + + util::StringView Name() const + { + return name_; + } + + void AddCallSignature(Signature *signature) + { + callSignatures_.push_back(signature); + } + + void SetReferencedSignature(Signature *refSignature) + { + refSignature_ = refSignature; + } + + Signature *GetReferencedSignature() const + { + return refSignature_; + } + + Signature *FindSignature(const ir::ScriptFunction *func) const + { + for (auto *it : callSignatures_) { + if (it->Function() == func) { + return it; + } + } + + return nullptr; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << "ets.lang.Object"; + } + + Signature *FirstAbstractSignature(); + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + ArenaVector callSignatures_; + util::StringView name_; + Signature *refSignature_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/ets/etsObjectType.cpp b/checker/types/ets/etsObjectType.cpp new file mode 100644 index 000000000..f637bdb7d --- /dev/null +++ b/checker/types/ets/etsObjectType.cpp @@ -0,0 +1,462 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsObjectType.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" + +namespace panda::es2panda::checker { + +void ETSObjectType::Iterate(const PropertyTraverser &cb) const +{ + for (const auto *prop : GetAllProperties()) { + cb(prop); + } + + if (superType_ != nullptr) { + superType_->Iterate(cb); + } + + for (const auto *interface : interfaces_) { + interface->Iterate(cb); + } +} + +binder::LocalVariable *ETSObjectType::GetProperty(const util::StringView &name, PropertySearchFlags flags) const +{ + binder::LocalVariable *res {}; + if ((flags & PropertySearchFlags::SEARCH_INSTANCE_FIELD) != 0) { + res = GetOwnProperty(name); + } + + if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_FIELD) != 0)) { + res = GetOwnProperty(name); + } + + if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_INSTANCE_DECL) != 0)) { + res = GetOwnProperty(name); + } + + if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_DECL) != 0)) { + res = GetOwnProperty(name); + } + + if (res == nullptr && (flags & PropertySearchFlags::SEARCH_METHOD) != 0) { + if ((flags & PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION) != 0) { + if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) { + res = GetOwnProperty(name); + } + + if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0)) { + res = GetOwnProperty(name); + } + } else { + return CreateSyntheticVarFromEverySignature(name, flags); + } + } + + if ((flags & (PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE)) == 0) { + return res; + } + + if (res != nullptr) { + return res; + } + + if ((flags & PropertySearchFlags::SEARCH_IN_INTERFACES) != 0) { + for (auto *interface : interfaces_) { + res = interface->GetProperty(name, flags); + + if (res != nullptr) { + return res; + } + } + } + + if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) { + res = superType_->GetProperty(name, flags); + } + + return res; +} + +binder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(const util::StringView &name, + PropertySearchFlags flags) const +{ + binder::LocalVariable *res = + allocator_->New(binder::VariableFlags::SYNTHETIC | binder::VariableFlags::METHOD); + ETSFunctionType *funcType = allocator_->New(name, allocator_); + funcType->AddTypeFlag(TypeFlag::SYNTHETIC); + CollectSignaturesForSyntheticType(funcType, name, flags); + + if (funcType->CallSignatures().empty()) { + return nullptr; + } + + res->SetTsType(funcType); + funcType->SetVariable(res); + return res; +} + +void ETSObjectType::CollectSignaturesForSyntheticType(ETSFunctionType *funcType, const util::StringView &name, + PropertySearchFlags flags) const +{ + if ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0) { + auto *found = GetOwnProperty(name); + if (found != nullptr) { + if (found->TsType()->IsETSFunctionType()) { + for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) { + if (((flags & PropertySearchFlags::INGORE_ABSTRACT) != 0) && + it->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + continue; + } + + funcType->AddCallSignature(it); + } + } + + if (found->TsType()->IsETSObjectType()) { + auto *functionalInterface = found->TsType()->AsETSObjectType(); + ASSERT(functionalInterface->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)); + funcType->AddCallSignature(functionalInterface->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures()[0]); + } + } + } + + if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) { + auto *found = GetOwnProperty(name); + if (found != nullptr) { + if (found->TsType()->IsETSFunctionType()) { + for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) { + if (((flags & PropertySearchFlags::INGORE_ABSTRACT) != 0) && + it->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + continue; + } + + funcType->AddCallSignature(it); + } + } + + if (found->TsType()->IsETSObjectType()) { + auto *functionalInterface = found->TsType()->AsETSObjectType(); + ASSERT(functionalInterface->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)); + funcType->AddCallSignature(functionalInterface->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures()[0]); + } + } + } + + if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) { + superType_->CollectSignaturesForSyntheticType(funcType, name, flags); + } +} + +std::vector ETSObjectType::GetAllProperties() const +{ + std::vector allProperties; + for (const auto &[_, prop] : InstanceFields()) { + (void)_; + allProperties.push_back(prop); + } + + for (const auto &[_, prop] : StaticFields()) { + (void)_; + allProperties.push_back(prop); + } + + for (const auto &[_, prop] : InstanceMethods()) { + (void)_; + allProperties.push_back(prop); + } + + for (const auto &[_, prop] : StaticMethods()) { + (void)_; + allProperties.push_back(prop); + } + + for (const auto &[_, prop] : InstanceDecls()) { + (void)_; + allProperties.push_back(prop); + } + + for (const auto &[_, prop] : StaticDecls()) { + (void)_; + allProperties.push_back(prop); + } + + return allProperties; +} + +std::vector ETSObjectType::Methods() const +{ + std::vector methods; + for (const auto &[_, prop] : InstanceMethods()) { + (void)_; + methods.push_back(prop); + } + + for (const auto &[_, prop] : StaticMethods()) { + (void)_; + methods.push_back(prop); + } + + return methods; +} + +std::vector ETSObjectType::Fields() const +{ + std::vector fields; + for (const auto &[_, prop] : InstanceFields()) { + (void)_; + fields.push_back(prop); + } + + for (const auto &[_, prop] : StaticFields()) { + (void)_; + fields.push_back(prop); + } + + return fields; +} + +std::vector ETSObjectType::ForeignProperties() const +{ + std::vector foreignProps; + std::unordered_set ownProps; + ownProps.reserve(properties_.size()); + + for (const auto *prop : GetAllProperties()) { + ownProps.insert(prop->Name()); + } + + auto allProps = CollectAllProperties(); + for (const auto &[name, var] : allProps) { + if (ownProps.find(name) == ownProps.end()) { + foreignProps.push_back(var); + } + } + + return foreignProps; +} + +std::unordered_map ETSObjectType::CollectAllProperties() const +{ + std::unordered_map propMap; + propMap.reserve(properties_.size()); + Iterate([&propMap](const binder::LocalVariable *var) { propMap.insert({var->Name(), var}); }); + + return propMap; +} + +void ETSObjectType::ToString(std::stringstream &ss) const +{ + ss << name_; +} + +void ETSObjectType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsETSObjectType() || !other->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + return; + } + + if (variable_ != other->Variable()) { + return; + } + + ETSObjectType *otherObj = other->AsETSObjectType(); + if (typeArguments_.empty() != otherObj->TypeArguments().empty()) { + return; + } + + if (!typeArguments_.empty()) { + ASSERT(typeArguments_.size() == otherObj->TypeArguments().size()); + for (size_t idx = 0; idx < typeArguments_.size(); idx++) { + typeArguments_[idx]->Identical(relation, otherObj->TypeArguments()[idx]); + if (!relation->IsTrue()) { + return; + } + } + } + + relation->Result(true); +} + +bool ETSObjectType::AssignmentSource([[maybe_unused]] TypeRelation *relation, Type *target) +{ + if (HasObjectFlag(ETSObjectFlags::ENUM)) { + relation->GetChecker()->ThrowTypeError("Can not assignable to Enum object.", this->GetDeclNode()->Start()); + } + + return target->IsETSNullType(); +} + +void ETSObjectType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsETSNullType()) { + relation->Result(true); + return; + } + + if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { + auto found = properties_[static_cast(PropertyType::INSTANCE_METHOD)].find("invoke"); + ASSERT(found != properties_[static_cast(PropertyType::INSTANCE_METHOD)].end()); + relation->IsAssignableTo(source, found->second->TsType()); + return; + } + + IsSubtype(relation, source); +} + +void ETSObjectType::IsSubtype(TypeRelation *relation, Type *source) +{ + if (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + return; + } + + ETSObjectType *sourceObj = source->AsETSObjectType(); + Type *sup = sourceObj->AsSuper(relation->GetChecker(), variable_); + if (sup == nullptr) { + return; + } + + relation->Result(true); +} + +Type *ETSObjectType::AsSuper(Checker *checker, binder::Variable *sourceVar) +{ + if (sourceVar == nullptr) { + return nullptr; + } + + if (variable_ == sourceVar) { + return this; + } + + if (!checker->TypeStack().insert(sourceVar).second) { + return nullptr; + } + + Type *superType = checker->AsETSChecker()->GetSuperType(this); + + if (superType == nullptr) { + return this; + } + + if (!superType->IsETSObjectType()) { + checker->TypeStack().erase(sourceVar); + return nullptr; + } + + ETSObjectType *superObj = superType->AsETSObjectType(); + + if (superObj->HasObjectFlag(ETSObjectFlags::CLASS)) { + Type *res = superObj->AsSuper(checker, sourceVar); + if (res != nullptr) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + + if (sourceVar->Declaration()->Node()->IsTSInterfaceDeclaration()) { + ArenaVector interfaces = checker->AsETSChecker()->GetInterfaces(this); + for (auto *it : interfaces) { + Type *res = it->AsSuper(checker, sourceVar); + if (res != nullptr) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + } + + checker->TypeStack().erase(sourceVar); + return nullptr; +} + +binder::LocalVariable *ETSObjectType::CopyProperty(binder::LocalVariable *prop, ArenaAllocator *allocator, + TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + auto *copiedProp = prop->Copy(allocator, prop->Declaration()); + auto *copiedPropType = ETSChecker::TryToInstantiate(relation->GetChecker()->AsETSChecker()->GetTypeOfVariable(prop), + allocator, relation, globalTypes); + copiedPropType->SetVariable(copiedProp); + copiedProp->SetTsType(copiedPropType); + return copiedProp; +} + +Type *ETSObjectType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + auto *checker = relation->GetChecker()->AsETSChecker(); + auto *copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_); + copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS | + ETSObjectFlags::UNCOMPLETE_INSTANTIATION); + + copiedType->SetVariable(variable_); + copiedType->SetSuperType(superType_); + + for (auto *it : interfaces_) { + copiedType->AddInterface(it); + } + + for (auto &[_, prop] : InstanceFields()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto &[_, prop] : StaticFields()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto &[_, prop] : InstanceMethods()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto &[_, prop] : StaticMethods()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto &[_, prop] : InstanceDecls()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto &[_, prop] : StaticDecls()) { + (void)_; + auto *copiedProp = CopyProperty(prop, allocator, relation, globalTypes); + copiedType->AddProperty(copiedProp); + } + + for (auto *it : constructSignatures_) { + copiedType->AddConstructSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsObjectType.h b/checker/types/ets/etsObjectType.h new file mode 100644 index 000000000..097b8f81e --- /dev/null +++ b/checker/types/ets/etsObjectType.h @@ -0,0 +1,410 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +enum class ETSObjectFlags : uint32_t { + NO_OPTS = 0U, + CLASS = 1U << 0U, + INTERFACE = 1U << 1U, + INSTANCE = 1U << 2U, + ABSTRACT = 1U << 3U, + GLOBAL = 1U << 4U, + ENUM = 1U << 5U, + FUNCTIONAL = 1U << 6U, + RESOLVED_MEMBERS = 1U << 7U, + RESOLVED_INTERFACES = 1U << 8U, + RESOLVED_SUPER = 1U << 9U, + RESOLVED_TYPE_PARAMS = 1U << 10U, + CHECKED_COMPATIBLE_ABSTRACTS = 1U << 11U, + NULL_TYPE = 1U << 12U, + STRING = 1U << 13U, + UNCOMPLETE_INSTANTIATION = 1U << 14U, + INNER = 1U << 15U, + + BUILTIN_STRING = 1U << 23U, + BUILTIN_BOOLEAN = 1U << 24U, + BUILTIN_BYTE = 1U << 25U, + BUILTIN_CHAR = 1U << 26U, + BUILTIN_SHORT = 1U << 27U, + BUILTIN_INT = 1U << 28U, + BUILTIN_LONG = 1U << 29U, + BUILTIN_FLOAT = 1U << 30U, + BUILTIN_DOUBLE = 1U << 31U, + + UNBOXABLE_TYPE = BUILTIN_BOOLEAN | BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG | + BUILTIN_FLOAT | BUILTIN_DOUBLE, + BUILTIN_TYPE = BUILTIN_STRING | UNBOXABLE_TYPE, + VALID_SWITCH_TYPE = + BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG | BUILTIN_STRING | ENUM, + GLOBAL_CLASS = CLASS | GLOBAL, + FUNCTIONAL_INTERFACE = INTERFACE | ABSTRACT | FUNCTIONAL, +}; + +DEFINE_BITOPS(ETSObjectFlags) + +enum class PropertySearchFlags : uint32_t { + NO_OPTS = 0, + SEARCH_INSTANCE_METHOD = 1U << 0U, + SEARCH_INSTANCE_FIELD = 1U << 1U, + SEARCH_INSTANCE_DECL = 1U << 2U, + SEARCH_STATIC_METHOD = 1U << 3U, + SEARCH_STATIC_FIELD = 1U << 4U, + SEARCH_STATIC_DECL = 1U << 5U, + + SEARCH_IN_BASE = 1U << 6U, + SEARCH_IN_INTERFACES = 1U << 7U, + INGORE_ABSTRACT = 1U << 8U, + ALLOW_FUNCTIONAL_INTERFACE = 1U << 9U, + DISALLOW_SYNTHETIC_METHOD_CREATION = 1U << 10U, + + SEARCH_METHOD = SEARCH_INSTANCE_METHOD | SEARCH_STATIC_METHOD, + SEARCH_FIELD = SEARCH_INSTANCE_FIELD | SEARCH_STATIC_FIELD, + SEARCH_DECL = SEARCH_INSTANCE_DECL | SEARCH_STATIC_DECL, + SEARCH_ALL = SEARCH_METHOD | SEARCH_FIELD | SEARCH_DECL, +}; + +DEFINE_BITOPS(PropertySearchFlags) + +enum class PropertyType { + INSTANCE_METHOD, + INSTANCE_FIELD, + INSTANCE_DECL, + STATIC_METHOD, + STATIC_FIELD, + STATIC_DECL, + COUNT, +}; + +class ETSObjectType : public Type { +public: + using PropertyMap = ArenaUnorderedMap; + using InstantiationMap = ArenaUnorderedMap; + using PropertyTraverser = std::function; + using PropertyHolder = std::array(PropertyType::COUNT)>; + + explicit ETSObjectType(ArenaAllocator *allocator) : ETSObjectType(allocator, ETSObjectFlags::NO_OPTS) {} + + explicit ETSObjectType(ArenaAllocator *allocator, ETSObjectFlags flags) + : ETSObjectType(allocator, "", "", nullptr, flags) + { + } + + explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + ir::AstNode *declNode, ETSObjectFlags flags) + : ETSObjectType(allocator, name, assemblerName, declNode, flags, + std::make_index_sequence(PropertyType::COUNT)> {}) + { + } + + void AddConstructSignature(Signature *signature) + { + constructSignatures_.push_back(signature); + } + + void AddConstructSignature(const ArenaVector &signatures) + { + constructSignatures_.insert(constructSignatures_.end(), signatures.begin(), signatures.end()); + } + + void AddInterface(ETSObjectType *interface) + { + interfaces_.push_back(interface); + } + + void SetSuperType(ETSObjectType *super) + { + superType_ = super; + } + + void SetTypeArguments(ArenaVector &&typeArgs) + { + typeArguments_ = std::move(typeArgs); + } + + void SetEnclosingType(ETSObjectType *enclosingType) + { + enclosingType_ = enclosingType; + } + + PropertyMap InstanceMethods() const + { + return properties_[static_cast(PropertyType::INSTANCE_METHOD)]; + } + + PropertyMap InstanceFields() const + { + return properties_[static_cast(PropertyType::INSTANCE_FIELD)]; + } + + PropertyMap InstanceDecls() const + { + return properties_[static_cast(PropertyType::INSTANCE_DECL)]; + } + + PropertyMap StaticMethods() const + { + return properties_[static_cast(PropertyType::STATIC_METHOD)]; + } + + PropertyMap StaticFields() const + { + return properties_[static_cast(PropertyType::STATIC_FIELD)]; + } + + PropertyMap StaticDecls() const + { + return properties_[static_cast(PropertyType::STATIC_DECL)]; + } + + const ArenaVector &TypeArguments() const + { + return typeArguments_; + } + + ArenaVector &TypeArguments() + { + return typeArguments_; + } + + const ArenaVector &ConstructSignatures() const + { + return constructSignatures_; + } + + ArenaVector &ConstructSignatures() + { + return constructSignatures_; + } + + const ArenaVector &Interfaces() const + { + return interfaces_; + } + + ArenaVector &Interfaces() + { + return interfaces_; + } + + ir::AstNode *GetDeclNode() const + { + return declNode_; + } + + const ETSObjectType *SuperType() const + { + return superType_; + } + + ETSObjectType *SuperType() + { + return superType_; + } + + const ETSObjectType *EnclosingType() const + { + return enclosingType_; + } + + ETSObjectType *EnclosingType() + { + return enclosingType_; + } + + ETSObjectType *OutermostClass() + { + auto *iter = enclosingType_; + + while (iter != nullptr && iter->EnclosingType() != nullptr) { + iter = iter->EnclosingType(); + } + + return iter; + } + + bool IsPropertyInherited(binder::Variable *var) + { + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + return GetProperty(var->Name(), PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL) == + var; + } + + return true; + } + + bool IsSignatureInherited(Signature *signature) + { + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return signature->Owner() == this; + } + + return true; + } + + const util::StringView &Name() const + { + return name_; + } + + const util::StringView &AssemblerName() const + { + return assemblerName_; + } + + void SetName(const util::StringView &newName) + { + name_ = newName; + } + + void SetAssemblerName(const util::StringView &newName) + { + assemblerName_ = newName; + } + + ETSObjectFlags ObjectFlags() const + { + return flags_; + } + + void AddObjectFlag(ETSObjectFlags flag) + { + flags_ |= flag; + } + + void RemoveObjectFlag(ETSObjectFlags flag) + { + flags_ &= ~flag; + } + + bool HasObjectFlag(ETSObjectFlags flag) const + { + return (flags_ & flag) != 0; + } + + ETSFunctionType *GetFunctionalInterfaceInvokeType() + { + ASSERT(HasObjectFlag(ETSObjectFlags::FUNCTIONAL)); + auto *invoke = GetOwnProperty("invoke"); + ASSERT(invoke && invoke->TsType() && invoke->TsType()->IsETSFunctionType()); + return invoke->TsType()->AsETSFunctionType(); + } + + ETSObjectFlags BuiltInKind() + { + return static_cast(flags_ & ETSObjectFlags::BUILTIN_TYPE); + } + + ETSObjectType *GetInstantiatedType(util::StringView hash) + { + auto found = instantiationMap_.find(hash); + + if (found != instantiationMap_.end()) { + return found->second; + } + + return nullptr; + } + + InstantiationMap &GetInstantiationMap() + { + return instantiationMap_; + } + + template + binder::LocalVariable *GetOwnProperty(const util::StringView &name) const + { + auto found = properties_[static_cast(type)].find(name); + if (found != properties_[static_cast(type)].end()) { + return found->second; + } + return nullptr; + } + + template + void AddProperty(binder::LocalVariable *prop) + { + properties_[static_cast(type)].emplace(prop->Name(), prop); + } + + std::vector ForeignProperties() const; + binder::LocalVariable *GetProperty(const util::StringView &name, PropertySearchFlags flags) const; + std::vector GetAllProperties() const; + void CreatePropertyMap(ArenaAllocator *allocator); + binder::LocalVariable *CopyProperty(binder::LocalVariable *prop, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes); + std::vector Methods() const; + std::vector Fields() const; + binder::LocalVariable *CreateSyntheticVarFromEverySignature(const util::StringView &name, + PropertySearchFlags flags) const; + void CollectSignaturesForSyntheticType(ETSFunctionType *funcType, const util::StringView &name, + PropertySearchFlags flags) const; + + void Iterate(const PropertyTraverser &cb) const; + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource(TypeRelation *relation, Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + void IsSubtype(TypeRelation *relation, Type *source) override; + Type *AsSuper(Checker *checker, binder::Variable *sourceVar) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << assemblerName_; + } + +private: + template + explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + ir::AstNode *declNode, ETSObjectFlags flags, [[maybe_unused]] std::index_sequence s) + : Type(TypeFlag::ETS_OBJECT), + allocator_(allocator), + name_(name), + assemblerName_(assemblerName), + declNode_(declNode), + constructSignatures_(allocator->Adapter()), + interfaces_(allocator->Adapter()), + flags_(flags), + instantiationMap_(allocator->Adapter()), + typeArguments_(allocator->Adapter()), + properties_ {(void(Is), PropertyMap {allocator->Adapter()})...} + { + } + + std::unordered_map CollectAllProperties() const; + + ArenaAllocator *allocator_; + util::StringView name_; + util::StringView assemblerName_; + ir::AstNode *declNode_; + ArenaVector constructSignatures_; + ArenaVector interfaces_; + ETSObjectFlags flags_; + InstantiationMap instantiationMap_; + ArenaVector typeArguments_; + PropertyHolder properties_; + ETSObjectType *superType_ {}; + ETSObjectType *enclosingType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/ets/etsStringType.cpp b/checker/types/ets/etsStringType.cpp new file mode 100644 index 000000000..847fdb887 --- /dev/null +++ b/checker/types/ets/etsStringType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsStringType.h" + +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" + +namespace panda::es2panda::checker { +void ETSStringType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSStringType()) { + relation->Result(true); + } +} + +void ETSStringType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (source->IsETSStringType()) { + relation->Result(true); + } +} + +Type *ETSStringType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsStringType.h b/checker/types/ets/etsStringType.h new file mode 100644 index 000000000..9c7917445 --- /dev/null +++ b/checker/types/ets/etsStringType.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_STRING_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class ETSStringType : public ETSObjectType { +public: + explicit ETSStringType(ArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) + : ETSObjectType(allocator, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER) + { + SetSuperType(super); + } + + explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, util::StringView value) + : ETSObjectType(allocator, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER), + value_(value) + { + SetSuperType(super); + AddTypeFlag(TypeFlag::CONSTANT); + variable_ = super->Variable(); + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "string"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::BUILTIN_STRING; + } + + util::StringView GetValue() const + { + return value_; + } + +private: + util::StringView value_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsTypeParameter.cpp b/checker/types/ets/etsTypeParameter.cpp new file mode 100644 index 000000000..4a98ab157 --- /dev/null +++ b/checker/types/ets/etsTypeParameter.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsTypeParameter.h" + +namespace panda::es2panda::checker { +void ETSTypeParameter::ToString([[maybe_unused]] std::stringstream &ss) const +{ + UNREACHABLE(); +} + +void ETSTypeParameter::Identical([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) +{ + UNREACHABLE(); +} + +void ETSTypeParameter::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + UNREACHABLE(); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsTypeParameter.h b/checker/types/ets/etsTypeParameter.h new file mode 100644 index 000000000..a085f1be0 --- /dev/null +++ b/checker/types/ets/etsTypeParameter.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_PARAMETER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_PARAMETER_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSTypeParameter : public Type { +public: + explicit ETSTypeParameter() : Type(TypeFlag::ETS_TYPE_PARAMETER) {} + explicit ETSTypeParameter(Type *assemblerType) : Type(TypeFlag::ETS_TYPE_PARAMETER), assemblerType_(assemblerType) + { + } + + void SetType(Type *type) + { + type_ = type; + } + + Type *GetType() + { + return type_; + } + + Type *GetAssemblerType() + { + return assemblerType_; + } + + Type **GetTypeRef() + { + return &type_; + } + + Type **GetAssemblerTypeRef() + { + return &assemblerType_; + } + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + +private: + Type *type_ {}; + Type *assemblerType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsTypeReference.cpp b/checker/types/ets/etsTypeReference.cpp new file mode 100644 index 000000000..55f8f7327 --- /dev/null +++ b/checker/types/ets/etsTypeReference.cpp @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsTypeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +util::StringView ETSTypeReference::ReferencedName() const +{ + return varRef_->Name(); +} + +void ETSTypeReference::ToString(std::stringstream &ss) const +{ + ss << ReferencedName(); +} + +void ETSTypeReference::ToAssemblerType(std::stringstream &ss) const +{ + ASSERT(*assemblerRef_); + (*assemblerRef_)->ToAssemblerTypeWithRank(ss); +} + +void ETSTypeReference::Identical(TypeRelation *relation, Type *other) +{ + if ((*ref_) != nullptr) { + (*ref_)->Identical(relation, other); + return; + } + + if (!other->IsETSTypeReference()) { + return; + } + + relation->Result(varRef_ == other->AsETSTypeReference()->VarRef()); +} + +void ETSTypeReference::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if ((*ref_) != nullptr) { + (*ref_)->AssignmentTarget(relation, source); + } +} + +bool ETSTypeReference::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if ((*ref_) == nullptr) { + return false; + } + + if (!target->IsETSTypeReference()) { + return true; + } + + if (!relation->IsAssignableTo(this, target)) { + return true; + } + + relation->Result(true); + return false; +} + +Type *ETSTypeReference::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + if ((*ref_) != nullptr) { + return relation->GetChecker()->AsETSChecker()->TryToInstantiate(*ref_, allocator, relation, globalTypes); + } + + return relation->GetChecker()->AsETSChecker()->CreateTypeReference(ref_, assemblerRef_, varRef_); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsTypeReference.h b/checker/types/ets/etsTypeReference.h new file mode 100644 index 000000000..90c0764d4 --- /dev/null +++ b/checker/types/ets/etsTypeReference.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_REFERENCE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::binder { +class LocalVariable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class ETSTypeReference : public Type { +public: + explicit ETSTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *varRef) + : Type(TypeFlag::ETS_TYPE_REFERENCE), ref_(ref), assemblerRef_(assemblerRef), varRef_(varRef) + { + } + + Type *Ref() + { + return *ref_; + } + + const Type *Ref() const + { + return *ref_; + } + + binder::LocalVariable *VarRef() + { + return varRef_; + } + + const binder::LocalVariable *VarRef() const + { + return varRef_; + } + + util::StringView ReferencedName() const; + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type **ref_; + Type **assemblerRef_; + binder::LocalVariable *varRef_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/checker/types/ets/etsVoidType.cpp b/checker/types/ets/etsVoidType.cpp new file mode 100644 index 000000000..3a7dd3bb1 --- /dev/null +++ b/checker/types/ets/etsVoidType.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "etsVoidType.h" + +namespace panda::es2panda::checker { +void ETSVoidType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSVoidType()) { + relation->Result(true); + } +} + +void ETSVoidType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *ETSVoidType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/lexer/templates/keywordsMap.h.erb b/checker/types/ets/etsVoidType.h similarity index 42% rename from lexer/templates/keywordsMap.h.erb rename to checker/types/ets/etsVoidType.h index 46d4cc8bb..7ebd9a25c 100644 --- a/lexer/templates/keywordsMap.h.erb +++ b/checker/types/ets/etsVoidType.h @@ -13,37 +13,32 @@ * limitations under the License. */ -// Autogenerated file -- DO NOT EDIT! +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_VOID_TYPE_H -#include "plugins/ecmascript/es2panda/lexer/keywordString.h" -#include "utils/span.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -namespace panda::es2panda::lexer { -class KeywordsMap { +namespace panda::es2panda::checker { +class ETSVoidType : public Type { public: - KeywordsMap() = delete; - - static Span Map(char32_t cp) { - switch(cp) { -% keywords.each do |group| - case LEX_CHAR_LOWERCASE_<%= group.keys[0][0].upcase %>: { - return Span(KEYWORDS_<%= group.keys[0][0].upcase %>); - } -% end - default: { - return Span(); - } - } + ETSVoidType() : Type(TypeFlag::ETS_VOID) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "void"; } -% keywords.each do |group| + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_VOID; + } - static constexpr std::array> KEYWORDS_<%= group.keys[0][0].upcase %> = {{ -% group.each do |key, kw| - {"<%= key%>", <%= kw[0] %>, <%= kw[1] %>}, -% end - }}; -% end +private: }; +} // namespace panda::es2panda::checker -} // namespace panda::es2panda::lexer +#endif diff --git a/checker/types/ets/floatType.cpp b/checker/types/ets/floatType.cpp new file mode 100644 index 000000000..fbebd8d18 --- /dev/null +++ b/checker/types/ets/floatType.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "floatType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void FloatType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsFloatType()) { + relation->Result(true); + } +} + +void FloatType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool FloatType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx( + relation, checker::TypeRelationFlag::ONLY_CHECK_WIDENING | checker::TypeRelationFlag::NARROWING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *FloatType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/floatType.h b/checker/types/ets/floatType.h new file mode 100644 index 000000000..642b8d7d3 --- /dev/null +++ b/checker/types/ets/floatType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FLOAT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FLOAT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class FloatType : public Type { +public: + using UType = float; + + FloatType() : Type(TypeFlag::FLOAT) {} + explicit FloatType(UType value) : Type(TypeFlag::FLOAT | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "float"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_FLOAT; + } + +private: + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/intType.cpp b/checker/types/ets/intType.cpp new file mode 100644 index 000000000..bc50dcdf8 --- /dev/null +++ b/checker/types/ets/intType.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "intType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void IntType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsIntType()) { + relation->Result(true); + } +} + +void IntType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool IntType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx( + relation, checker::TypeRelationFlag::ONLY_CHECK_WIDENING | checker::TypeRelationFlag::NARROWING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *IntType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/intType.h b/checker/types/ets/intType.h new file mode 100644 index 000000000..00916e43d --- /dev/null +++ b/checker/types/ets/intType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_INT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_INT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class IntType : public Type { +public: + using UType = int32_t; + + IntType() : Type(TypeFlag::INT) {} + explicit IntType(UType value) : Type(TypeFlag::INT | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "int"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_INT; + } + +private: + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/longType.cpp b/checker/types/ets/longType.cpp new file mode 100644 index 000000000..fbe9345ad --- /dev/null +++ b/checker/types/ets/longType.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "longType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void LongType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsLongType()) { + relation->Result(true); + } +} + +void LongType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool LongType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx( + relation, checker::TypeRelationFlag::ONLY_CHECK_WIDENING | checker::TypeRelationFlag::NARROWING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *LongType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/longType.h b/checker/types/ets/longType.h new file mode 100644 index 000000000..af9f0f504 --- /dev/null +++ b/checker/types/ets/longType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_LONG_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_LONG_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class LongType : public Type { +public: + using UType = int64_t; + + LongType() : Type(TypeFlag::LONG) {} + explicit LongType(UType value) : Type(TypeFlag::LONG | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "long"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_LONG; + } + +private: + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/shortType.cpp b/checker/types/ets/shortType.cpp new file mode 100644 index 000000000..5c5431c58 --- /dev/null +++ b/checker/types/ets/shortType.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "shortType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +void ShortType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsShortType()) { + relation->Result(true); + } +} + +void ShortType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (relation->ApplyUnboxing()) { + UnboxingConverter(relation->GetChecker()->AsETSChecker(), relation, source, this); + } + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +bool ShortType::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (relation->InAssignmentContext()) { + checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx( + relation, checker::TypeRelationFlag::ONLY_CHECK_WIDENING | checker::TypeRelationFlag::NARROWING); + auto unboxedType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target); + if (unboxedType != nullptr) { + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, unboxedType, this); + } + } + + if (relation->ApplyBoxing()) { + BoxingConverter(relation->GetChecker()->AsETSChecker(), relation, this, target); + } + + return relation->IsTrue(); +} + +Type *ShortType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/shortType.h b/checker/types/ets/shortType.h new file mode 100644 index 000000000..ea685bd67 --- /dev/null +++ b/checker/types/ets/shortType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_SHORT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_SHORT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ShortType : public Type { +public: + using UType = int16_t; + + ShortType() : Type(TypeFlag::SHORT) {} + explicit ShortType(UType value) : Type(TypeFlag::SHORT | TypeFlag::CONSTANT), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "short"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_SHORT; + } + +private: + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/types.h b/checker/types/ets/types.h new file mode 100644 index 000000000..5cad297ba --- /dev/null +++ b/checker/types/ets/types.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_H + +#include "byteType.h" +#include "charType.h" +#include "doubleType.h" +#include "floatType.h" +#include "intType.h" +#include "longType.h" +#include "shortType.h" +#include "etsBooleanType.h" +#include "etsFunctionType.h" +#include "etsVoidType.h" +#include "etsStringType.h" +#include "etsObjectType.h" +#include "etsArrayType.h" +#include "wildcardType.h" +#include "etsTypeReference.h" +#include "etsTypeParameter.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#endif /* TYPES_H */ diff --git a/checker/types/ets/wildcardType.cpp b/checker/types/ets/wildcardType.cpp new file mode 100644 index 000000000..ca8c974c8 --- /dev/null +++ b/checker/types/ets/wildcardType.cpp @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wildcardType.h" + +namespace panda::es2panda::checker { +void WildcardType::ToString(std::stringstream &ss) const +{ + ss << "wildcard"; +} + +void WildcardType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsWildcardType()) { + relation->Result(true); + } +} + +void WildcardType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *WildcardType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/wildcardType.h b/checker/types/ets/wildcardType.h new file mode 100644 index 000000000..a0b3df5a4 --- /dev/null +++ b/checker/types/ets/wildcardType.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_WILDCARD_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_WILDCARD_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class WildcardType : public Type { +public: + WildcardType() : Type(TypeFlag::WILDCARD) {} + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << "wildcard"; + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/types/globalTypesHolder.cpp b/checker/types/globalTypesHolder.cpp similarity index 32% rename from typescript/types/globalTypesHolder.cpp rename to checker/types/globalTypesHolder.cpp index 0b0a4e0db..ea93ab12e 100644 --- a/typescript/types/globalTypesHolder.cpp +++ b/checker/types/globalTypesHolder.cpp @@ -15,28 +15,41 @@ #include "globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberType.h" -#include "plugins/ecmascript/es2panda/typescript/types/anyType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanType.h" -#include "plugins/ecmascript/es2panda/typescript/types/voidType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nullType.h" -#include "plugins/ecmascript/es2panda/typescript/types/undefinedType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unknownType.h" -#include "plugins/ecmascript/es2panda/typescript/types/neverType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nonPrimitiveType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/anyType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/voidType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nullType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/undefinedType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unknownType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/neverType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nonPrimitiveType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/tupleType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/byteType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/charType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/doubleType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/floatType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/intType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/longType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/shortType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsBooleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsStringType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsVoidType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/wildcardType.h" namespace panda::es2panda::checker { -GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) +GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) : builtinNameMappings_(allocator->Adapter()) { + // TS specific types globalTypes_[static_cast(GlobalTypeId::NUMBER)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ANY)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::STRING)] = allocator->New(); @@ -65,6 +78,58 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) globalTypes_[static_cast(GlobalTypeId::EMPTY_OBJECT)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::RESOLVING_RETURN_TYPE)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ERROR_TYPE)] = allocator->New(); + + // ETS specific types + globalTypes_[static_cast(GlobalTypeId::BYTE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::SHORT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::INT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::LONG)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::FLOAT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::DOUBLE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::CHAR)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_BOOLEAN)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_VOID)] = allocator->New(); + auto *globalNullType = allocator->New(allocator); + globalNullType->AsETSObjectType()->AddObjectFlag(ETSObjectFlags::NULL_TYPE); + globalTypes_[static_cast(GlobalTypeId::ETS_NULL)] = globalNullType; + globalTypes_[static_cast(GlobalTypeId::ETS_WILDCARD)] = allocator->New(); + + builtinNameMappings_.emplace("Boolean", GlobalTypeId::ETS_BOOLEAN_BUILTIN); + builtinNameMappings_.emplace("Byte", GlobalTypeId::ETS_BYTE_BUILTIN); + builtinNameMappings_.emplace("Char", GlobalTypeId::ETS_CHAR_BUILTIN); + builtinNameMappings_.emplace("Comparable", GlobalTypeId::ETS_COMPARABLE_BUILTIN); + builtinNameMappings_.emplace("Console", GlobalTypeId::ETS_CONSOLE_BUILTIN); + builtinNameMappings_.emplace("Date", GlobalTypeId::ETS_DATE_BUILTIN); + builtinNameMappings_.emplace("Double", GlobalTypeId::ETS_DOUBLE_BUILTIN); + builtinNameMappings_.emplace("Exception", GlobalTypeId::ETS_EXCEPTION_BUILTIN); + builtinNameMappings_.emplace("Float", GlobalTypeId::ETS_FLOAT_BUILTIN); + builtinNameMappings_.emplace("Floating", GlobalTypeId::ETS_FLOATING_BUILTIN); + builtinNameMappings_.emplace("Int", GlobalTypeId::ETS_INTEGER_BUILTIN); + builtinNameMappings_.emplace("Integral", GlobalTypeId::ETS_INTEGRAL_BUILTIN); + builtinNameMappings_.emplace("Long", GlobalTypeId::ETS_LONG_BUILTIN); + builtinNameMappings_.emplace("Map", GlobalTypeId::ETS_MAP_BUILTIN); + builtinNameMappings_.emplace("Object", GlobalTypeId::ETS_OBJECT_BUILTIN); + builtinNameMappings_.emplace("Panic", GlobalTypeId::ETS_PANIC_BUILTIN); + builtinNameMappings_.emplace("Runtime", GlobalTypeId::ETS_RUNTIME_BUILTIN); + builtinNameMappings_.emplace("Set", GlobalTypeId::ETS_SET_BUILTIN); + builtinNameMappings_.emplace("Short", GlobalTypeId::ETS_SHORT_BUILTIN); + builtinNameMappings_.emplace("StackTraceElement", GlobalTypeId::ETS_STACK_TRACE_ELEMENT_BUILTIN); + builtinNameMappings_.emplace("StackTrace", GlobalTypeId::ETS_STACK_TRACE_BUILTIN); + builtinNameMappings_.emplace("NullPointerException", GlobalTypeId::ETS_NULL_POINTER_EXCEPTION_BUILTIN); + builtinNameMappings_.emplace("ArrayIndexOutOfBoundsException", + GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN); + builtinNameMappings_.emplace("ArithmeticException", GlobalTypeId::ETS_ARITHMETIC_EXCEPTION_BUILTIN); + builtinNameMappings_.emplace("ClassNotFoundException", GlobalTypeId::ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN); + builtinNameMappings_.emplace("OutOfMemoryError", GlobalTypeId::ETS_OUT_OF_MEMORY_ERROR_BUILTIN); + builtinNameMappings_.emplace("NoSuchMethodError", GlobalTypeId::ETS_NO_SUCH_METHOD_ERROR_BUILTIN); + builtinNameMappings_.emplace("AssertionPanic", GlobalTypeId::ETS_ASSERTION_PANIC_BUILTIN); + builtinNameMappings_.emplace("DivideByZeroPanic", GlobalTypeId::ETS_DIVIDE_BY_ZERO_PANIC_BUILTIN); + builtinNameMappings_.emplace("NullPointerPanic", GlobalTypeId::ETS_NULL_POINTER_PANIC_BUILTIN); + builtinNameMappings_.emplace("UncatchedExceptionPanic", GlobalTypeId::ETS_UNCATCHED_EXCEPTION_PANIC_BUILTIN); + builtinNameMappings_.emplace("String", GlobalTypeId::ETS_STRING_BUILTIN); + builtinNameMappings_.emplace("StringBuilder", GlobalTypeId::ETS_STRING_BUILDER_BUILTIN); + builtinNameMappings_.emplace("Type", GlobalTypeId::ETS_TYPE_BUILTIN); + builtinNameMappings_.emplace("Types", GlobalTypeId::ETS_TYPES_BUILTIN); } Type *GlobalTypesHolder::GlobalNumberType() @@ -181,4 +246,245 @@ Type *GlobalTypesHolder::GlobalErrorType() { return globalTypes_.at(static_cast(GlobalTypeId::ERROR_TYPE)); } + +Type *GlobalTypesHolder::GlobalByteType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::BYTE)); +} + +Type *GlobalTypesHolder::GlobalShortType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::SHORT)); +} + +Type *GlobalTypesHolder::GlobalIntType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::INT)); +} + +Type *GlobalTypesHolder::GlobalLongType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::LONG)); +} + +Type *GlobalTypesHolder::GlobalFloatType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::FLOAT)); +} + +Type *GlobalTypesHolder::GlobalDoubleType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::DOUBLE)); +} + +Type *GlobalTypesHolder::GlobalCharType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::CHAR)); +} + +Type *GlobalTypesHolder::GlobalETSBooleanType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BOOLEAN)); +} + +Type *GlobalTypesHolder::GlobalETSStringLiteralType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING)); +} + +Type *GlobalTypesHolder::GlobalETSVoidType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_VOID)); +} + +Type *GlobalTypesHolder::GlobalETSObjectType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_OBJECT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalETSNullType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULL)); +} + +Type *GlobalTypesHolder::GlobalWildcardType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_WILDCARD)); +} + +Type *GlobalTypesHolder::GlobalETSBooleanBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BOOLEAN_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalByteBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BYTE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalCharBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_CHAR_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalComparableBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_COMPARABLE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalConsoleBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_CONSOLE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalDoubleBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_DOUBLE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalExceptionBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_EXCEPTION_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalFloatBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_FLOAT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalFloatingBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_FLOATING_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalIntegerBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_INTEGER_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalIntegralBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_INTEGRAL_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalLongBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_LONG_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalMapBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_MAP_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalPanicBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_PANIC_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalRuntimeBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_RUNTIME_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalSetBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_SET_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalShortBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_SHORT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalStackTraceElementBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STACK_TRACE_ELEMENT_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalStackTraceBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STACK_TRACE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalNullPointerExceptionBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULL_POINTER_EXCEPTION_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalArrayIndexOutOfBoundsExceptionBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalArithmeticExceptionBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_ARITHMETIC_EXCEPTION_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalClassNotFoundExceptionBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalClassOutOfMemoryErrorBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_OUT_OF_MEMORY_ERROR_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalNoSuchMethodErrorBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_NO_SUCH_METHOD_ERROR_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalAssertionPanicBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_ASSERTION_PANIC_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalDivideByZeroPanicBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_DIVIDE_BY_ZERO_PANIC_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalNullPointerPanicBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULL_POINTER_PANIC_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalUncatchedExceptionPanicBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_UNCATCHED_EXCEPTION_PANIC_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalETSStringBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalStringBuilderBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING_BUILDER_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalTypeBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_TYPE_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalTypesBuiltinType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_TYPES_BUILTIN)); +} + +void GlobalTypesHolder::InitializeBuiltin(const util::StringView name, Type *type) +{ + const auto typeId = builtinNameMappings_.find(name); + if (typeId == builtinNameMappings_.end()) { + std::cerr << "WARNING: Did not find '" << name << "' builtin in GlobalTypeHolder, it should be added." + << std::endl; + return; + } + globalTypes_.at(static_cast(typeId->second)) = type; +} } // namespace panda::es2panda::checker diff --git a/typescript/types/globalTypesHolder.h b/checker/types/globalTypesHolder.h similarity index 35% rename from typescript/types/globalTypesHolder.h rename to checker/types/globalTypesHolder.h index 6981d5da7..5cd1d3a89 100644 --- a/typescript/types/globalTypesHolder.h +++ b/checker/types/globalTypesHolder.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { enum class GlobalTypeId { @@ -43,7 +43,54 @@ enum class GlobalTypeId { EMPTY_OBJECT, RESOLVING_RETURN_TYPE, ERROR_TYPE, - COUNT + BYTE, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE, + CHAR, + ETS_BOOLEAN, + ETS_STRING, + ETS_VOID, + ETS_OBJECT_BUILTIN, + ETS_NULL, + ETS_WILDCARD, + ETS_BOOLEAN_BUILTIN, + ETS_BYTE_BUILTIN, + ETS_CHAR_BUILTIN, + ETS_COMPARABLE_BUILTIN, + ETS_CONSOLE_BUILTIN, + ETS_DATE_BUILTIN, + ETS_DOUBLE_BUILTIN, + ETS_EXCEPTION_BUILTIN, + ETS_FLOAT_BUILTIN, + ETS_FLOATING_BUILTIN, + ETS_INTEGER_BUILTIN, + ETS_INTEGRAL_BUILTIN, + ETS_LONG_BUILTIN, + ETS_MAP_BUILTIN, + ETS_PANIC_BUILTIN, + ETS_RUNTIME_BUILTIN, + ETS_SET_BUILTIN, + ETS_SHORT_BUILTIN, + ETS_STACK_TRACE_ELEMENT_BUILTIN, + ETS_STACK_TRACE_BUILTIN, + ETS_NULL_POINTER_EXCEPTION_BUILTIN, + ETS_ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION_BUILTIN, + ETS_ARITHMETIC_EXCEPTION_BUILTIN, + ETS_CLASS_NOT_FOUND_EXCEPTION_BUILTIN, + ETS_OUT_OF_MEMORY_ERROR_BUILTIN, + ETS_NO_SUCH_METHOD_ERROR_BUILTIN, + ETS_ASSERTION_PANIC_BUILTIN, + ETS_DIVIDE_BY_ZERO_PANIC_BUILTIN, + ETS_NULL_POINTER_PANIC_BUILTIN, + ETS_UNCATCHED_EXCEPTION_PANIC_BUILTIN, + ETS_STRING_BUILTIN, + ETS_STRING_BUILDER_BUILTIN, + ETS_TYPE_BUILTIN, + ETS_TYPES_BUILTIN, + COUNT, }; class GlobalTypesHolder { @@ -53,6 +100,7 @@ public: NO_COPY_SEMANTIC(GlobalTypesHolder); NO_MOVE_SEMANTIC(GlobalTypesHolder); + // TS specific types Type *GlobalNumberType(); Type *GlobalAnyType(); Type *GlobalStringType(); @@ -77,9 +125,72 @@ public: Type *GlobalResolvingReturnType(); Type *GlobalErrorType(); + // ETS specific types + Type *GlobalByteType(); + Type *GlobalShortType(); + Type *GlobalIntType(); + Type *GlobalLongType(); + Type *GlobalFloatType(); + Type *GlobalDoubleType(); + Type *GlobalCharType(); + Type *GlobalETSBooleanType(); + Type *GlobalETSStringLiteralType(); + Type *GlobalETSVoidType(); + Type *GlobalETSObjectType(); + Type *GlobalETSNullType(); + Type *GlobalWildcardType(); + Type *GlobalETSBooleanBuiltinType(); + Type *GlobalByteBuiltinType(); + Type *GlobalCharBuiltinType(); + Type *GlobalComparableBuiltinType(); + Type *GlobalConsoleBuiltinType(); + Type *GlobalDoubleBuiltinType(); + Type *GlobalExceptionBuiltinType(); + Type *GlobalFloatBuiltinType(); + Type *GlobalFloatingBuiltinType(); + Type *GlobalIntegerBuiltinType(); + Type *GlobalIntegralBuiltinType(); + Type *GlobalLongBuiltinType(); + Type *GlobalMapBuiltinType(); + Type *GlobalPanicBuiltinType(); + Type *GlobalRuntimeBuiltinType(); + Type *GlobalSetBuiltinType(); + Type *GlobalShortBuiltinType(); + Type *GlobalStackTraceElementBuiltinType(); + Type *GlobalStackTraceBuiltinType(); + Type *GlobalNullPointerExceptionBuiltinType(); + Type *GlobalArrayIndexOutOfBoundsExceptionBuiltinType(); + Type *GlobalArithmeticExceptionBuiltinType(); + Type *GlobalClassNotFoundExceptionBuiltinType(); + Type *GlobalClassOutOfMemoryErrorBuiltinType(); + Type *GlobalNoSuchMethodErrorBuiltinType(); + Type *GlobalAssertionPanicBuiltinType(); + Type *GlobalDivideByZeroPanicBuiltinType(); + Type *GlobalNullPointerPanicBuiltinType(); + Type *GlobalUncatchedExceptionPanicBuiltinType(); + Type *GlobalETSStringBuiltinType(); + Type *GlobalStringBuilderBuiltinType(); + Type *GlobalTypeBuiltinType(); + Type *GlobalTypesBuiltinType(); + + void InitializeBuiltin(util::StringView name, Type *type); + + using Holder = std::array(GlobalTypeId::COUNT)>; + + Holder &GlobalTypes() + { + return globalTypes_; + } + + const Holder &GlobalTypes() const + { + return globalTypes_; + } + private: - std::array(GlobalTypeId::COUNT)> globalTypes_ {}; + Holder globalTypes_ {}; + ArenaMap builtinNameMappings_; }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_GLOBAL_TYPES_HOLDER_H */ diff --git a/typescript/types/signature.cpp b/checker/types/signature.cpp similarity index 81% rename from typescript/types/signature.cpp rename to checker/types/signature.cpp index 80140201d..a9aa5785d 100644 --- a/typescript/types/signature.cpp +++ b/checker/types/signature.cpp @@ -15,18 +15,29 @@ #include "signature.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + namespace panda::es2panda::checker { + +util::StringView Signature::InternalName() const +{ + return internalName_.Empty() ? func_->Scope()->InternalName() : internalName_; +} + Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { - checker::SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); + SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); - for (auto *it : copiedInfo->params) { - it->SetTsType(it->TsType()->Instantiate(allocator, relation, globalTypes)); + for (size_t idx = 0; idx < signatureInfo_->params.size(); idx++) { + copiedInfo->params[idx]->SetTsType( + ETSChecker::TryToInstantiate(signatureInfo_->params[idx]->TsType(), allocator, relation, globalTypes)); } - Type *copiedReturnType = returnType_->Instantiate(allocator, relation, globalTypes); + Type *copiedReturnType = ETSChecker::TryToInstantiate(returnType_, allocator, relation, globalTypes); - return allocator->New(copiedInfo, copiedReturnType); + return allocator->New(copiedInfo, copiedReturnType, func_); } void Signature::ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod) const @@ -80,7 +91,11 @@ void Signature::Identical(TypeRelation *relation, Signature *other) return; } - relation->IsIdenticalTo(returnType_, other->ReturnType()); + if (relation->NoReturnTypeCheck()) { + relation->Result(true); + } else { + relation->IsIdenticalTo(returnType_, other->ReturnType()); + } if (relation->IsTrue()) { for (uint64_t i = 0; i < signatureInfo_->params.size(); i++) { diff --git a/typescript/types/signature.h b/checker/types/signature.h similarity index 57% rename from typescript/types/signature.h rename to checker/types/signature.h index ea843d456..eec7c2f55 100644 --- a/typescript/types/signature.h +++ b/checker/types/signature.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H #include "type.h" @@ -49,12 +49,41 @@ public: // NOLINTEND(misc-non-private-member-variables-in-classes) }; +enum class SignatureFlags : uint32_t { + NO_OPTS = 0U, + VIRTUAL = 1U << 0U, + ABSTRACT = 1U << 1U, + CALL = 1U << 2U, + CONSTRUCT = 1U << 3U, + PUBLIC = 1U << 4U, + PROTECTED = 1U << 5U, + PRIVATE = 1U << 6U, + STATIC = 1U << 7U, + OPEN = 1U << 8U, + CONSTRUCTOR = 1U << 9U, + TYPE = 1U << 10U, + + FUNCTIONAL_INTERFACE_SIGNATURE = VIRTUAL | ABSTRACT | CALL | PUBLIC | TYPE, +}; + +DEFINE_BITOPS(SignatureFlags) + class Signature { public: Signature(SignatureInfo *signature_info, Type *returnType) : signatureInfo_(signature_info), returnType_(returnType) { } + Signature(SignatureInfo *signature_info, Type *returnType, util::StringView internalName) + : signatureInfo_(signature_info), returnType_(returnType), internalName_(internalName) + { + } + + Signature(SignatureInfo *signature_info, Type *returnType, ir::ScriptFunction *func) + : signatureInfo_(signature_info), returnType_(returnType), func_(func) + { + } + ~Signature() = default; NO_COPY_SEMANTIC(Signature); NO_MOVE_SEMANTIC(Signature); @@ -94,14 +123,24 @@ public: returnType_ = type; } - void SetNode(const ir::AstNode *node) + void SetOwner(ETSObjectType *owner) { - node_ = node; + ownerObj_ = owner; } - const ir::AstNode *Node() const + ir::ScriptFunction *Function() { - return node_; + return func_; + } + + ETSObjectType *Owner() + { + return ownerObj_; + } + + const ir::ScriptFunction *Function() const + { + return func_; } const binder::LocalVariable *RestVar() const @@ -109,6 +148,49 @@ public: return signatureInfo_->restVar; } + uint8_t ProtectionFlag() const + { + if ((flags_ & SignatureFlags::PRIVATE) != 0) { + return 2; + } + + if ((flags_ & SignatureFlags::PROTECTED) != 0) { + return 1; + } + + return 0; + } + + void AddSignatureFlag(SignatureFlags flag) + { + flags_ |= flag; + } + + void RemoveSignatureFlag(SignatureFlags flag) + { + flags_ &= ~flag; + } + + bool HasSignatureFlag(SignatureFlags flag) const + { + return (flags_ & flag) != 0; + } + + void ToAssemblerType(std::stringstream &ss) const + { + ss << compiler::Signatures::MANGLE_BEGIN; + + for (const auto *param : signatureInfo_->params) { + param->TsType()->ToAssemblerTypeWithRank(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + returnType_->ToAssemblerTypeWithRank(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + util::StringView InternalName() const; + Signature *Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); void ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod = false) const; @@ -118,7 +200,10 @@ public: private: checker::SignatureInfo *signatureInfo_; Type *returnType_; - const ir::AstNode *node_ {}; + ir::ScriptFunction *func_ {}; + SignatureFlags flags_ {SignatureFlags::NO_OPTS}; + util::StringView internalName_ {}; + ETSObjectType *ownerObj_ {}; }; } // namespace panda::es2panda::checker diff --git a/typescript/types/anyType.cpp b/checker/types/ts/anyType.cpp similarity index 100% rename from typescript/types/anyType.cpp rename to checker/types/ts/anyType.cpp diff --git a/typescript/types/anyType.h b/checker/types/ts/anyType.h similarity index 87% rename from typescript/types/anyType.h rename to checker/types/ts/anyType.h index 8105bebf3..76c38e62e 100644 --- a/typescript/types/anyType.h +++ b/checker/types/ts/anyType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class AnyType : public Type { @@ -32,4 +32,4 @@ public: }; } // namespace panda::es2panda::checker -#endif /* TYPESCRIPT_TYPES_ANY_TYPE_H */ +#endif diff --git a/typescript/types/arrayType.cpp b/checker/types/ts/arrayType.cpp similarity index 96% rename from typescript/types/arrayType.cpp rename to checker/types/ts/arrayType.cpp index 78d105513..90deba9dc 100644 --- a/typescript/types/arrayType.cpp +++ b/checker/types/ts/arrayType.cpp @@ -16,7 +16,7 @@ #include "arrayType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { void ArrayType::ToString(std::stringstream &ss) const diff --git a/typescript/types/arrayType.h b/checker/types/ts/arrayType.h similarity index 89% rename from typescript/types/arrayType.h rename to checker/types/ts/arrayType.h index 4e28e70f8..27e61711a 100644 --- a/typescript/types/arrayType.h +++ b/checker/types/ts/arrayType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class ArrayType : public Type { diff --git a/typescript/types/bigintLiteralType.cpp b/checker/types/ts/bigintLiteralType.cpp similarity index 100% rename from typescript/types/bigintLiteralType.cpp rename to checker/types/ts/bigintLiteralType.cpp diff --git a/typescript/types/bigintLiteralType.h b/checker/types/ts/bigintLiteralType.h similarity index 89% rename from typescript/types/bigintLiteralType.h rename to checker/types/ts/bigintLiteralType.h index aef7b39c9..f0fd4b1f5 100644 --- a/typescript/types/bigintLiteralType.h +++ b/checker/types/ts/bigintLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintLiteralType : public Type { diff --git a/typescript/types/bigintType.cpp b/checker/types/ts/bigintType.cpp similarity index 100% rename from typescript/types/bigintType.cpp rename to checker/types/ts/bigintType.cpp diff --git a/typescript/types/bigintType.h b/checker/types/ts/bigintType.h similarity index 87% rename from typescript/types/bigintType.h rename to checker/types/ts/bigintType.h index d3022f3cc..07636b22d 100644 --- a/typescript/types/bigintType.h +++ b/checker/types/ts/bigintType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintType : public Type { diff --git a/typescript/types/booleanLiteralType.cpp b/checker/types/ts/booleanLiteralType.cpp similarity index 100% rename from typescript/types/booleanLiteralType.cpp rename to checker/types/ts/booleanLiteralType.cpp diff --git a/typescript/types/booleanLiteralType.h b/checker/types/ts/booleanLiteralType.h similarity index 88% rename from typescript/types/booleanLiteralType.h rename to checker/types/ts/booleanLiteralType.h index 8f7b46c3b..f10bfc2dd 100644 --- a/typescript/types/booleanLiteralType.h +++ b/checker/types/ts/booleanLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanLiteralType : public Type { diff --git a/typescript/types/booleanType.cpp b/checker/types/ts/booleanType.cpp similarity index 100% rename from typescript/types/booleanType.cpp rename to checker/types/ts/booleanType.cpp diff --git a/typescript/types/booleanType.h b/checker/types/ts/booleanType.h similarity index 87% rename from typescript/types/booleanType.h rename to checker/types/ts/booleanType.h index 463b5c596..e16b95c68 100644 --- a/typescript/types/booleanType.h +++ b/checker/types/ts/booleanType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanType : public Type { diff --git a/typescript/types/constructorType.cpp b/checker/types/ts/constructorType.cpp similarity index 95% rename from typescript/types/constructorType.cpp rename to checker/types/ts/constructorType.cpp index 15edc26fd..3af66bc5a 100644 --- a/typescript/types/constructorType.cpp +++ b/checker/types/ts/constructorType.cpp @@ -15,7 +15,7 @@ #include "constructorType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void ConstructorType::ToString(std::stringstream &ss) const diff --git a/typescript/types/constructorType.h b/checker/types/ts/constructorType.h similarity index 90% rename from typescript/types/constructorType.h rename to checker/types/ts/constructorType.h index 0776b2f19..4c930cee4 100644 --- a/typescript/types/constructorType.h +++ b/checker/types/ts/constructorType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H #include "objectType.h" diff --git a/typescript/types/elementFlags.h b/checker/types/ts/elementFlags.h similarity index 79% rename from typescript/types/elementFlags.h rename to checker/types/ts/elementFlags.h index dba255767..d3a73c35b 100644 --- a/typescript/types/elementFlags.h +++ b/checker/types/ts/elementFlags.h @@ -13,18 +13,18 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" namespace panda::es2panda::checker { enum class ElementFlags : uint32_t { - NO_OPTS = 0x0U, - REQUIRED = 0x1U, // T - OPTIONAL = 0x2U, // T? - REST = 0x4U, // ...T[] - VARIADIC = 0x8U, // ...T + NO_OPTS = 0U, + REQUIRED = 1U << 0U, // T + OPTIONAL = 1U << 1U, // T? + REST = 1U << 2U, // ...T[] + VARIADIC = 1U << 3U, // ...T FIXED = REQUIRED | OPTIONAL, VARIABLE = REST | VARIADIC, NON_REQUIRED = OPTIONAL | REST | VARIADIC, diff --git a/typescript/types/enumLiteralType.cpp b/checker/types/ts/enumLiteralType.cpp similarity index 96% rename from typescript/types/enumLiteralType.cpp rename to checker/types/ts/enumLiteralType.cpp index 79984a9e3..f6b7bc3ce 100644 --- a/typescript/types/enumLiteralType.cpp +++ b/checker/types/ts/enumLiteralType.cpp @@ -16,7 +16,7 @@ #include "enumLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void EnumLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/enumLiteralType.h b/checker/types/ts/enumLiteralType.h similarity index 90% rename from typescript/types/enumLiteralType.h rename to checker/types/ts/enumLiteralType.h index 1b601a2c4..a0ddeb725 100644 --- a/typescript/types/enumLiteralType.h +++ b/checker/types/ts/enumLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class Scope; diff --git a/typescript/types/enumType.cpp b/checker/types/ts/enumType.cpp similarity index 100% rename from typescript/types/enumType.cpp rename to checker/types/ts/enumType.cpp diff --git a/typescript/types/enumType.h b/checker/types/ts/enumType.h similarity index 90% rename from typescript/types/enumType.h rename to checker/types/ts/enumType.h index 2c8cf92f8..1a06fb731 100644 --- a/typescript/types/enumType.h +++ b/checker/types/ts/enumType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class EnumVariable; diff --git a/typescript/types/functionType.cpp b/checker/types/ts/functionType.cpp similarity index 96% rename from typescript/types/functionType.cpp rename to checker/types/ts/functionType.cpp index 274dceefc..d3748baf3 100644 --- a/typescript/types/functionType.cpp +++ b/checker/types/ts/functionType.cpp @@ -15,7 +15,7 @@ #include "functionType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void FunctionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/functionType.h b/checker/types/ts/functionType.h similarity index 90% rename from typescript/types/functionType.h rename to checker/types/ts/functionType.h index 4527c6b99..f1b465a54 100644 --- a/typescript/types/functionType.h +++ b/checker/types/ts/functionType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H #include #include "objectType.h" diff --git a/typescript/types/indexInfo.cpp b/checker/types/ts/indexInfo.cpp similarity index 100% rename from typescript/types/indexInfo.cpp rename to checker/types/ts/indexInfo.cpp diff --git a/typescript/types/indexInfo.h b/checker/types/ts/indexInfo.h similarity index 92% rename from typescript/types/indexInfo.h rename to checker/types/ts/indexInfo.h index 111079a3b..79e252ebc 100644 --- a/typescript/types/indexInfo.h +++ b/checker/types/ts/indexInfo.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class IndexInfo { diff --git a/typescript/types/interfaceType.cpp b/checker/types/ts/interfaceType.cpp similarity index 98% rename from typescript/types/interfaceType.cpp rename to checker/types/ts/interfaceType.cpp index f9f48b683..2d093f1f7 100644 --- a/typescript/types/interfaceType.cpp +++ b/checker/types/ts/interfaceType.cpp @@ -16,8 +16,8 @@ #include "interfaceType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeParameter.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/typeParameter.h" #include #include diff --git a/typescript/types/interfaceType.h b/checker/types/ts/interfaceType.h similarity index 97% rename from typescript/types/interfaceType.h rename to checker/types/ts/interfaceType.h index 1788e719a..d929906a0 100644 --- a/typescript/types/interfaceType.h +++ b/checker/types/ts/interfaceType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H #include "objectType.h" diff --git a/typescript/types/neverType.cpp b/checker/types/ts/neverType.cpp similarity index 100% rename from typescript/types/neverType.cpp rename to checker/types/ts/neverType.cpp diff --git a/typescript/types/neverType.h b/checker/types/ts/neverType.h similarity index 87% rename from typescript/types/neverType.h rename to checker/types/ts/neverType.h index d103dc77c..606e255f4 100644 --- a/typescript/types/neverType.h +++ b/checker/types/ts/neverType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NeverType : public Type { diff --git a/typescript/types/nonPrimitiveType.cpp b/checker/types/ts/nonPrimitiveType.cpp similarity index 100% rename from typescript/types/nonPrimitiveType.cpp rename to checker/types/ts/nonPrimitiveType.cpp diff --git a/typescript/types/nonPrimitiveType.h b/checker/types/ts/nonPrimitiveType.h similarity index 86% rename from typescript/types/nonPrimitiveType.h rename to checker/types/ts/nonPrimitiveType.h index ea646d161..380aaa316 100644 --- a/typescript/types/nonPrimitiveType.h +++ b/checker/types/ts/nonPrimitiveType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NonPrimitiveType : public Type { diff --git a/typescript/types/nullType.cpp b/checker/types/ts/nullType.cpp similarity index 100% rename from typescript/types/nullType.cpp rename to checker/types/ts/nullType.cpp diff --git a/typescript/types/nullType.h b/checker/types/ts/nullType.h similarity index 88% rename from typescript/types/nullType.h rename to checker/types/ts/nullType.h index 45f37fc48..16b4a614c 100644 --- a/typescript/types/nullType.h +++ b/checker/types/ts/nullType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NullType : public Type { diff --git a/typescript/types/numberLiteralType.cpp b/checker/types/ts/numberLiteralType.cpp similarity index 96% rename from typescript/types/numberLiteralType.cpp rename to checker/types/ts/numberLiteralType.cpp index f72e6f6cd..c94f81681 100644 --- a/typescript/types/numberLiteralType.cpp +++ b/checker/types/ts/numberLiteralType.cpp @@ -17,7 +17,7 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberLiteralType.h b/checker/types/ts/numberLiteralType.h similarity index 88% rename from typescript/types/numberLiteralType.h rename to checker/types/ts/numberLiteralType.h index e3c3a9a96..b3c34d898 100644 --- a/typescript/types/numberLiteralType.h +++ b/checker/types/ts/numberLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberLiteralType : public Type { diff --git a/typescript/types/numberType.cpp b/checker/types/ts/numberType.cpp similarity index 96% rename from typescript/types/numberType.cpp rename to checker/types/ts/numberType.cpp index 0a89535ac..9381711f7 100644 --- a/typescript/types/numberType.cpp +++ b/checker/types/ts/numberType.cpp @@ -16,7 +16,7 @@ #include "numberType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberType.h b/checker/types/ts/numberType.h similarity index 87% rename from typescript/types/numberType.h rename to checker/types/ts/numberType.h index 702417e77..f8505c863 100644 --- a/typescript/types/numberType.h +++ b/checker/types/ts/numberType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberType : public Type { diff --git a/typescript/types/objectDescriptor.cpp b/checker/types/ts/objectDescriptor.cpp similarity index 93% rename from typescript/types/objectDescriptor.cpp rename to checker/types/ts/objectDescriptor.cpp index df7949ba5..6d9ec80ba 100644 --- a/typescript/types/objectDescriptor.cpp +++ b/checker/types/ts/objectDescriptor.cpp @@ -16,8 +16,8 @@ #include "objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { binder::LocalVariable *ObjectDescriptor::FindProperty(const util::StringView &name) const diff --git a/typescript/types/objectDescriptor.h b/checker/types/ts/objectDescriptor.h similarity index 93% rename from typescript/types/objectDescriptor.h rename to checker/types/ts/objectDescriptor.h index 1d1ba16e5..f852f5014 100644 --- a/typescript/types/objectDescriptor.h +++ b/checker/types/ts/objectDescriptor.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H #include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" diff --git a/typescript/types/objectLiteralType.cpp b/checker/types/ts/objectLiteralType.cpp similarity index 94% rename from typescript/types/objectLiteralType.cpp rename to checker/types/ts/objectLiteralType.cpp index 729940cd1..7581f3289 100644 --- a/typescript/types/objectLiteralType.cpp +++ b/checker/types/ts/objectLiteralType.cpp @@ -16,11 +16,11 @@ #include "objectLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -class Checker; +class TSChecker; void ObjectLiteralType::ToString(std::stringstream &ss) const { diff --git a/typescript/types/objectLiteralType.h b/checker/types/ts/objectLiteralType.h similarity index 90% rename from typescript/types/objectLiteralType.h rename to checker/types/ts/objectLiteralType.h index a20328d7c..e9b5695c1 100644 --- a/typescript/types/objectLiteralType.h +++ b/checker/types/ts/objectLiteralType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H #include "objectType.h" diff --git a/typescript/types/objectType.cpp b/checker/types/ts/objectType.cpp similarity index 97% rename from typescript/types/objectType.cpp rename to checker/types/ts/objectType.cpp index 966a57af8..fd34d5873 100644 --- a/typescript/types/objectType.cpp +++ b/checker/types/ts/objectType.cpp @@ -15,10 +15,10 @@ #include "objectType.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/interfaceType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/interfaceType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" namespace panda::es2panda::checker { bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation, diff --git a/typescript/types/objectType.h b/checker/types/ts/objectType.h similarity index 89% rename from typescript/types/objectType.h rename to checker/types/ts/objectType.h index 0b07f5a26..76adb47f9 100644 --- a/typescript/types/objectType.h +++ b/checker/types/ts/objectType.h @@ -13,12 +13,12 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" @@ -33,11 +33,11 @@ OBJECT_TYPE_MAPPING(DECLARE_OBJECT_TYPENAMES) #undef DECLARE_OBJECT_TYPENAMES enum class ObjectFlags : uint32_t { - NO_OPTS = 0x0U, - CHECK_EXCESS_PROPS = 0x1U, - RESOLVED_MEMBERS = 0x2U, - RESOLVED_BASE_TYPES = 0x4U, - RESOLVED_DECLARED_MEMBERS = 0x8U, + NO_OPTS = 0U, + CHECK_EXCESS_PROPS = 1U << 0U, + RESOLVED_MEMBERS = 1U << 1U, + RESOLVED_BASE_TYPES = 1U << 2U, + RESOLVED_DECLARED_MEMBERS = 1U << 3U, }; DEFINE_BITOPS(ObjectFlags) @@ -76,10 +76,13 @@ public: OBJECT_TYPE_MAPPING(OBJECT_TYPE_AS_CASTS) #undef OBJECT_TYPE_AS_CASTS - explicit ObjectType(ObjectType::ObjectTypeKind kind) : Type(TypeFlag::OBJECT), kind_(kind) {} + explicit ObjectType(ObjectType::ObjectTypeKind kind) + : Type(TypeFlag::OBJECT), kind_(kind), objFlag_(ObjectFlags::NO_OPTS) + { + } ObjectType(ObjectType::ObjectTypeKind kind, ObjectDescriptor *desc) - : Type(TypeFlag::OBJECT), kind_(kind), desc_(desc) + : Type(TypeFlag::OBJECT), kind_(kind), desc_(desc), objFlag_(ObjectFlags::NO_OPTS) { } diff --git a/typescript/types/stringLiteralType.cpp b/checker/types/ts/stringLiteralType.cpp similarity index 100% rename from typescript/types/stringLiteralType.cpp rename to checker/types/ts/stringLiteralType.cpp diff --git a/typescript/types/stringLiteralType.h b/checker/types/ts/stringLiteralType.h similarity index 88% rename from typescript/types/stringLiteralType.h rename to checker/types/ts/stringLiteralType.h index 0c9c07826..c4df8c8e4 100644 --- a/typescript/types/stringLiteralType.h +++ b/checker/types/ts/stringLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringLiteralType : public Type { diff --git a/typescript/types/stringType.cpp b/checker/types/ts/stringType.cpp similarity index 100% rename from typescript/types/stringType.cpp rename to checker/types/ts/stringType.cpp diff --git a/typescript/types/stringType.h b/checker/types/ts/stringType.h similarity index 87% rename from typescript/types/stringType.h rename to checker/types/ts/stringType.h index 86e746e96..c21499b93 100644 --- a/typescript/types/stringType.h +++ b/checker/types/ts/stringType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringType : public Type { diff --git a/typescript/types/tupleType.cpp b/checker/types/ts/tupleType.cpp similarity index 97% rename from typescript/types/tupleType.cpp rename to checker/types/ts/tupleType.cpp index 4358db09c..e6830f28d 100644 --- a/typescript/types/tupleType.cpp +++ b/checker/types/ts/tupleType.cpp @@ -15,10 +15,10 @@ #include "tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *TupleType::ConvertToArrayType(Checker *checker) +Type *TupleType::ConvertToArrayType(TSChecker *checker) { ArenaVector unionTypes(checker->Allocator()->Adapter()); diff --git a/typescript/types/tupleType.h b/checker/types/ts/tupleType.h similarity index 92% rename from typescript/types/tupleType.h rename to checker/types/ts/tupleType.h index b69978fca..3ee5d44a1 100644 --- a/typescript/types/tupleType.h +++ b/checker/types/ts/tupleType.h @@ -13,14 +13,14 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H #include "macros.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/elementFlags.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/elementFlags.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { using NamedTupleMemberPool = std::unordered_map; @@ -101,7 +101,7 @@ public: return res->second; } - Type *ConvertToArrayType(Checker *checker); + Type *ConvertToArrayType(TSChecker *checker); void ToString(std::stringstream &ss) const override; void Identical(TypeRelation *relation, Type *other) override; diff --git a/typescript/types/typeParameter.cpp b/checker/types/ts/typeParameter.cpp similarity index 100% rename from typescript/types/typeParameter.cpp rename to checker/types/ts/typeParameter.cpp diff --git a/typescript/types/typeParameter.h b/checker/types/ts/typeParameter.h similarity index 90% rename from typescript/types/typeParameter.h rename to checker/types/ts/typeParameter.h index fe30e2cdc..2b6a51dd2 100644 --- a/typescript/types/typeParameter.h +++ b/checker/types/ts/typeParameter.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeParameter : public Type { diff --git a/typescript/types/typeReference.cpp b/checker/types/ts/typeReference.cpp similarity index 100% rename from typescript/types/typeReference.cpp rename to checker/types/ts/typeReference.cpp diff --git a/typescript/types/typeReference.h b/checker/types/ts/typeReference.h similarity index 84% rename from typescript/types/typeReference.h rename to checker/types/ts/typeReference.h index aa90e1c70..9b7c47f12 100644 --- a/typescript/types/typeReference.h +++ b/checker/types/ts/typeReference.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeReference : public Type { @@ -44,4 +44,4 @@ private: }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/typescript/types/types.h b/checker/types/ts/types.h similarity index 89% rename from typescript/types/types.h rename to checker/types/ts/types.h index 7b3d98100..404ed5af8 100644 --- a/typescript/types/types.h +++ b/checker/types/ts/types.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_H #include "anyType.h" #include "arrayType.h" @@ -42,8 +42,8 @@ #include "unknownType.h" #include "voidType.h" #include "indexInfo.h" -#include "signature.h" #include "typeParameter.h" #include "typeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" #endif /* TYPES_H */ diff --git a/typescript/types/undefinedType.cpp b/checker/types/ts/undefinedType.cpp similarity index 100% rename from typescript/types/undefinedType.cpp rename to checker/types/ts/undefinedType.cpp diff --git a/typescript/types/undefinedType.h b/checker/types/ts/undefinedType.h similarity index 87% rename from typescript/types/undefinedType.h rename to checker/types/ts/undefinedType.h index 64cdef883..d58e4561f 100644 --- a/typescript/types/undefinedType.h +++ b/checker/types/ts/undefinedType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UndefinedType : public Type { diff --git a/typescript/types/unionType.cpp b/checker/types/ts/unionType.cpp similarity index 98% rename from typescript/types/unionType.cpp rename to checker/types/ts/unionType.cpp index 9bb413659..b408ae424 100644 --- a/typescript/types/unionType.cpp +++ b/checker/types/ts/unionType.cpp @@ -16,7 +16,7 @@ #include "unionType.h" #include -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" namespace panda::es2panda::checker { void UnionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/unionType.h b/checker/types/ts/unionType.h similarity index 96% rename from typescript/types/unionType.h rename to checker/types/ts/unionType.h index 70e185017..90222f83e 100644 --- a/typescript/types/unionType.h +++ b/checker/types/ts/unionType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class GlobalTypesHolder; diff --git a/typescript/types/unknownType.cpp b/checker/types/ts/unknownType.cpp similarity index 100% rename from typescript/types/unknownType.cpp rename to checker/types/ts/unknownType.cpp diff --git a/typescript/types/unknownType.h b/checker/types/ts/unknownType.h similarity index 87% rename from typescript/types/unknownType.h rename to checker/types/ts/unknownType.h index 892b81655..205e1e501 100644 --- a/typescript/types/unknownType.h +++ b/checker/types/ts/unknownType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UnknownType : public Type { diff --git a/typescript/types/voidType.cpp b/checker/types/ts/voidType.cpp similarity index 100% rename from typescript/types/voidType.cpp rename to checker/types/ts/voidType.cpp diff --git a/typescript/types/voidType.h b/checker/types/ts/voidType.h similarity index 87% rename from typescript/types/voidType.h rename to checker/types/ts/voidType.h index 9f8fcfd2c..2776c0d5b 100644 --- a/typescript/types/voidType.h +++ b/checker/types/ts/voidType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class VoidType : public Type { diff --git a/typescript/types/type.cpp b/checker/types/type.cpp similarity index 63% rename from typescript/types/type.cpp rename to checker/types/type.cpp index 4d4ba4b5b..c61cb48b4 100644 --- a/typescript/types/type.cpp +++ b/checker/types/type.cpp @@ -15,11 +15,21 @@ #include "type.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFlag.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFlag.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" namespace panda::es2panda::checker { +bool Type::IsETSNullType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::NULL_TYPE); +} + +bool Type::IsETSStringType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::STRING); +} + void Type::ToStringAsSrc(std::stringstream &ss) const { ToString(ss); @@ -35,8 +45,20 @@ bool Type::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unu return false; } +TypeFacts Type::GetTypeFacts() const +{ + return TypeFacts::NONE; +} + void Type::Compare([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) {} +void Type::IsSubtype([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *Type::AsSuper([[maybe_unused]] Checker *checker, [[maybe_unused]] binder::Variable *sourceVar) +{ + return nullptr; +} + Type *Type::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, [[maybe_unused]] GlobalTypesHolder *globalTypes) { diff --git a/typescript/types/type.h b/checker/types/type.h similarity index 72% rename from typescript/types/type.h rename to checker/types/type.h index c0411b81c..58170c8d1 100644 --- a/typescript/types/type.h +++ b/checker/types/type.h @@ -13,12 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeMapping.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "generated/signatures.h" +#include "plugins/ecmascript/es2panda/checker/types/typeMapping.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFacts.h" #include "macros.h" #include @@ -36,6 +37,7 @@ class GlobalTypesHolder; #define DECLARE_TYPENAMES(typeFlag, typeName) class typeName; TYPE_MAPPING(DECLARE_TYPENAMES) #undef DECLARE_TYPENAMES +class ETSStringType; class Type { public: @@ -74,6 +76,21 @@ public: TYPE_MAPPING(TYPE_AS_CASTS) #undef TYPE_AS_CASTS + bool IsETSStringType() const; + bool IsETSNullType() const; + + ETSStringType *AsETSStringType() + { + ASSERT(IsETSObjectType()); + return reinterpret_cast(this); + } + + const ETSStringType *AsETSStringType() const + { + ASSERT(IsETSObjectType()); + return reinterpret_cast(this); + } + TypeFlag TypeFlags() const { return typeFlags_; @@ -114,16 +131,35 @@ public: return variable_; } + util::StringView ToAssemblerTypeView(ArenaAllocator *allocator) const + { + std::stringstream ss; + ToAssemblerType(ss); + return util::UString(ss.str(), allocator).View(); + } + virtual void ToString(std::stringstream &ss) const = 0; virtual void ToStringAsSrc(std::stringstream &ss) const; - virtual TypeFacts GetTypeFacts() const = 0; + virtual TypeFacts GetTypeFacts() const; + virtual void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const {}; + virtual void ToAssemblerTypeWithRank([[maybe_unused]] std::stringstream &ss) const + { + ToAssemblerType(ss); + }; + + virtual uint32_t Rank() const + { + return 0; + } virtual void Identical(TypeRelation *relation, Type *other); virtual void AssignmentTarget(TypeRelation *relation, Type *source) = 0; virtual bool AssignmentSource(TypeRelation *relation, Type *target); virtual void Compare(TypeRelation *relation, Type *other); + virtual void IsSubtype(TypeRelation *relation, Type *source); + virtual Type *AsSuper(Checker *checker, binder::Variable *sourceVar); - virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) = 0; + virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) diff --git a/typescript/types/typeFacts.h b/checker/types/typeFacts.h similarity index 75% rename from typescript/types/typeFacts.h rename to checker/types/typeFacts.h index 3a92604a7..e5fe539a1 100644 --- a/typescript/types/typeFacts.h +++ b/checker/types/typeFacts.h @@ -13,38 +13,38 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" namespace panda::es2panda::checker { enum class TypeFacts : uint32_t { - NONE = 0x0U, - TYPEOF_EQ_STRING = 0x1U, // typeof x === "string" - TYPEOF_EQ_NUMBER = 0x2U, // typeof x === "number" - TYPEOF_EQ_BIGINT = 0x4U, // typeof x === "bigint" - TYPEOF_EQ_BOOLEAN = 0x8U, // typeof x === "boolean" - TYPEOF_EQ_SYMBOL = 0x10U, // typeof x === "symbol" - TYPEOF_EQ_OBJECT = 0x20U, // typeof x === "object" - TYPEOF_EQ_FUNCTION = 0x40U, // typeof x === "function" - TYPEOF_EQ_HOST_OBJECT = 0x80U, // typeof x === "xxx" - TYPEOF_NE_STRING = 0x100U, // typeof x !== "string" - TYPEOF_NE_NUMBER = 0x200U, // typeof x !== "number" - TYPEOF_NE_BIGINT = 0x400U, // typeof x !== "bigint" - TYPEOF_NE_BOOLEAN = 0x800U, // typeof x !== "boolean" - TYPEOF_NE_SYMBOL = 0x1000U, // typeof x !== "symbol" - TYPEOF_NE_OBJECT = 0x2000U, // typeof x !== "object" - TYPEOF_NE_FUNCTION = 0x4000U, // typeof x !== "function" - TYPEOF_NE_HOST_OBJECT = 0x8000U, // typeof x !== "xxx" - EQ_UNDEFINED = 0x10000U, // x === undefined - EQ_NULL = 0x20000U, // x === null - EQ_UNDEFINED_OR_NULL = 0x40000U, // x === undefined / x === null - NE_UNDEFINED = 0x80000U, // x !== undefined - NE_NULL = 0x100000U, // x !== null - NE_UNDEFINED_OR_NULL = 0x200000U, // x != undefined / x != null - TRUTHY = 0x400000U, // x - FALSY = 0x800000U, // !x + NONE = 0U, + TYPEOF_EQ_STRING = 1U << 0U, // typeof x === "string" + TYPEOF_EQ_NUMBER = 1U << 1U, // typeof x === "number" + TYPEOF_EQ_BIGINT = 1U << 2U, // typeof x === "bigint" + TYPEOF_EQ_BOOLEAN = 1U << 3U, // typeof x === "boolean" + TYPEOF_EQ_SYMBOL = 1U << 4U, // typeof x === "symbol" + TYPEOF_EQ_OBJECT = 1U << 5U, // typeof x === "object" + TYPEOF_EQ_FUNCTION = 1U << 6U, // typeof x === "function" + TYPEOF_EQ_HOST_OBJECT = 1U << 7U, // typeof x === "xxx" + TYPEOF_NE_STRING = 1U << 8U, // typeof x !== "string" + TYPEOF_NE_NUMBER = 1U << 9U, // typeof x !== "number" + TYPEOF_NE_BIGINT = 1U << 10U, // typeof x !== "bigint" + TYPEOF_NE_BOOLEAN = 1U << 11U, // typeof x !== "boolean" + TYPEOF_NE_SYMBOL = 1U << 12U, // typeof x !== "symbol" + TYPEOF_NE_OBJECT = 1U << 13U, // typeof x !== "object" + TYPEOF_NE_FUNCTION = 1U << 14U, // typeof x !== "function" + TYPEOF_NE_HOST_OBJECT = 1U << 15U, // typeof x !== "xxx" + EQ_UNDEFINED = 1U << 16U, // x === undefined + EQ_NULL = 1U << 17U, // x === null + EQ_UNDEFINED_OR_NULL = 1U << 18U, // x === undefined / x === null + NE_UNDEFINED = 1U << 19U, // x !== undefined + NE_NULL = 1U << 20U, // x !== null + NE_UNDEFINED_OR_NULL = 1U << 21U, // x != undefined / x != null + TRUTHY = 1U << 22U, // x + FALSY = 1U << 23U, // !x LAST = FALSY, ALL = (LAST << 1U) - 1U, diff --git a/typescript/types/typeFlag.h b/checker/types/typeFlag.h similarity index 33% rename from typescript/types/typeFlag.h rename to checker/types/typeFlag.h index 613221f8c..a7fadb812 100644 --- a/typescript/types/typeFlag.h +++ b/checker/types/typeFlag.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FLAG_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FLAG_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" @@ -23,39 +23,76 @@ namespace panda::es2panda::checker { enum class TypeFlag : uint64_t { NONE = 0, - NUMBER = 1ULL << 0U, // x: number - STRING = 1ULL << 1U, // x: string - BOOLEAN = 1ULL << 2U, // x: boolean - VOID = 1ULL << 3U, // x: void - NULL_TYPE = 1ULL << 4U, // x: null - UNDEFINED = 1ULL << 5U, // x: undefined - UNKNOWN = 1ULL << 6U, // x: unknown - NEVER = 1ULL << 7U, // x: never - UNION = 1ULL << 8U, // x: a | b - OBJECT = 1ULL << 9U, // x: object - BIGINT = 1ULL << 10U, // x: bigint - BOOLEAN_LITERAL = 1ULL << 11U, // x: true - NUMBER_LITERAL = 1ULL << 12U, // x: 10 - STRING_LITERAL = 1ULL << 13U, // x: "foo" - BIGINT_LITERAL = 1ULL << 14U, // x: 10n - ENUM = 1ULL << 15U, // enum x - ENUM_LITERAL = 1ULL << 16U, // member of enum - SYMBOL = 1ULL << 17U, // x: symbol - UNIQUE_SYMBOL = 1ULL << 18U, // one of JS unique symbols - TYPE_PARAMETER = 1ULL << 19U, // function - INTERSECTION = 1ULL << 20U, // x: a & b - INDEX = 1ULL << 21U, // keyof x - INDEX_ACCESS = 1ULL << 22U, // x[a] - CONDITIONAL = 1ULL << 23U, // x extends a ? b : c - SUBSTITUTION = 1ULL << 24U, // type parameter substitution - TEMPLATE_LITERAL = 1ULL << 25U, // x: `hello ${World}` - STRING_MAPPING = 1ULL << 27U, // Uppercase/Lowercase type - ANY = 1ULL << 28U, // x: any - ARRAY = 1ULL << 29U, // x: number[] - FUNCTION = 1ULL << 30U, // x: (a) => b - NON_PRIMITIVE = 1ULL << 31U, // x: object - TYPE_REFERENCE = 1ULL << 32U, - READONLY = 1ULL << 33U, + NUMBER = 1ULL << 0ULL, // x: number + STRING = 1ULL << 1ULL, // x: string + BOOLEAN = 1ULL << 2ULL, // x: boolean + VOID = 1ULL << 3ULL, // x: void + NULL_TYPE = 1ULL << 4ULL, // x: null + UNDEFINED = 1ULL << 5ULL, // x: undefined + UNKNOWN = 1ULL << 6ULL, // x: unknown + NEVER = 1ULL << 7ULL, // x: never + UNION = 1ULL << 8ULL, // x: a | b + OBJECT = 1ULL << 9ULL, // x: object + BIGINT = 1ULL << 10ULL, // x: bigint + BOOLEAN_LITERAL = 1ULL << 11ULL, // x: true + NUMBER_LITERAL = 1ULL << 12ULL, // x: 10 + STRING_LITERAL = 1ULL << 13ULL, // x: "foo" + BIGINT_LITERAL = 1ULL << 14ULL, // x: 10n + ENUM = 1ULL << 15ULL, // enum x + ENUM_LITERAL = 1ULL << 16ULL, // member of enum + SYMBOL = 1ULL << 17ULL, // x: symbol + UNIQUE_SYMBOL = 1ULL << 18ULL, // one of JS unique symbols + TYPE_PARAMETER = 1ULL << 19ULL, // function + INTERSECTION = 1ULL << 20ULL, // x: a & b + INDEX = 1ULL << 21ULL, // keyof x + INDEX_ACCESS = 1ULL << 22ULL, // x[a] + CONDITIONAL = 1ULL << 23ULL, // x extends a ? b : c + SUBSTITUTION = 1ULL << 24ULL, // type parameter substitution + TEMPLATE_LITERAL = 1ULL << 25ULL, // x: `hello ${World}` + STRING_MAPPING = 1ULL << 27ULL, // Uppercase/Lowercase type + ANY = 1ULL << 28ULL, // x: any + ARRAY = 1ULL << 29ULL, // x: number[] + FUNCTION = 1ULL << 30ULL, // x: (a) => b + NON_PRIMITIVE = 1ULL << 31ULL, // x: object + TYPE_REFERENCE = 1ULL << 32ULL, // x: A + READONLY = 1ULL << 33ULL, // type assigned to a readonly property + CONSTANT = 1ULL << 34ULL, // type for constant expressions containing the associated constant value + BYTE = 1ULL << 35ULL, // x: byte + SHORT = 1ULL << 36ULL, // x: short + INT = 1ULL << 37ULL, // x: int + LONG = 1ULL << 38ULL, // x: long + FLOAT = 1ULL << 39ULL, // x: float + DOUBLE = 1ULL << 40ULL, // x: double + CHAR = 1ULL << 41ULL, // x: char + ETS_BOOLEAN = 1ULL << 42ULL, // ETS boolean type + ETS_VOID = 1ULL << 43ULL, // ETS void type + ETS_OBJECT = 1ULL << 44ULL, // ETS class or interface type + ETS_ARRAY = 1ULL << 45ULL, // ETS array type + SYNTHETIC = 1ULL << 46ULL, // synthetic type created by the checker for specific checks + WILDCARD = 1ULL << 47ULL, // new A() + ETS_TYPE_PARAMETER = 1ULL << 48ULL, // ETS type parameter + ETS_TYPE_REFERENCE = 1ULL << 49ULL, // ETS type reference + ETS_TYPE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | ETS_BOOLEAN | ETS_VOID | ETS_OBJECT | ETS_ARRAY | + WILDCARD | ETS_TYPE_PARAMETER, + ETS_PRIMITIVE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | ETS_BOOLEAN | ETS_VOID, + ETS_ARRAY_INDEX = BYTE | SHORT | INT, + ETS_INTEGRAL = BYTE | CHAR | SHORT | INT | LONG, + ETS_FLOATING_POINT = FLOAT | DOUBLE, + ETS_NUMERIC = ETS_INTEGRAL | FLOAT | DOUBLE, + ETS_ARRAY_OR_OBJECT = ETS_ARRAY | ETS_OBJECT, + ETS_WIDE_NUMERIC = LONG | DOUBLE, + VALID_SWITCH_TYPE = BYTE | SHORT | INT | CHAR | LONG | ENUM_LITERAL, + NARROWABLE_TO_FLOAT = DOUBLE, + NARROWABLE_TO_LONG = FLOAT | NARROWABLE_TO_FLOAT, + NARROWABLE_TO_INT = LONG | NARROWABLE_TO_LONG, + NARROWABLE_TO_CHAR = SHORT | INT | NARROWABLE_TO_INT, + NARROWABLE_TO_SHORT = INT | NARROWABLE_TO_INT, + NARROWABLE_TO_BYTE = CHAR | NARROWABLE_TO_CHAR, + WIDENABLE_TO_SHORT = BYTE, + WIDENABLE_TO_INT = CHAR | SHORT | WIDENABLE_TO_SHORT, + WIDENABLE_TO_LONG = INT | WIDENABLE_TO_INT, + WIDENABLE_TO_FLOAT = LONG | WIDENABLE_TO_LONG, + WIDENABLE_TO_DOUBLE = FLOAT | WIDENABLE_TO_FLOAT, COMPUTED_TYPE_LITERAL_NAME = STRING_LITERAL | NUMBER_LITERAL | ENUM, COMPUTED_NAME = COMPUTED_TYPE_LITERAL_NAME | STRING | NUMBER | ANY | SYMBOL, ANY_OR_UNKNOWN = ANY | UNKNOWN, diff --git a/checker/types/typeMapping.h b/checker/types/typeMapping.h new file mode 100644 index 000000000..ae3b69582 --- /dev/null +++ b/checker/types/typeMapping.h @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H + +#include "typeFlag.h" + +// NOLINTBEGIN(cppcoreguidelines-macro-usage) +#define TYPE_MAPPING(_) \ + _(TypeFlag::ARRAY, ArrayType) \ + _(TypeFlag::ANY, AnyType) \ + _(TypeFlag::BIGINT_LITERAL, BigintLiteralType) \ + _(TypeFlag::NUMBER, NumberType) \ + _(TypeFlag::STRING, StringType) \ + _(TypeFlag::BOOLEAN, BooleanType) \ + _(TypeFlag::VOID, VoidType) \ + _(TypeFlag::NULL_TYPE, NullType) \ + _(TypeFlag::UNDEFINED, UndefinedType) \ + _(TypeFlag::UNKNOWN, UnknownType) \ + _(TypeFlag::NEVER, NeverType) \ + _(TypeFlag::UNION, UnionType) \ + _(TypeFlag::OBJECT, ObjectType) \ + _(TypeFlag::BIGINT, BigintType) \ + _(TypeFlag::BOOLEAN_LITERAL, BooleanLiteralType) \ + _(TypeFlag::NUMBER_LITERAL, NumberLiteralType) \ + _(TypeFlag::STRING_LITERAL, StringLiteralType) \ + _(TypeFlag::ENUM, EnumType) \ + _(TypeFlag::ENUM_LITERAL, EnumLiteralType) \ + _(TypeFlag::TYPE_PARAMETER, TypeParameter) \ + _(TypeFlag::TYPE_REFERENCE, TypeReference) \ + _(TypeFlag::BYTE, ByteType) \ + _(TypeFlag::SHORT, ShortType) \ + _(TypeFlag::INT, IntType) \ + _(TypeFlag::LONG, LongType) \ + _(TypeFlag::FLOAT, FloatType) \ + _(TypeFlag::DOUBLE, DoubleType) \ + _(TypeFlag::CHAR, CharType) \ + _(TypeFlag::ETS_BOOLEAN, ETSBooleanType) \ + _(TypeFlag::ETS_VOID, ETSVoidType) \ + _(TypeFlag::FUNCTION, ETSFunctionType) \ + _(TypeFlag::ETS_OBJECT, ETSObjectType) \ + _(TypeFlag::ETS_ARRAY, ETSArrayType) \ + _(TypeFlag::NON_PRIMITIVE, NonPrimitiveType) \ + _(TypeFlag::WILDCARD, WildcardType) \ + _(TypeFlag::ETS_TYPE_PARAMETER, ETSTypeParameter) \ + _(TypeFlag::ETS_TYPE_REFERENCE, ETSTypeReference) + +#define OBJECT_TYPE_MAPPING(_) \ + _(ObjectType::ObjectTypeKind::FUNCTION, FunctionType) \ + _(ObjectType::ObjectTypeKind::TUPLE, TupleType) \ + _(ObjectType::ObjectTypeKind::LITERAL, ObjectLiteralType) \ + _(ObjectType::ObjectTypeKind::INTERFACE, InterfaceType) +// NOLINTEND(cppcoreguidelines-macro-usage) + +#endif /* TYPE_MAPPING_H */ diff --git a/typescript/types/typeRelation.cpp b/checker/types/typeRelation.cpp similarity index 84% rename from typescript/types/typeRelation.cpp rename to checker/types/typeRelation.cpp index da3491542..efdac8fd2 100644 --- a/typescript/types/typeRelation.cpp +++ b/checker/types/typeRelation.cpp @@ -15,33 +15,11 @@ #include "typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -const Type *AsSrc::GetType() const -{ - return type_; -} - -TypeRelation::TypeRelation(Checker *checker) : checker_(checker) {} - -bool TypeRelation::IsTrue() const -{ - return result_ == RelationResult::TRUE; -} - -const Checker *TypeRelation::GetChecker() const -{ - return checker_; -} - -Checker *TypeRelation::GetChecker() -{ - return checker_; -} - ArenaAllocator *TypeRelation::Allocator() { return checker_->Allocator(); @@ -116,6 +94,7 @@ bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target) return result_ == RelationResult::TRUE; } +// TODO(user): applyNarrowing -> flag bool TypeRelation::IsAssignableTo(Type *source, Type *target) { result_ = CacheLookup(source, target, checker_->AssignableResults(), RelationType::ASSIGNABLE); @@ -130,8 +109,10 @@ bool TypeRelation::IsAssignableTo(Type *source, Type *target) target->AssignmentTarget(this, source); } - checker_->AssignableResults().cached.insert( - {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + if (flags_ == TypeRelationFlag::NONE) { + checker_->AssignableResults().cached.insert( + {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + } } return result_ == RelationResult::TRUE; @@ -165,9 +146,4 @@ void TypeRelation::RaiseError(std::initializer_list lis { checker_->ThrowTypeError(list, loc); } - -void TypeRelation::Result(bool res) -{ - result_ = res ? RelationResult::TRUE : RelationResult::FALSE; -} } // namespace panda::es2panda::checker diff --git a/typescript/types/typeRelation.h b/checker/types/typeRelation.h similarity index 44% rename from typescript/types/typeRelation.h rename to checker/types/typeRelation.h index c55b30ea1..d8e8dfe12 100644 --- a/typescript/types/typeRelation.h +++ b/checker/types/typeRelation.h @@ -13,27 +13,58 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "plugins/ecmascript/es2panda/lexer/token/tokenType.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include "macros.h" #include #include +namespace panda::es2panda::ir { +class Expression; +} // namespace panda::es2panda::ir + namespace panda::es2panda::checker { class Signature; class IndexInfo; class Type; class Checker; -enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS }; +enum class TypeRelationFlag : uint32_t { + NONE = 0U, + NARROWING = 1U << 0U, + WIDENING = 1U << 1U, + BOXING = 1U << 2U, + UNBOXING = 1U << 3U, + CAPTURE = 1U << 4U, + STRING = 1U << 5U, + VALUE_SET = 1U << 6U, + UNCHECKED = 1U << 7U, + NO_THROW = 1U << 8U, + SELF_REFERENCE = 1U << 9U, + NO_RETURN_TYPE_CHECK = 1U << 10U, + DIRECT_RETURN = 1U << 11U, + NO_WIDENING = 1U << 12U, + NO_BOXING = 1U << 13U, + NO_UNBOXING = 1U << 14U, + ONLY_CHECK_WIDENING = 1U << 15U, + IN_ASSIGNMENT_CONTEXT = 1U << 16U, + + ASSIGNMENT_CONTEXT = WIDENING | BOXING | UNBOXING, +}; + +enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS, ERROR }; enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL }; +DEFINE_BITOPS(TypeRelationFlag) + class RelationKey { public: uint64_t sourceId; @@ -74,17 +105,86 @@ class AsSrc { public: explicit AsSrc(const Type *type) : type_(const_cast(type)) {} - const Type *GetType() const; + const Type *GetType() const + { + return type_; + } private: Type *type_; }; -using TypeErrorMessageElement = std::variant; +using TypeErrorMessageElement = + std::variant; class TypeRelation { public: - explicit TypeRelation(Checker *checker); + explicit TypeRelation(Checker *checker) : checker_(checker), result_(RelationResult::FALSE) {} + + bool IsTrue() const + { + return result_ == RelationResult::TRUE; + } + + bool IsError() const + { + return result_ == RelationResult::ERROR; + } + + bool ApplyNarrowing() const + { + return (flags_ & TypeRelationFlag::NARROWING) != 0; + } + + bool ApplyWidening() const + { + return (flags_ & TypeRelationFlag::WIDENING) != 0; + } + + bool ApplyBoxing() const + { + return (flags_ & TypeRelationFlag::BOXING) != 0; + } + + bool ApplyUnboxing() const + { + return (flags_ & TypeRelationFlag::UNBOXING) != 0; + } + + bool NoReturnTypeCheck() const + { + return (flags_ & TypeRelationFlag::NO_RETURN_TYPE_CHECK) != 0; + } + + bool DirectReturn() const + { + return (flags_ & TypeRelationFlag::DIRECT_RETURN) != 0; + } + + bool InAssignmentContext() const + { + return (flags_ & TypeRelationFlag::IN_ASSIGNMENT_CONTEXT) != 0; + } + + bool OnlyCheckWidening() const + { + return (flags_ & TypeRelationFlag::ONLY_CHECK_WIDENING) != 0; + } + + const Checker *GetChecker() const + { + return checker_; + } + + ir::Expression *GetNode() const + { + return node_; + } + + Checker *GetChecker() + { + return checker_; + } bool IsIdenticalTo(Type *source, Type *target); bool IsIdenticalTo(Signature *source, Signature *target); @@ -94,18 +194,58 @@ public: void RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const; void RaiseError(std::initializer_list list, const lexer::SourcePosition &loc) const; - void Result(bool res); - const Checker *GetChecker() const; - Checker *GetChecker(); + void Result(bool res) + { + result_ = res ? RelationResult::TRUE : RelationResult::FALSE; + } + + void Result(RelationResult res) + { + result_ = res; + } + + void SetNode(ir::Expression *node) + { + node_ = node; + } + + void SetFlags(TypeRelationFlag flags) + { + flags_ = flags; + } + ArenaAllocator *Allocator(); - bool IsTrue() const; + + friend class SavedTypeRelationFlagsContext; private: RelationResult CacheLookup(const Type *source, const Type *target, const RelationHolder &holder, RelationType type) const; Checker *checker_; - RelationResult result_ {RelationResult::FALSE}; + RelationResult result_ {}; + TypeRelationFlag flags_ {}; + ir::Expression *node_ {}; +}; +class SavedTypeRelationFlagsContext { +public: + explicit SavedTypeRelationFlagsContext(TypeRelation *relation, TypeRelationFlag newFlag) + : relation_(relation), prev_(relation->flags_) + { + relation_->flags_ = newFlag; + } + + NO_COPY_SEMANTIC(SavedTypeRelationFlagsContext); + DEFAULT_MOVE_SEMANTIC(SavedTypeRelationFlagsContext); + + ~SavedTypeRelationFlagsContext() + { + relation_->flags_ = prev_; + } + +private: + TypeRelation *relation_; + TypeRelationFlag prev_; }; } // namespace panda::es2panda::checker diff --git a/compiler/base/catchTable.cpp b/compiler/base/catchTable.cpp index b6992dd74..eda1103bb 100644 --- a/compiler/base/catchTable.cpp +++ b/compiler/base/catchTable.cpp @@ -18,8 +18,8 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -TryLabelSet::TryLabelSet(PandaGen *pg) - : try_(pg->AllocLabel(), pg->AllocLabel()), catch_(pg->AllocLabel(), pg->AllocLabel()) +TryLabelSet::TryLabelSet(CodeGen *cg) + : try_(cg->AllocLabel(), cg->AllocLabel()), catch_(cg->AllocLabel(), cg->AllocLabel()) { } } // namespace panda::es2panda::compiler diff --git a/compiler/base/catchTable.h b/compiler/base/catchTable.h index 5dfd29a23..50236a066 100644 --- a/compiler/base/catchTable.h +++ b/compiler/base/catchTable.h @@ -20,11 +20,11 @@ #include "plugins/ecmascript/es2panda/compiler/core/labelPair.h" namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class TryLabelSet { public: - explicit TryLabelSet(PandaGen *pg); + explicit TryLabelSet(CodeGen *cg); ~TryLabelSet() = default; DEFAULT_COPY_SEMANTIC(TryLabelSet); @@ -67,7 +67,7 @@ private: class CatchTable { public: - CatchTable(PandaGen *pg, uint32_t depth) : labelSet_(pg), depth_(depth) {} + CatchTable(CodeGen *cg, uint32_t depth) : labelSet_(cg), depth_(depth) {} ~CatchTable() = default; NO_COPY_SEMANTIC(CatchTable); diff --git a/compiler/base/condition.cpp b/compiler/base/condition.cpp index 647f20923..ce9558c83 100644 --- a/compiler/base/condition.cpp +++ b/compiler/base/condition.cpp @@ -16,6 +16,7 @@ #include "condition.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" #include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/unaryExpression.h" @@ -89,4 +90,83 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa pg->ToBoolean(expr); pg->BranchIfFalse(expr, falseLabel); } + +Condition::Result Condition::CheckConstantExpr(const ir::Expression *expr) +{ + if (expr->TsType()->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + auto res = expr->TsType()->AsETSBooleanType()->GetValue(); + return res ? Result::CONST_TRUE : Result::CONST_FALSE; + } + + return Result::UNKNOWN; +} + +void Condition::Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLabel) +{ + if (expr->IsBinaryExpression()) { + const auto *binExpr = expr->AsBinaryExpression(); + + switch (binExpr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::KEYW_INSTANCEOF: { + auto ttctx = TargetTypeContext(etsg, binExpr->OperationType()); + + RegScope rs(etsg); + VReg lhs = etsg->AllocReg(); + + binExpr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(binExpr, lhs, binExpr->OperationType()); + binExpr->Right()->Compile(etsg); + etsg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + binExpr->Left()->Compile(etsg); + etsg->ApplyConversion(binExpr->Left(), binExpr->OperationType()); + etsg->BranchIfFalse(binExpr, falseLabel); + + binExpr->Right()->Compile(etsg); + etsg->ApplyConversion(binExpr->Right(), binExpr->OperationType()); + etsg->BranchIfFalse(binExpr, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + auto *endLabel = etsg->AllocLabel(); + + binExpr->Left()->Compile(etsg); + etsg->ApplyConversion(binExpr->Left(), binExpr->OperationType()); + etsg->BranchIfTrue(binExpr, endLabel); + + binExpr->Right()->Compile(etsg); + etsg->ApplyConversion(binExpr->Right(), binExpr->OperationType()); + etsg->BranchIfFalse(binExpr, falseLabel); + etsg->SetLabel(binExpr, endLabel); + return; + } + default: { + break; + } + } + } else if (expr->IsUnaryExpression() && + expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { + expr->AsUnaryExpression()->Argument()->Compile(etsg); + etsg->ApplyConversion(expr->AsUnaryExpression()->Argument(), etsg->Checker()->GlobalETSBooleanType()); + etsg->BranchIfTrue(expr, falseLabel); + return; + } + + // TODO(user): Handle implicit bool conversion: not zero int == true, not null obj ref == true, otherwise false + ASSERT(expr->TsType()->IsETSBooleanType() || + (expr->TsType()->IsETSObjectType() && + expr->TsType()->AsETSObjectType()->HasObjectFlag( + checker::ETSObjectFlags::BUILTIN_BOOLEAN))); // already checked by checker::CheckTruthinessOfType() + expr->Compile(etsg); + etsg->ApplyConversion(expr, etsg->Checker()->GlobalETSBooleanType()); + etsg->BranchIfFalse(expr, falseLabel); +} } // namespace panda::es2panda::compiler diff --git a/compiler/base/condition.h b/compiler/base/condition.h index c7d8e655d..c969d1047 100644 --- a/compiler/base/condition.h +++ b/compiler/base/condition.h @@ -20,13 +20,22 @@ namespace panda::es2panda::compiler { class PandaGen; +class ETSGen; class Label; class Condition { public: Condition() = delete; + enum class Result { + CONST_TRUE, + CONST_FALSE, + UNKNOWN, + }; + static void Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel); + static void Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLabel); + static Result CheckConstantExpr(const ir::Expression *expr); }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/destructuring.cpp b/compiler/base/destructuring.cpp index ea61f4d3d..694faf5c2 100644 --- a/compiler/base/destructuring.cpp +++ b/compiler/base/destructuring.cpp @@ -40,7 +40,7 @@ static void GenRestElement(PandaGen *pg, const ir::SpreadElement *restElement, DestructuringRestIterator iterator(destIterator); // create left reference for rest element - LReference lref = LReference::CreateLRef(pg, restElement, isDeclaration); + auto lref = JSLReference::Create(pg, restElement, isDeclaration); // create an empty array first pg->CreateEmptyArray(restElement); @@ -104,7 +104,7 @@ static void GenArray(PandaGen *pg, const ir::ArrayExpression *array) init = element->AsAssignmentPattern()->Right(); } - LReference lref = LReference::CreateLRef(pg, target, array->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, array->IsDeclaration()); iterator.Step(); if (init != nullptr) { @@ -192,7 +192,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, for (const auto *element : properties) { if (element->IsRestElement()) { RegScope restScope(pg); - LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, element, object->IsDeclaration()); pg->CreateObjectWithExcludedKeys(element, rhs, propStart, properties.size() - 1); lref.SetValue(); break; @@ -214,7 +214,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, pg->StoreAccumulator(key, propReg); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); pg->LoadAccumulator(element, propReg); pg->LoadObjByValue(element, rhs); @@ -252,7 +252,7 @@ static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs Operand propOperand = pg->ToOwnPropertyKey(key, propExpr->IsComputed()); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); if (std::holds_alternative(propOperand)) { pg->LoadAccumulator(element, std::get(propOperand)); diff --git a/compiler/base/literals.h b/compiler/base/literals.h index 9534b8305..a1e30e6c3 100644 --- a/compiler/base/literals.h +++ b/compiler/base/literals.h @@ -27,7 +27,7 @@ class TaggedTemplateExpression; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -class Checker; +class TSChecker; class Type; } // namespace panda::es2panda::checker @@ -54,7 +54,6 @@ enum class LiteralTag { class Literal { public: explicit Literal() = default; - ~Literal() = default; explicit Literal(LiteralTag tag, const util::StringView &str) : tag_(tag), value_(str.Mutf8()) {} explicit Literal(const util::StringView &str) : tag_(LiteralTag::STRING), value_(str.Mutf8()) {} @@ -64,6 +63,7 @@ public: DEFAULT_COPY_SEMANTIC(Literal); DEFAULT_MOVE_SEMANTIC(Literal); + ~Literal() = default; static Literal NullLiteral() { diff --git a/compiler/base/lreference.cpp b/compiler/base/lreference.cpp index 0f2e0b36f..1baed6a79 100644 --- a/compiler/base/lreference.cpp +++ b/compiler/base/lreference.cpp @@ -19,7 +19,10 @@ #include "plugins/ecmascript/es2panda/compiler/base/destructuring.h" #include "plugins/ecmascript/es2panda/compiler/core/function.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" @@ -28,66 +31,104 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" namespace panda::es2panda::compiler { -// LReference -LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res) - : node_(node), pg_(pg), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) +LReference::LReferenceBase LReference::CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) { - if (refKind_ != ReferenceKind::MEMBER) { + switch (node->Type()) { + case ir::AstNodeType::IDENTIFIER: { + const util::StringView &name = node->AsIdentifier()->Name(); + binder::ScopeFindResult res = cg->Scope()->Find(name, binder::ResolveBindingOptions::ALL); + + if (res.variable == nullptr) { + res.variable = node->AsIdentifier()->Variable(); + } + + return {cg, node, ReferenceKind::VAR_OR_GLOBAL, res, isDeclaration}; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + return {cg, node, ReferenceKind::MEMBER, {}, false}; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); + return CreateBase(cg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + } + case ir::AstNodeType::VARIABLE_DECLARATOR: { + return CreateBase(cg, node->AsVariableDeclarator()->Id(), true); + } + case ir::AstNodeType::ARRAY_PATTERN: + case ir::AstNodeType::OBJECT_PATTERN: { + return {cg, node, ReferenceKind::DESTRUCTURING, {}, isDeclaration}; + } + case ir::AstNodeType::ASSIGNMENT_PATTERN: { + return CreateBase(cg, node->AsAssignmentPattern()->Left(), true); + } + case ir::AstNodeType::REST_ELEMENT: { + return CreateBase(cg, node->AsRestElement()->Argument(), true); + } + default: { + UNREACHABLE(); + } + } +} + +JSLReference::JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), pg_(static_cast(cg)) +{ + if (Kind() != ReferenceKind::MEMBER) { return; } - const auto *memberExpr = node_->AsMemberExpression(); + const auto *memberExpr = Node()->AsMemberExpression(); if (memberExpr->Object()->IsSuperExpression()) { - refKind_ = ReferenceKind::SUPER; + SetKind(ReferenceKind::SUPER); } else if (memberExpr->IsPrivateReference()) { - refKind_ = ReferenceKind::PRIVATE; + SetKind(ReferenceKind::PRIVATE); privateCtor_ = pg_->AllocReg(); - Function::LoadClassContexts(node_, pg_, privateCtor_, memberExpr->Property()->AsIdentifier()->Name()); + Function::LoadClassContexts(Node(), pg_, privateCtor_, memberExpr->Property()->AsIdentifier()->Name()); } obj_ = pg_->AllocReg(); memberExpr->Object()->Compile(pg_); - pg->StoreAccumulator(node_, obj_); + pg_->StoreAccumulator(Node(), obj_); prop_ = pg_->ToNamedPropertyKey(memberExpr->Property(), memberExpr->IsComputed()); if (std::holds_alternative(prop_)) { return; } - if (std::holds_alternative(prop_) && refKind_ != ReferenceKind::SUPER) { + if (std::holds_alternative(prop_) && Kind() != ReferenceKind::SUPER) { return; } memberExpr->Property()->Compile(pg_); VReg propReg = pg_->AllocReg(); - pg_->StoreAccumulator(node_, propReg); + pg_->StoreAccumulator(Node(), propReg); prop_ = propReg; } -void LReference::GetValue() +void JSLReference::GetValue() const { - switch (refKind_) { + switch (Kind()) { case ReferenceKind::VAR_OR_GLOBAL: { - pg_->LoadVar(node_->AsIdentifier(), res_); + pg_->LoadVar(Node()->AsIdentifier(), Result()); break; } case ReferenceKind::MEMBER: { if (std::holds_alternative(prop_)) { - pg_->LoadObjProperty(node_, obj_); + pg_->LoadObjProperty(Node(), obj_); break; } [[fallthrough]]; } case ReferenceKind::SUPER: { - pg_->LoadObjProperty(node_, prop_); + pg_->LoadObjProperty(Node(), prop_); break; } case ReferenceKind::PRIVATE: { - pg_->ClassPrivateFieldGet(node_, privateCtor_, obj_, std::get(prop_)); + pg_->ClassPrivateFieldGet(Node(), privateCtor_, obj_, std::get(prop_)); break; } default: { @@ -96,29 +137,29 @@ void LReference::GetValue() } } -void LReference::SetValue() +void JSLReference::SetValue() const { - switch (refKind_) { + switch (Kind()) { case ReferenceKind::VAR_OR_GLOBAL: { - pg_->StoreVar(node_, res_, isDeclaration_); + pg_->StoreVar(Node(), Result(), IsDeclaration()); break; } case ReferenceKind::SUPER: { - pg_->StoreSuperProperty(node_, obj_, prop_); + pg_->StoreSuperProperty(Node(), obj_, prop_); break; } case ReferenceKind::MEMBER: { - pg_->StoreObjProperty(node_, obj_, prop_); + pg_->StoreObjProperty(Node(), obj_, prop_); break; } case ReferenceKind::PRIVATE: { - pg_->ClassPrivateFieldSet(node_, privateCtor_, obj_, std::get(prop_)); + pg_->ClassPrivateFieldSet(Node(), privateCtor_, obj_, std::get(prop_)); break; } case ReferenceKind::DESTRUCTURING: { - Destructuring::Compile(pg_, node_->AsExpression()); + Destructuring::Compile(pg_, Node()->AsExpression()); break; } default: { @@ -127,48 +168,106 @@ void LReference::SetValue() } } -ReferenceKind LReference::Kind() const +ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), etsg_(static_cast(cg)) { - return refKind_; -} + if (Kind() != ReferenceKind::MEMBER) { + SetKind(ResolveReferenceKind(res.variable)); + return; + } -binder::Variable *LReference::Variable() const -{ - return res_.variable; + const auto *memberExpr = Node()->AsMemberExpression(); + staticObjRef_ = memberExpr->Object()->TsType(); + + if (!memberExpr->IsComputed() && memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + return; + } + + TargetTypeContext ttctx(etsg_, memberExpr->Object()->TsType()); + memberExpr->Object()->Compile(etsg_); + baseReg_ = etsg_->AllocReg(); + etsg_->StoreAccumulator(node, baseReg_); + + if (memberExpr->IsComputed()) { + TargetTypeContext pttctx(etsg_, memberExpr->Property()->TsType()); + memberExpr->Property()->Compile(etsg_); + propReg_ = etsg_->AllocReg(); + etsg_->ApplyConversionAndStoreAccumulator(node, propReg_, memberExpr->GetUnboxedPropertyType()); + } } -LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration) +ReferenceKind ETSLReference::ResolveReferenceKind(const binder::Variable *variable) { - switch (node->Type()) { - case ir::AstNodeType::IDENTIFIER: { - const util::StringView &name = node->AsIdentifier()->Name(); - binder::ScopeFindResult res = pg->Scope()->Find(name); + if (variable->HasFlag(binder::VariableFlags::SYNTHETIC)) { + return ReferenceKind::METHOD; + } + + auto *declNode = variable->Declaration()->Node(); - return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res}; + switch (declNode->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + auto *classField = declNode->AsClassProperty(); + return classField->IsStatic() ? ReferenceKind::STATIC_FIELD : ReferenceKind::FIELD; } - case ir::AstNodeType::MEMBER_EXPRESSION: { - return {node, pg, false, ReferenceKind::MEMBER, {}}; + case ir::AstNodeType::CLASS_DEFINITION: { + auto *classDef = declNode->AsClassDefinition(); + return classDef->IsStatic() ? ReferenceKind::STATIC_CLASS : ReferenceKind::CLASS; } - case ir::AstNodeType::VARIABLE_DECLARATION: { - ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); - return LReference::CreateLRef(pg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + case ir::AstNodeType::METHOD_DEFINITION: { + return ReferenceKind::METHOD; } - case ir::AstNodeType::VARIABLE_DECLARATOR: { - return LReference::CreateLRef(pg, node->AsVariableDeclarator()->Id(), true); + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { } - case ir::AstNodeType::ARRAY_PATTERN: - case ir::AstNodeType::OBJECT_PATTERN: { - return {node, pg, isDeclaration, ReferenceKind::DESTRUCTURING, {}}; + default: { + break; } - case ir::AstNodeType::ASSIGNMENT_PATTERN: { - return LReference::CreateLRef(pg, node->AsAssignmentPattern()->Left(), true); + } + + return ReferenceKind::LOCAL; +} + +void ETSLReference::GetValue() const +{ + switch (Kind()) { + case ReferenceKind::MEMBER: { + Node()->AsMemberExpression()->Compile(etsg_); + break; } - case ir::AstNodeType::REST_ELEMENT: { - return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), true); + default: { + etsg_->LoadVar(Node()->AsIdentifier(), Variable()); + break; + } + } +} + +void ETSLReference::SetValue() const +{ + switch (Kind()) { + case ReferenceKind::MEMBER: { + auto *memberExpr = Node()->AsMemberExpression(); + etsg_->ApplyConversion(Node(), memberExpr->TsType()); + + if (memberExpr->IsComputed()) { + etsg_->StoreArrayElement(Node(), baseReg_, propReg_); + break; + } + + auto &propName = memberExpr->Property()->AsIdentifier()->Name(); + if (memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + util::StringView fullName = etsg_->FormClassPropReference(staticObjRef_->AsETSObjectType(), propName); + etsg_->StoreStaticProperty(Node(), memberExpr->TsType(), fullName); + break; + } + + etsg_->StoreProperty(Node(), memberExpr->TsType(), baseReg_, propName); + break; } default: { - UNREACHABLE(); + etsg_->StoreVar(Node()->AsIdentifier(), Result()); + break; } } } + } // namespace panda::es2panda::compiler diff --git a/compiler/base/lreference.h b/compiler/base/lreference.h index 0df234059..54e6a3e59 100644 --- a/compiler/base/lreference.h +++ b/compiler/base/lreference.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_BASE_LREFERENCE_H -#define ES2PANDA_COMPILER_BASE_LREFERENCE_H +#ifndef ES2PANDA_COMPILER_BASE_JSLREFERENCE_H +#define ES2PANDA_COMPILER_BASE_JSLREFERENCE_H #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -23,6 +23,10 @@ namespace panda::es2panda::ir { class AstNode; } // namespace panda::es2panda::ir +namespace panda::es2panda::checker { +class ETSObjectType; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { enum class ReferenceKind { MEMBER, @@ -30,34 +34,122 @@ enum class ReferenceKind { SUPER, VAR_OR_GLOBAL, DESTRUCTURING, + LOCAL, + STATIC_FIELD, + FIELD, + CLASS, + STATIC_CLASS, + METHOD, + STATIC_METHOD, }; +class CodeGen; +class ETSGen; class PandaGen; class LReference { public: - LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res); ~LReference() = default; NO_COPY_SEMANTIC(LReference); - NO_MOVE_SEMANTIC(LReference); + DEFAULT_MOVE_SEMANTIC(LReference); + + ReferenceKind Kind() const + { + return refKind_; + } + + void SetKind(ReferenceKind refKind) + { + refKind_ = refKind; + } + + binder::Variable *Variable() const + { + return res_.variable; + } + + const ir::AstNode *Node() const + { + return node_; + } + + binder::ScopeFindResult &Result() + { + return res_; + } + + const binder::ScopeFindResult &Result() const + { + return res_; + } - void GetValue(); - void SetValue(); - binder::Variable *Variable() const; - ReferenceKind Kind() const; + bool IsDeclaration() const + { + return isDeclaration_; + } - static LReference CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration); +protected: + using LReferenceBase = std::tuple; + static LReferenceBase CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration); + + explicit LReference(const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, bool isDeclaration) + : node_(node), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) + { + } private: const ir::AstNode *node_; - PandaGen *pg_; ReferenceKind refKind_; binder::ScopeFindResult res_; + bool isDeclaration_; +}; + +class JSLReference : public LReference { +public: + JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~JSLReference() = default; + NO_COPY_SEMANTIC(JSLReference); + NO_MOVE_SEMANTIC(JSLReference); + + void GetValue() const; + void SetValue() const; + + static JSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + +private: + PandaGen *pg_; VReg obj_; VReg privateCtor_ {}; Operand prop_; - bool isDeclaration_; +}; + +class ETSLReference : public LReference { +public: + ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~ETSLReference() = default; + NO_COPY_SEMANTIC(ETSLReference); + NO_MOVE_SEMANTIC(ETSLReference); + + void GetValue() const; + void SetValue() const; + + static ETSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + + static ReferenceKind ResolveReferenceKind(const binder::Variable *variable); + +private: + ETSGen *etsg_; + const checker::Type *staticObjRef_ {}; + VReg baseReg_ {}; + VReg propReg_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/optionalChain.cpp b/compiler/base/optionalChain.cpp index c9cec7519..e115517dd 100644 --- a/compiler/base/optionalChain.cpp +++ b/compiler/base/optionalChain.cpp @@ -40,7 +40,7 @@ void OptionalChain::Check(compiler::VReg obj) RegScope rs(pg_); - if (obj == INVALID_VREG) { + if (obj.IsInvalid()) { obj = pg_->AllocReg(); pg_->StoreAccumulator(node_, obj); } diff --git a/compiler/core/ETSGen.cpp b/compiler/core/ETSGen.cpp new file mode 100644 index 000000000..436486331 --- /dev/null +++ b/compiler/core/ETSGen.cpp @@ -0,0 +1,1305 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ETSGen.h" + +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/statement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/deferStatement.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::compiler { + +const checker::ETSChecker *ETSGen::Checker() const +{ + return Context()->Checker()->AsETSChecker(); +} + +const checker::Type *ETSGen::ReturnType() const +{ + return RootNode()->AsScriptFunction()->Signature()->ReturnType(); +} + +void ETSGen::ApplyConversionAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType) +{ + ApplyConversion(node, targetType); + StoreAccumulator(node, vreg); +} + +VReg ETSGen::StoreException(const ir::AstNode *node) +{ + VReg exception = AllocReg(); + Ra().Emit(node, exception); + + acc_.SetType(Checker()->GlobalBuiltinExceptionType()); + exception.SetType(acc_.GetType()); + return exception; +} + +void ETSGen::StoreAccumulator(const ir::AstNode *node, VReg &vreg) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Ra().Emit(node, vreg); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Ra().Emit(node, vreg); + } else { + Ra().Emit(node, vreg); + } + + vreg.SetType(acc_.GetType()); +} + +void ETSGen::LoadAccumulator(const ir::AstNode *node, VReg vreg) +{ + if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Ra().Emit(node, vreg); + } else if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Ra().Emit(node, vreg); + } else { + Ra().Emit(node, vreg); + } + + acc_.SetType(vreg.GetType()); +} + +void ETSGen::MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs) +{ + if (vs.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Ra().Emit(node, vd, vs); + } else if (vs.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Ra().Emit(node, vd, vs); + } else { + Ra().Emit(node, vd, vs); + } + + vd.SetType(vs.GetType()); +} + +void ETSGen::LoadVar(const ir::AstNode *node, binder::Variable *var) +{ + auto *local = var->AsLocalVariable(); + + switch (ETSLReference::ResolveReferenceKind(var)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(var); + LoadStaticProperty(node, var->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + LoadProperty(node, var->TsType(), GetThisReg(), var->Name()); + break; + } + case ReferenceKind::METHOD: + case ReferenceKind::STATIC_METHOD: + case ReferenceKind::CLASS: + case ReferenceKind::STATIC_CLASS: { + acc_.SetType(var->TsType()); + break; + } + case ReferenceKind::LOCAL: { + LoadAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } + + if (targetType_ != nullptr) { + ApplyConversion(node, targetType_); + } +} + +void ETSGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result) +{ + auto *local = result.variable->AsLocalVariable(); + ApplyConversion(node, local->TsType()); + + switch (ETSLReference::ResolveReferenceKind(result.variable)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(result.variable); + StoreStaticProperty(node, result.variable->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + StoreProperty(node, result.variable->TsType(), GetThisReg(), result.name); + break; + } + case ReferenceKind::LOCAL: { + StoreAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name) +{ + std::stringstream ss; + ss << classType->AssemblerName() << '.' << name; + auto res = ProgElement()->Strings().emplace(ss.str()); + + return util::StringView(*res.first); +} + +util::StringView ETSGen::FormClassPropReference(binder::Variable *var) +{ + auto containingObjectType = util::Helpers::GetContainingObjectType(var->Declaration()->Node()); + return FormClassPropReference(containingObjectType, var->Name()); +} + +void ETSGen::StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(containingObjectType_, name); + StoreStaticProperty(node, propType, fullName); +} + +void ETSGen::StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Sa().Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Sa().Emit(node, fullName); + } else { + Sa().Emit(node, fullName); + } +} + +void ETSGen::LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Sa().Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Sa().Emit(node, fullName); + } else { + Sa().Emit(node, fullName); + } + + acc_.SetType(propType); +} + +void ETSGen::StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsETSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Ra().Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Ra().Emit(node, objReg, fullName); + } else { + Ra().Emit(node, objReg, fullName); + } +} + +void ETSGen::LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsETSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Ra().Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Ra().Emit(node, objReg, fullName); + } else { + Ra().Emit(node, objReg, fullName); + } + + acc_.SetType(propType); +} + +void ETSGen::LoadThis(const ir::AstNode *node) +{ + LoadAccumulator(node, GetThisReg()); +} + +VReg &ETSGen::GetThisReg() +{ + binder::ScopeFindResult res = Scope()->Find(binder::Binder::MANDATORY_PARAM_THIS); + return res.variable->AsLocalVariable()->Vreg(); +} + +void ETSGen::LoadDefaultValue([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const checker::Type *type) +{ + if (type->IsETSObjectType() || type->IsETSArrayType()) { + LoadAccumulatorNull(node, type); + } else if (type->IsETSBooleanType()) { + LoadAccumulatorBoolean(node, type->AsETSBooleanType()->GetValue()); + } else { + auto ttctx = TargetTypeContext(this, type); + LoadAccumulatorInt(node, 0); + } +} + +void ETSGen::EmitReturnVoid(const ir::AstNode *node) +{ + Sa().Emit(node); +} + +void ETSGen::ReturnAcc(const ir::AstNode *node) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + Sa().Emit(node); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + Sa().Emit(node); + } else { + Sa().Emit(node); + } +} + +bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) +{ + const auto *type = node->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return false; + } + + auto typeKind = checker::ETSChecker::TypeKind(type); + + switch (typeKind) { + case checker::TypeFlag::CHAR: { + LoadAccumulatorChar(node, type->AsCharType()->GetValue()); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: { + LoadAccumulatorBoolean(node, type->AsETSBooleanType()->GetValue()); + break; + } + case checker::TypeFlag::BYTE: { + LoadAccumulatorByte(node, type->AsByteType()->GetValue()); + break; + } + case checker::TypeFlag::SHORT: { + LoadAccumulatorShort(node, type->AsShortType()->GetValue()); + break; + } + case checker::TypeFlag::INT: { + LoadAccumulatorInt(node, type->AsIntType()->GetValue()); + break; + } + case checker::TypeFlag::LONG: { + LoadAccumulatorWideInt(node, type->AsLongType()->GetValue()); + break; + } + case checker::TypeFlag::FLOAT: { + LoadAccumulatorFloat(node, type->AsFloatType()->GetValue()); + break; + } + case checker::TypeFlag::DOUBLE: { + LoadAccumulatorDouble(node, type->AsDoubleType()->GetValue()); + break; + } + case checker::TypeFlag::ETS_OBJECT: { + LoadAccumulatorString(node, type->AsETSObjectType()->AsETSStringType()->GetValue()); + break; + } + default: { + UNREACHABLE(); + } + } + + return true; +} + +void ETSGen::ApplyConversion(const ir::AstNode *node, const checker::Type *targetType) +{ + auto ttctx = TargetTypeContext(this, targetType); + + auto typeKind = checker::ETSChecker::TypeKind(targetType); + + auto sourceType = acc_.GetType(); + + if (sourceType->IsETSObjectType() && + sourceType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::UNBOXABLE_TYPE) && + targetType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + EmitUnboxingConversion(node, targetType, typeKind); + return; + } + + if (sourceType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && targetType->IsETSObjectType() && + targetType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::UNBOXABLE_TYPE)) { + EmitBoxingConversion(node, targetType, sourceType); + return; + } + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + CastToDouble(node); + break; + } + case checker::TypeFlag::FLOAT: { + CastToFloat(node); + break; + } + case checker::TypeFlag::LONG: { + CastToLong(node); + break; + } + default: { + break; + } + } +} + +void ETSGen::EmitUnboxingConversion(const ir::AstNode *node, const checker::Type *targetType, + checker::TypeFlag typeKind) +{ + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: { + Ra().Emit(node, Signatures::BUILTIN_BOOLEAN_BOOLEAN_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::BYTE: { + Ra().Emit(node, Signatures::BUILTIN_BYTE_BYTE_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::CHAR: { + Ra().Emit(node, Signatures::BUILTIN_CHAR_CHAR_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::SHORT: { + Ra().Emit(node, Signatures::BUILTIN_SHORT_SHORT_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::INT: { + Ra().Emit(node, Signatures::BUILTIN_INT_INT_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::LONG: { + Ra().Emit(node, Signatures::BUILTIN_LONG_LONG_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::FLOAT: { + Ra().Emit(node, Signatures::BUILTIN_FLOAT_FLOAT_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::DOUBLE: { + Ra().Emit(node, Signatures::BUILTIN_DOUBLE_DOUBLE_VALUE, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::EmitBoxingConversion(const ir::AstNode *node, const checker::Type *targetType, + const checker::Type *sourceType) +{ + auto sourceTypeKind = checker::ETSChecker::TypeKind(sourceType); + switch (sourceTypeKind) { + case checker::TypeFlag::ETS_BOOLEAN: { + Ra().Emit(node, Signatures::BUILTIN_BOOLEAN_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::BYTE: { + Ra().Emit(node, Signatures::BUILTIN_BYTE_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::CHAR: { + Ra().Emit(node, Signatures::BUILTIN_CHAR_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::SHORT: { + Ra().Emit(node, Signatures::BUILTIN_SHORT_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::INT: { + Ra().Emit(node, Signatures::BUILTIN_INT_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::LONG: { + Ra().Emit(node, Signatures::BUILTIN_LONG_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::FLOAT: { + Ra().Emit(node, Signatures::BUILTIN_FLOAT_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + case checker::TypeFlag::DOUBLE: { + Ra().Emit(node, Signatures::BUILTIN_DOUBLE_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs) +{ + RegScope rs(this); + auto tmp = AllocReg(); + + StoreAccumulator(node, tmp); + LoadAccumulator(node, lhs); + MoveVreg(node, lhs, tmp); +} + +void ETSGen::CastToBoolean([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); +} + +void ETSGen::CastToByte([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: { + return; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalByteType()); +} + +void ETSGen::CastToChar([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::INT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalCharType()); +} + +void ETSGen::CastToShort([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + return; + } + case checker::TypeFlag::INT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalShortType()); +} + +void ETSGen::CastToDouble(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + return; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalDoubleType()); +} + +void ETSGen::CastToFloat(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + return; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalFloatType()); +} + +void ETSGen::CastToLong(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::LONG: { + return; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalLongType()); +} + +void ETSGen::CastToInt(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalIntType()); +} + +void ETSGen::ToBinaryResult(const ir::AstNode *node, Label *ifFalse) +{ + Label *end = AllocLabel(); + Sa().Emit(node, 1); + Sa().Emit(node, end); + SetLabel(node, ifFalse); + Sa().Emit(node, 0); + SetLabel(node, end); +} + +void ETSGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) +{ + ApplyConversion(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + IsInstance(node, lhs.GetType()->AsETSObjectType()->AssemblerName()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) +{ + ApplyConversion(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + Sa().Emit(node, lhs.GetType()->AsETSObjectType()->AssemblerName()); + BranchIfFalse(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::EmitNullPointerException(const ir::AstNode *node) +{ + VReg exception = StoreException(node); + NewObject(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION); + CallThisStatic0(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION_CTOR); + EmitThrow(node, exception); +} + +void ETSGen::CompileStatements(const ArenaVector &statements) +{ + for (const auto *stmt : statements) { + stmt->Compile(this); + } +} + +void ETSGen::CompileDeferStatements(const ArenaVector &statements) +{ + for (auto it = statements.crbegin(); it != statements.crend(); it++) { + auto *stmt = *it; + if (!stmt->IsDeferStatement()) { + continue; + } + stmt->AsDeferStatement()->Stmt()->Compile(this); + } +} + +void ETSGen::CompileStatementList(const ArenaVector &statements) +{ + if (!Scope()->HasFlag(binder::ScopeFlags::DEFER_STMT)) { + CompileStatements(statements); + return; + } + + ASSERT(!statements.empty()); + auto *node = statements.front(); + + TrapContext trapCtx(this); + const auto &labelSet = trapCtx.LabelSet(); + + SetLabel(node, labelSet.TryBegin()); + CompileStatements(statements); + CompileDeferStatements(statements); + SetLabel(node, labelSet.TryEnd()); + Branch(node, labelSet.CatchEnd()); + + SetLabel(node, labelSet.CatchBegin()); + VReg exception = StoreException(node); + CompileDeferStatements(statements); + EmitThrow(node, exception); + SetLabel(node, labelSet.CatchEnd()); +} + +void ETSGen::Negate(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + + switch (typeKind) { + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::INT: { + Sa().Emit(node); + return; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::LogicalNot(const ir::AstNode *node) +{ + ASSERT(acc_.GetType()->IsETSBooleanType()); + Sa().Emit(node); + Sa().Emit(node, 1); +} + +void ETSGen::Unary(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS: { + break; // NOP -> Unary numeric promotion is performed + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + UnaryMinus(node); + break; + } + case lexer::TokenType::PUNCTUATOR_TILDE: { + UnaryTilde(node); + break; + } + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { + LogicalNot(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::UnaryMinus(const ir::AstNode *node) +{ + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::UnaryTilde(const ir::AstNode *node) +{ + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + Sa().Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::Update(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { + UpdateOperator(node); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { + UpdateOperator(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) +{ + RegScope rs(this); + util::StringView signature {}; + + node->Compile(this); + + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::ETS_BOOLEAN: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BOOLEAN; + break; + } + case checker::TypeFlag::CHAR: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_CHAR; + break; + } + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::INT: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_INT; + break; + } + case checker::TypeFlag::LONG: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_LONG; + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node); + [[fallthrough]]; + } + case checker::TypeFlag::DOUBLE: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_DOUBLE; + break; + } + default: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BUILTIN_STRING; + break; + } + } + + if (acc_.GetType()->IsETSObjectType() && !acc_.GetType()->IsETSStringType()) { + Ra().Emit(node, Signatures::BUILTIN_OBJECT_TO_STRING, VReg::RegStart(), 0); + } + + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + + CallThisStatic1(node, builder, signature, arg0); +} + +void ETSGen::AppendString(const ir::Expression *expr, VReg &builder) +{ + ASSERT((expr->IsBinaryExpression() && + expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) || + (expr->IsAssignmentExpression() && + expr->AsAssignmentExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS_EQUAL)); + + if (expr->IsBinaryExpression()) { + StringBuilder(expr->AsBinaryExpression()->Left(), expr->AsBinaryExpression()->Right(), builder); + } else { + StringBuilder(expr->AsAssignmentExpression()->Left(), expr->AsAssignmentExpression()->Right(), builder); + } +} + +void ETSGen::StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg &builder) +{ + if (left->IsBinaryExpression()) { + AppendString(left->AsBinaryExpression(), builder); + } else { + StringBuilderAppend(left, builder); + } + + StringBuilderAppend(right, builder); +} + +void ETSGen::BuildString(const ir::Expression *node) +{ + RegScope rs(this); + VReg builder = AllocReg(); + + Sa().Emit(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, VReg::RegStart(), VReg::RegStart()); + StoreAccumulator(node, builder); + + AppendString(node, builder); + CallThisStatic0(node, builder, Signatures::BUILTIN_STRING_BUILDER_TO_STRING); + + acc_.SetType(Checker()->GlobalETSStringLiteralType()); +} + +void ETSGen::NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name) +{ + Ra().Emit(node, ctor, name); +} + +void ETSGen::NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType) +{ + std::stringstream ss; + arrType->ToAssemblerTypeWithRank(ss); + auto res = ProgElement()->Strings().emplace(ss.str()); + + Ra().Emit(node, arr, dim, util::StringView(*res.first)); +} + +void ETSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg) +{ + Ra().Emit(node, arrayReg); + acc_.SetType(Checker()->GlobalIntType()); +} + +void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg) +{ + auto *elementType = objectReg.GetType()->AsETSArrayType()->ElementType(); + + switch (checker::ETSChecker::ETSType(elementType)) { + case checker::TypeFlag::BYTE: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::INT: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::LONG: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::FLOAT: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::DOUBLE: { + Ra().Emit(node, objectReg); + break; + } + case checker::TypeFlag::ETS_ARRAY: + case checker::TypeFlag::ETS_OBJECT: { + Ra().Emit(node, objectReg); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void ETSGen::StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index) +{ + auto *elementType = objectReg.GetType()->AsETSArrayType()->ElementType(); + + switch (checker::ETSChecker::ETSType(elementType)) { + case checker::TypeFlag::BYTE: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::INT: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::LONG: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::FLOAT: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::DOUBLE: { + Ra().Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::ETS_ARRAY: + case checker::TypeFlag::ETS_OBJECT: { + Ra().Emit(node, objectReg, index); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void ETSGen::ThrowException(const ir::Expression *expr) +{ + RegScope rs(this); + + expr->Compile(this); + VReg arg = AllocReg(); + StoreAccumulator(expr, arg); + EmitThrow(expr, arg); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSGen.h b/compiler/core/ETSGen.h new file mode 100644 index 000000000..43f72693f --- /dev/null +++ b/compiler/core/ETSGen.h @@ -0,0 +1,670 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETSGEN_H +#define ES2PANDA_COMPILER_CORE_ETSGEN_H + +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSfunction.h" +#include "plugins/ecmascript/es2panda/compiler/core/targetTypeContext.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::compiler { + +class ETSGen : public CodeGen { +public: + explicit ETSGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement), + containingObjectType_(util::Helpers::GetContainingObjectType(RootNode())) + { + ETSFunction::Compile(this); + } + + const checker::ETSChecker *Checker() const; + const checker::Type *ReturnType() const; + + const checker::ETSObjectType *ContainingObjectType() const + { + return containingObjectType_; + } + + VReg &Acc() + { + return acc_; + } + + const VReg &Acc() const + { + return acc_; + } + + VReg StoreException(const ir::AstNode *node); + void ApplyConversionAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType); + void StoreAccumulator(const ir::AstNode *node, VReg &vreg); + void LoadAccumulator(const ir::AstNode *node, VReg vreg); + void MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs); + + void LoadVar(const ir::AstNode *node, binder::Variable *var); + void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result); + + void LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + void StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + + void StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &name); + util::StringView FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name); + + void StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + void LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + + void LoadThis(const ir::AstNode *node); + VReg &GetThisReg(); + + void LoadDefaultValue(const ir::AstNode *node, const checker::Type *type); + void EmitReturnVoid(const ir::AstNode *node); + void ReturnAcc(const ir::AstNode *node); + + void IsInstance(const ir::AstNode *node, util::StringView name) + { + Sa().Emit(node, name); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); + void Unary(const ir::AstNode *node, lexer::TokenType op); + void Update(const ir::AstNode *node, lexer::TokenType op); + + bool TryLoadConstantExpression(const ir::Expression *node); + void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse); + + void BranchIfFalse(const ir::AstNode *node, Label *ifFalse) + { + Sa().Emit(node, ifFalse); + } + + void BranchIfTrue(const ir::AstNode *node, Label *ifFalse) + { + Sa().Emit(node, ifFalse); + } + + void EmitThrow(const ir::AstNode *node, VReg err) + { + Ra().Emit(node, err); + } + + void EmitNullPointerException(const ir::AstNode *node); + + void ThrowException(const ir::Expression *expr); + + void Negate(const ir::AstNode *node); + void LogicalNot(const ir::AstNode *node); + + void LoadAccumulatorByte(const ir::AstNode *node, int8_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::BYTE); + } + + void LoadAccumulatorShort(const ir::AstNode *node, int16_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::SHORT); + } + + void LoadAccumulatorInt(const ir::AstNode *node, int32_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::INT); + } + + void LoadAccumulatorWideInt(const ir::AstNode *node, int64_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::LONG); + } + + void LoadAccumulatorFloat(const ir::AstNode *node, float number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::FLOAT); + } + + void LoadAccumulatorDouble(const ir::AstNode *node, double number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::DOUBLE); + } + + void LoadAccumulatorBoolean(const ir::AstNode *node, bool value) + { + auto typeKind = + targetType_ != nullptr ? checker::ETSChecker::TypeKind(targetType_) : checker::TypeFlag::ETS_BOOLEAN; + Sa().Emit(node, value ? 1 : 0); + if (typeKind == checker::TypeFlag::ETS_OBJECT && + targetType_->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_BOOLEAN)) { + Ra().Emit(node, Signatures::BUILTIN_BOOLEAN_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType_); + } else { + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + } + + void LoadAccumulatorString(const ir::AstNode *node, util::StringView str) + { + Sa().Emit(node, str); + acc_.SetType(Checker()->GlobalETSStringLiteralType()); + } + + void LoadAccumulatorNull(const ir::AstNode *node, const checker::Type *type) + { + Sa().Emit(node); + acc_.SetType(type); + } + + void LoadAccumulatorChar(const ir::AstNode *node, char16_t value) + { + auto typeKind = targetType_ != nullptr ? checker::ETSChecker::TypeKind(targetType_) : checker::TypeFlag::CHAR; + Sa().Emit(node, value); + if (typeKind == checker::TypeFlag::ETS_OBJECT && + targetType_->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_CHAR)) { + Ra().Emit(node, Signatures::BUILTIN_CHAR_VALUE_OF, VReg::RegStart(), 0); + acc_.SetType(targetType_); + } else { + acc_.SetType(Checker()->GlobalCharType()); + } + } + + void ApplyConversion(const ir::AstNode *node) + { + if (targetType_ != nullptr) { + ApplyConversion(node, targetType_); + } + } + void ApplyConversion(const ir::AstNode *node, const checker::Type *targetType); + void EmitUnboxingConversion(const ir::AstNode *node, const checker::Type *targetType, checker::TypeFlag typeKind); + void EmitBoxingConversion(const ir::AstNode *node, const checker::Type *targetType, + const checker::Type *sourceType); + void SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs); + + void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); + void LoadArrayElement(const ir::AstNode *node, VReg objectReg); + void StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index); + + void CompileStatementList(const ArenaVector &statements); + + // Cast + void CastToBoolean(const ir::AstNode *node); + void CastToByte(const ir::AstNode *node); + void CastToChar(const ir::AstNode *node); + void CastToShort(const ir::AstNode *node); + void CastToDouble(const ir::AstNode *node); + void CastToFloat(const ir::AstNode *node); + void CastToLong(const ir::AstNode *node); + void CastToInt(const ir::AstNode *node); + + // Call, Construct + void NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType); + void NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name); + void BuildString(const ir::Expression *node); + void InitObject(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallStatic(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallThisStatic(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisVirtual(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisStatic0(const ir::AstNode *node, VReg &ctor, util::StringView name) + { + Ra().Emit(node, name, ctor, VReg::RegStart()); + } + + void CallThisStatic1(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0) + { + Ra().Emit(node, name, ctor, arg0); + } + + void CallThisStatic2(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0, VReg &arg1) + { + Ra().Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + } + + void GetType(const ir::AstNode *node, bool isETSPrimitive) + { + if (isETSPrimitive) { + // TODO(SzD) LoadStaticProperty if ETS stdlib has static TYPE constants otherwise fallback to LdaType + } else { + auto classRef = acc_.GetType()->AsETSObjectType()->AssemblerName(); + Sa().Emit(node, classRef); + } + } + + ~ETSGen() = default; + NO_COPY_SEMANTIC(ETSGen); + NO_MOVE_SEMANTIC(ETSGen); + +private: + void StringBuilderAppend(const ir::AstNode *node, VReg builder); + void AppendString(const ir::Expression *binExpr, VReg &builder); + void StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg &builder); + void CompileStatements(const ArenaVector &statements); + void CompileDeferStatements(const ArenaVector &statements); + util::StringView FormClassPropReference(binder::Variable *var); + void UnaryMinus(const ir::AstNode *node); + void UnaryTilde(const ir::AstNode *node); + + template + void StoreValueIntoArray(const ir::AstNode *node, VReg &arr, VReg &index) + { + Ra().Emit(node, arr, index); + } + + template + void UpdateOperator(const ir::AstNode *node) + { + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + RegScope scope(this); + VReg reg = AllocReg(); + Ra().Emit(node, reg, 1LL); + Ra().Emit(node, reg); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: { + Sa().Emit(node, 1); + break; + } + case checker::TypeFlag::DOUBLE: { + RegScope scope(this); + VReg reg = AllocReg(); + Ra().Emit(node, reg, 1.0); + Ra().Emit(node, reg); + break; + } + case checker::TypeFlag::FLOAT: { + RegScope scope(this); + VReg reg = AllocReg(); + Ra().Emit(node, reg, 1.0F); + Ra().Emit(node, reg); + break; + } + default: { + UNREACHABLE(); + } + } + } + + template + void BinaryEqualityObj(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + Ra().Emit(node, lhs, ifFalse); + } + + template + void BinaryNumberComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + Ra().Emit(node, lhs); + Sa().Emit(node, ifFalse); + } + + template + void BinaryEquality(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryEqualityCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryEqualityCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::ETS_OBJECT: { + ASSERT(lhs.GetType()->IsETSObjectType()); + if (lhs.GetType()->IsETSStringType()) { + RegScope rs(this); + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + CallThisStatic1(node, lhs, Signatures::BUILTIN_STRING_EQUALS, arg0); + acc_.SetType(Checker()->GlobalETSBooleanType()); + if constexpr (std::is_same_v) { + LogicalNot(node); + } + BranchIfFalse(node, ifFalse); + return; + } + + BinaryEqualityObj(node, lhs, ifFalse); + + break; + } + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Ra().Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryRelation(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryRelationCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryRelationCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Ra().Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + Ra().Emit(node, lhs); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + case checker::TypeFlag::FLOAT: { + Ra().Emit(node, lhs); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + default: { + BinaryBitwiseArithmetic(node, lhs); + } + } + } + + template + void BinaryBitwiseArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::LONG: { + Ra().Emit(node, lhs); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + Ra().Emit(node, lhs); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: { + Ra().Emit(node, lhs); + acc_.SetType(Checker()->GlobalETSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } + } +// NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty) +#define COMPILE_ARG(idx) \ + ASSERT(idx < arguments.size()); \ + auto *paramType##idx = signature->Params()[idx]->TsType(); \ + auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ + arguments[idx]->Compile(this); \ + VReg arg##idx = AllocReg(); \ + ApplyConversionAndStoreAccumulator(node, arg##idx, paramType##idx) + + template + void CallThisImpl(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + Ra().Emit(node, name, ctor, VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + Ra().Emit(node, name, ctor, arg0); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + Ra().Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + Ra().Emit(node, name, ctor, arg0, arg1, arg2); + break; + } + default: { + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + Rra().Emit(node, ctor, arguments.size() + 1, name, ctor); + break; + } + } + } + + template + void CallImpl(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + Ra().Emit(node, name, VReg::RegStart(), VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + Ra().Emit(node, name, arg0, VReg::RegStart()); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + Ra().Emit(node, name, arg0, arg1); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + Ra().Emit(node, name, arg0, arg1, arg2, VReg::RegStart()); + break; + } + case 4: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + COMPILE_ARG(3); + Ra().Emit(node, name, arg0, arg1, arg2, arg3); + break; + } + default: { + VReg argStart = NextReg(); + + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + Rra().Emit(node, argStart, arguments.size(), name, argStart); + break; + } + } + } + +#undef COMPILE_ARG + // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty) + + void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); + + template + void LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType); + void InitializeContainingClass(); + + friend class TargetTypeContext; + + VReg acc_ {}; + const checker::Type *targetType_ {}; + const checker::ETSObjectType *containingObjectType_ {}; +}; + +template +void ETSGen::LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType) +{ + auto typeKind = + targetType_ && !targetType_->IsETSObjectType() ? checker::ETSChecker::TypeKind(targetType_) : targetType; + + switch (typeKind) { + case checker::TypeFlag::BYTE: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalByteType()); + break; + } + case checker::TypeFlag::CHAR: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalCharType()); + break; + } + case checker::TypeFlag::SHORT: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalShortType()); + break; + } + case checker::TypeFlag::INT: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::LONG: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::FLOAT: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + case checker::TypeFlag::DOUBLE: { + Sa().Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + default: { + UNREACHABLE(); + } + } + + if (targetType_ && targetType_->IsETSObjectType()) { + ApplyConversion(node, targetType_); + acc_.SetType(targetType_); + } +} + +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/ETSemitter.cpp b/compiler/core/ETSemitter.cpp new file mode 100644 index 000000000..55ed6a148 --- /dev/null +++ b/compiler/core/ETSemitter.cpp @@ -0,0 +1,645 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ETSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumMember.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +#include "assembly-program.h" + +namespace panda::es2panda::compiler { + +#ifdef PANDA_WITH_ETS +static constexpr auto EXTENSION = panda_file::SourceLang::ETS; +#else +// TODO: temporary dummy gn buildfix until ETS plugin has gn build support +static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY; +#endif + +static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags) +{ + uint32_t accessFlags = 0; + + if ((modifierFlags & ir::ModifierFlags::PRIVATE) != 0) { + accessFlags = ACC_PRIVATE; + } else if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) { + accessFlags = ACC_PROTECTED; + } else { + accessFlags = ACC_PUBLIC; + } + + if ((modifierFlags & ir::ModifierFlags::STATIC) != 0) { + accessFlags |= ACC_STATIC; + } + + if ((modifierFlags & ir::ModifierFlags::CONST) != 0) { + accessFlags |= ACC_FINAL; + } + + if ((modifierFlags & ir::ModifierFlags::ABSTRACT) != 0) { + accessFlags |= ACC_ABSTRACT; + } + + if ((modifierFlags & ir::ModifierFlags::NATIVE) != 0) { + accessFlags |= ACC_NATIVE; + } + + return accessFlags; +} + +static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc) +{ + auto *funcScope = scriptFunc->Scope(); + auto *paramScope = funcScope->ParamScope(); + + auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION); + + func.params.reserve(paramScope->Params().size()); + + for (const auto *var : paramScope->Params()) { + std::stringstream ss; + var->TsType()->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), var->TsType()->Rank()), EXTENSION); + } + + std::stringstream ss; + + if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) { + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + } else { + auto *returnType = scriptFunc->Signature()->ReturnType(); + + returnType->ToAssemblerType(ss); + ASSERT(!ss.str().empty()); + func.return_type = pandasm::Type(ss.str(), returnType->Rank()); + } + + if (!scriptFunc->IsStaticBlock()) { + const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc); + func.metadata->SetAccessFlags(TranslateModifierFlags(methodDef->Modifiers())); + } + + return func; +} + +pandasm::Function *ETSFunctionEmitter::GenFunctionSignature() +{ + auto func = GenScriptFunction(Cg()->RootNode()->AsScriptFunction()); + auto *funcElement = new pandasm::Function(func.name, func.language); + *funcElement = std::move(func); + GetProgramElement()->SetFunction(funcElement); + funcElement->regs_num = VReg::REG_START - Cg()->TotalRegsNum(); + + return funcElement; +} + +void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = Signatures::ANY; + variableDebug.signature_type = Signatures::ANY; +} + +void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {} + +template +static pandasm::Function GenExternalFunction(T signature, bool isCtor) +{ + auto iter = signature.begin(); + std::string name(*iter++); + + auto func = pandasm::Function(name, EXTENSION); + + while (iter != signature.end()) { + auto paramName = *iter++; + func.params.emplace_back(pandasm::Type(paramName, 0), EXTENSION); + } + + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + if (isCtor) { + func.metadata->SetAttribute(Signatures::CONSTRUCTOR); + } + func.metadata->SetAttribute(Signatures::EXTERNAL); + + return func; +} + +static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor) +{ + auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION); + + for (auto param : signature->Params()) { + auto *paramType = param->TsType(); + + std::stringstream ss; + paramType->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), paramType->Rank()), EXTENSION); + } + + std::stringstream ss; + signature->ReturnType()->ToAssemblerType(ss); + func.return_type = pandasm::Type(ss.str(), signature->ReturnType()->Rank()); + + if (isCtor) { + func.metadata->SetAttribute(Signatures::CONSTRUCTOR); + } + func.metadata->SetAttribute(Signatures::EXTERNAL); + + return func; +} + +void ETSEmitter::GenAnnotation() +{ + Program()->lang = EXTENSION; + const auto *binder = static_cast(Context()->Binder()); + + auto *globalRecordTable = binder->GetGlobalRecordTable(); + + for (auto *classDecl : globalRecordTable->ClassDefinitions()) { + GenClassRecord(classDecl, false); + } + + for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, false); + } + + for (auto *enumDecl : globalRecordTable->EnumDeclaration()) { + GenEnumRecord(enumDecl, false); + } + + for (auto *signature : globalRecordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + Program()->function_table.emplace(func.name, std::move(func)); + } + + for (auto [extProg, recordTable] : binder->GetExternalRecordTable()) { + (void)extProg; + GenExternalRecord(recordTable); + } + + const auto *checker = static_cast(Context()->Checker()); + + for (auto [arrType, signature] : checker->GlobalArrayTypes()) { + GenGlobalArrayRecord(arrType, signature); + } +} + +void ETSEmitter::GenExternalRecord(binder::RecordTable *recordTable) +{ + bool IsGenStdLib = recordTable->Program()->Binder()->IsGenStdLib(); + for (auto *classDecl : recordTable->ClassDefinitions()) { + GenClassRecord(classDecl, !IsGenStdLib); + } + + for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, !IsGenStdLib); + } + + for (auto *signature : recordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + + if (!IsGenStdLib) { + func.metadata->SetAttribute(Signatures::EXTERNAL); + } + + Program()->function_table.emplace(func.name, std::move(func)); + } +} + +void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init) +{ + if (init == nullptr) { + return; + } + + const auto *type = init->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return; + } + + auto typeKind = checker::ETSChecker::TypeKind(type); + + classField.metadata->SetFieldType(classField.type); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: { + classField.metadata->SetValue(pandasm::ScalarValue::Create( + static_cast(type->AsETSBooleanType()->GetValue()))); + break; + } + case checker::TypeFlag::BYTE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsByteType()->GetValue())); + break; + } + case checker::TypeFlag::SHORT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsShortType()->GetValue())); + break; + } + case checker::TypeFlag::INT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsIntType()->GetValue())); + break; + } + case checker::TypeFlag::LONG: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsLongType()->GetValue())); + break; + } + case checker::TypeFlag::FLOAT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsFloatType()->GetValue())); + break; + } + case checker::TypeFlag::DOUBLE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsDoubleType()->GetValue())); + break; + } + case checker::TypeFlag::CHAR: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsCharType()->GetValue())); + break; + } + case checker::TypeFlag::ETS_OBJECT: { + classField.metadata->SetValue(pandasm::ScalarValue::Create( + type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8())); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external) +{ + auto *scriptFunc = methodDef->Function(); + auto func = GenScriptFunction(scriptFunc); + + if (external) { + func.metadata->SetAttribute(Signatures::EXTERNAL); + } + + if (scriptFunc->Body() != nullptr) { + return; + } + + func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT); + Program()->function_table.emplace(func.name, std::move(func)); +} + +void ETSEmitter::GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external) +{ + GenField(field->TsType(), field->Id()->Name(), field->Value(), TranslateModifierFlags(field->Modifiers()), + classRecord, external); +} + +void ETSEmitter::GenField(const checker::Type *tsType, const util::StringView &name, const ir::Expression *value, + uint32_t accesFlags, pandasm::Record &record, bool external) +{ + auto field = pandasm::Field(Program()->lang); + std::stringstream ss; + tsType->ToAssemblerType(ss); + + field.name = name.Mutf8(); + field.type = pandasm::Type(ss.str(), tsType->Rank()); + + field.metadata->SetAccessFlags(accesFlags); + + if (external) { + field.metadata->SetAttribute(Signatures::EXTERNAL); + } else { + EmitDefaultFieldValue(field, value); + } + + record.field_list.emplace_back(std::move(field)); +} + +void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord) +{ + std::vector foreignProps = baseType->ForeignProperties(); + + for (const auto *foreignProp : foreignProps) { + auto *declNode = foreignProp->Declaration()->Node(); + if (!declNode->IsClassProperty()) { + continue; + } + + GenClassField(declNode->AsClassProperty(), classRecord, true); + } +} + +void ETSEmitter::GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature) +{ + std::stringstream ss; + arrayType->ToAssemblerTypeWithRank(ss); + + auto arrayRecord = pandasm::Record(ss.str(), Program()->lang); + + auto func = GenExternalFunction(signature, true); + func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION); + + Program()->function_table.emplace(func.name, std::move(func)); + + arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->record_table.emplace(arrayRecord.name, std::move(arrayRecord)); + + std::stringstream ss2; + arrayType->ElementType()->ToAssemblerTypeWithRank(ss2); + panda::pandasm::Type atype_pa(ss2.str(), 1); + Program()->array_types.emplace(std::move(atype_pa)); +} + +void ETSEmitter::GenEnumRecord(const ir::TSEnumDeclaration *enumDecl, bool external) +{ + auto enumRecord = pandasm::Record(enumDecl->InternalName().Mutf8(), Program()->lang); + + if (external) { + enumRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC | ACC_ENUM | ACC_STATIC; + enumRecord.metadata->SetAccessFlags(accessFlags); + enumRecord.source_file = Context()->Binder()->Program()->SourceFile().Mutf8(); + enumRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_ENUM); + + for (const auto [name, var] : enumDecl->TsType()->AsETSObjectType()->StaticFields()) { + GenField(var->TsType(), name, nullptr, accessFlags, enumRecord, external); + } + + Program()->record_table.emplace(enumRecord.name, std::move(enumRecord)); +} + +void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external) +{ + auto *baseType = interfaceDecl->TsType()->AsETSObjectType(); + + auto interfaceRecord = pandasm::Record(baseType->Name().Mutf8(), Program()->lang); + + if (external) { + interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE; + + if (interfaceDecl->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + interfaceRecord.metadata->SetAccessFlags(accessFlags); + interfaceRecord.source_file = Context()->Binder()->Program()->SourceFile().Mutf8(); + interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + + for (auto *it : baseType->Interfaces()) { + interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + GenClassInheritedFields(baseType, interfaceRecord); + + for (const auto *prop : interfaceDecl->Body()->Body()) { + if (prop->IsClassProperty()) { + GenClassField(prop->AsClassProperty(), interfaceRecord, false); + } else if (prop->IsMethodDefinition()) { + GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external); + } + } + + Program()->record_table.emplace(interfaceRecord.name, std::move(interfaceRecord)); +} + +void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external) +{ + auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang); + + if (external) { + classRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC; + + if (classDef->IsAbstract()) { + accessFlags |= ACC_ABSTRACT; + } + + if (!classDef->IsOpen()) { + accessFlags |= ACC_FINAL; + } + + if (classDef->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + classRecord.metadata->SetAccessFlags(accessFlags); + classRecord.source_file = Context()->Binder()->Program()->SourceFile().Mutf8(); + + auto *baseType = classDef->TsType()->AsETSObjectType(); + + if (baseType->SuperType() != nullptr) { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, + baseType->SuperType()->AssemblerName().Mutf8()); + } else { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + } + + for (auto *it : baseType->Interfaces()) { + classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + if (!classDef->IsAbstract()) { + GenClassInheritedFields(baseType, classRecord); + } + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty()) { + continue; + } + + GenClassField(prop->AsClassProperty(), classRecord, external); + } + + std::vector annotations; + if (classDef->TypeParams() != nullptr) { + annotations.emplace_back(GenAnnotationSignature(classDef)); + } + + const ir::AstNode *parent = classDef->Parent(); + while (parent != nullptr) { + if (parent->IsMethodDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + if (parent->IsClassDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingClass( + parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + parent = parent->Parent(); + } + + if (!annotations.empty()) { + classRecord.metadata->SetAnnotations(std::move(annotations)); + } + + Program()->record_table.emplace(classRecord.name, std::move(classRecord)); +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef) +{ + static constexpr std::string_view object = "Lstd/core/Object"; + std::vector parts {}; + std::stringstream ss {}; + const auto ¶ms = classDef->TypeParams()->Params(); + + bool firstIteration = true; + for (const auto *param : params) { + if (firstIteration) { + ss << Signatures::GENERIC_BEGIN; + firstIteration = false; + } + ss << param->Name()->Name() << Signatures::MANGLE_BEGIN; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (param->Constraint() == nullptr) { + ss << object; + } else { + param->Constraint()->AsETSTypeReference()->TsType()->ToAssemblerTypeWithRank(ss); + auto str = ss.str(); + std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + std::stringstream {}.swap(ss); + ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR; + } + + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + std::stringstream {}.swap(ss); // cleanup + } + + ss << Signatures::GENERIC_END; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (classDef->TsType()->AsETSObjectType()->SuperType() == nullptr) { + ss << object; + } else { + ss << Signatures::CLASS_REF_BEGIN; + auto superType = classDef->TsType()->AsETSObjectType()->SuperType()->AssemblerName().Mutf8(); + std::replace(superType.begin(), superType.end(), *Signatures::METHOD_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + ss << superType << Signatures::MANGLE_SEPARATOR; + } + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + GenAnnotationRecord(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationData signature(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::Value::Type::STRING, std::move(parts))); + signature.AddElement(std::move(value)); + return signature; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef) +{ + GenAnnotationRecord(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationData enclosing_method(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::ScalarValue::Create( + methodDef->Function()->Scope()->InternalName().Mutf8()))); + enclosing_method.AddElement(std::move(value)); + return enclosing_method; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className) +{ + GenAnnotationRecord(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationData enclosingClass(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique( + pandasm::ScalarValue::Create(pandasm::Type::FromName(className, true)))); + enclosingClass.AddElement(std::move(value)); + return enclosingClass; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef, + const ir::AstNode *parent) +{ + GenAnnotationRecord(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + pandasm::AnnotationData innerClass(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + const bool isAnonymous = (classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS) != 0; + pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME, + std::make_unique( + isAnonymous + ? pandasm::ScalarValue::Create(0) + : pandasm::ScalarValue::Create( + classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8()))); + innerClass.AddElement(std::move(name)); + + pandasm::AnnotationElement accessFlags( + Signatures::ANNOTATION_KEY_ACCESS_FLAGS, + std::make_unique( + pandasm::ScalarValue::Create(TranslateModifierFlags(parent->Modifiers())))); + innerClass.AddElement(std::move(accessFlags)); + return innerClass; +} + +void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType) +{ + const std::string recordName(recordNameView); + const auto recordIt = Program()->record_table.find(recordName); + if (recordIt == Program()->record_table.end()) { + pandasm::Record record(recordName, EXTENSION); + record.metadata->SetAttribute(Signatures::EXTERNAL); + record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE); + if (isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, + Signatures::RUNTIME_TYPE_ANNOTATION); + } else if (isRuntime && !isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION); + } else if (!isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION); + } + Program()->record_table.emplace(record.name, std::move(record)); + } +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSemitter.h b/compiler/core/ETSemitter.h new file mode 100644 index 000000000..839a2fda7 --- /dev/null +++ b/compiler/core/ETSemitter.h @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_ETS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::binder { +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::ir { +class ClassDefinition; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class ETSObjectType; +class ETSArrayType; +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::pandasm { +struct Field; +struct Record; +class ItemMetadata; +class AnnotationData; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { + +class ETSFunctionEmitter : public FunctionEmitter { +public: + ETSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~ETSFunctionEmitter() = default; + NO_COPY_SEMANTIC(ETSFunctionEmitter); + NO_MOVE_SEMANTIC(ETSFunctionEmitter); + +protected: + const ETSGen *Etsg() const + { + return reinterpret_cast(Cg()); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class ETSEmitter : public Emitter { +public: + explicit ETSEmitter(const CompilerContext *context) : Emitter(context) {} + ~ETSEmitter() override = default; + NO_COPY_SEMANTIC(ETSEmitter); + NO_MOVE_SEMANTIC(ETSEmitter); + + void GenAnnotation() override; + +private: + void GenExternalRecord(binder::RecordTable *recordTable); + void GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature); + void GenClassRecord(const ir::ClassDefinition *classDef, bool external); + void GenEnumRecord(const ir::TSEnumDeclaration *enumDecl, bool external); + void GenAnnotationRecord(std::string_view recordNameView, bool isRuntime = false, bool isType = false); + void GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external); + void EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init); + void GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external); + void GenField(const checker::Type *tsType, const util::StringView &name, const ir::Expression *value, + uint32_t accesFlags, pandasm::Record &record, bool external); + void GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external); + void GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord); + pandasm::AnnotationData GenAnnotationSignature(const ir::ClassDefinition *classDef); + pandasm::AnnotationData GenAnnotationEnclosingClass(std::string_view className); + pandasm::AnnotationData GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef); + pandasm::AnnotationData GenAnnotationInnerClass(const ir::ClassDefinition *classDef, const ir::AstNode *parent); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/ETSfunction.cpp b/compiler/core/ETSfunction.cpp new file mode 100644 index 000000000..4f9e68200 --- /dev/null +++ b/compiler/core/ETSfunction.cpp @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ETSfunction.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsEnumMember.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::compiler { +void ETSFunction::CallImplicitCtor(ETSGen *etsg) +{ + RegScope rs(etsg); + auto *superType = etsg->ContainingObjectType()->SuperType(); + + if (superType == nullptr) { + etsg->CallThisStatic0(etsg->RootNode(), etsg->GetThisReg(), Signatures::BUILTIN_OBJECT_CTOR); + + return; + } + + auto res = std::find_if(superType->ConstructSignatures().cbegin(), superType->ConstructSignatures().cend(), + [](const checker::Signature *sig) { return sig->Params().empty(); }); + + if (res == superType->ConstructSignatures().cend()) { + return; + } + + etsg->CallThisStatic0(etsg->RootNode(), etsg->GetThisReg(), (*res)->InternalName()); +} + +void ETSFunction::GenerateEnumMembers(ETSGen *etsg, const ir::AstNode *node, VReg arrayObj, + const ir::TSEnumMember *enumMember, int32_t index) +{ + RegScope rs(etsg); + VReg nameReg = etsg->AllocReg(); + VReg indexReg = etsg->AllocReg(); + + const auto name = enumMember->Key()->AsIdentifier()->Name(); + + etsg->LoadAccumulatorString(enumMember, name); + etsg->StoreAccumulator(enumMember, nameReg); + + etsg->LoadAccumulatorInt(enumMember, index); + etsg->StoreAccumulator(enumMember, indexReg); + + compiler::VReg enumObj = etsg->AllocReg(etsg->Checker()->GlobalETSObjectType()); + etsg->NewObject(enumMember, enumObj, etsg->ContainingObjectType()->AssemblerName()); + + etsg->CallThisStatic2(enumMember, enumObj, compiler::Signatures::BUILTIN_ENUM_CTOR, nameReg, indexReg); + + etsg->LoadAccumulator(enumMember, enumObj); + etsg->StoreStaticOwnProperty(enumMember, etsg->ContainingObjectType(), name); + + etsg->StoreArrayElement(node, arrayObj, indexReg); +} + +void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block) +{ + auto *scriptFunc = etsg->RootNode()->AsScriptFunction(); + if (scriptFunc->IsEnum()) { + if (scriptFunc->IsConstructor()) { + auto ¶ms = scriptFunc->Scope()->ParamScope()->Params(); + etsg->CallThisStatic2(scriptFunc, params[0]->Vreg(), compiler::Signatures::BUILTIN_ENUM_CTOR, + params[1]->Vreg(), params[2]->Vreg()); + } else { + RegScope rs(etsg); + int32_t index = 0; + + const auto *enumDecl = etsg->ContainingObjectType()->GetDeclNode()->AsTSEnumDeclaration(); + etsg->LoadAccumulatorInt(enumDecl, enumDecl->Members().size()); + + const checker::ETSObjectType *enumType = enumDecl->TsType()->AsETSObjectType(); + auto var = enumType->GetProperty(compiler::Signatures::ENUM_VALUES, + checker::PropertySearchFlags::SEARCH_STATIC_FIELD); + + ASSERT(var != nullptr); + const auto *varType = var->AsLocalVariable()->TsType()->AsETSArrayType(); + VReg arrayObj = etsg->AllocReg(varType); + VReg dim = etsg->AllocReg(); + etsg->StoreAccumulator(enumDecl, dim); + etsg->NewArray(enumDecl, arrayObj, dim, varType->ElementType()); + + for (const auto *member : enumDecl->Members()) { + if (member->IsScriptFunction() || member->IsMethodDefinition()) { + continue; + } + + GenerateEnumMembers(etsg, enumDecl, arrayObj, member->AsTSEnumMember(), index++); + } + + etsg->LoadAccumulator(enumDecl, arrayObj); + etsg->StoreStaticOwnProperty(enumDecl, varType, compiler::Signatures::ENUM_VALUES); + } + } else if (scriptFunc->IsStaticBlock()) { + const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || !prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(etsg); + } + } else if (scriptFunc->IsConstructor()) { + if (scriptFunc->IsImplicitConstructor()) { + CallImplicitCtor(etsg); + } + + const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(etsg); + } + } + + const auto &statements = block->Statements(); + + if (statements.empty()) { + etsg->SetFirstStmt(block); + etsg->EmitReturnVoid(block); + return; + } + + etsg->SetFirstStmt(statements.front()); + + etsg->CompileStatementList(statements); + + if (!statements.back()->IsReturnStatement()) { + if (etsg->ReturnType()->IsETSVoidType()) { + etsg->EmitReturnVoid(statements.back()); + } else { + etsg->LoadDefaultValue(statements.back(), scriptFunc->Signature()->ReturnType()); + etsg->ReturnAcc(statements.back()); + } + } +} + +void ETSFunction::CompileFunctionParameterDeclaration(ETSGen *etsg, const ir::ScriptFunction *func) +{ + ScopeContext scopeCtx(etsg, func->Scope()->ParamScope()); + + uint32_t index = 0; + + for (const auto *param : func->Params()) { + if (!param->IsRestElement()) { + index++; + continue; + } + + auto ref = JSLReference::Create(etsg, param, true); + [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); + ASSERT(paramVar && paramVar->IsLocalVariable()); + + [[maybe_unused]] VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); + ASSERT(paramVar->AsLocalVariable()->Vreg() == paramReg); + + ref.SetValue(); + index++; + } +} + +void ETSFunction::CompileFunction(ETSGen *etsg) +{ + const auto *decl = etsg->RootNode()->AsScriptFunction(); + CompileFunctionParameterDeclaration(etsg, decl); + + const ir::AstNode *body = decl->Body(); + + if (body->IsExpression()) { + // TODO(user): + } else { + CompileSourceBlock(etsg, body->AsBlockStatement()); + } +} + +void ETSFunction::Compile(ETSGen *etsg) +{ + FunctionRegScope lrs(etsg); + auto *topScope = etsg->TopScope(); + + if (topScope->IsFunctionScope()) { + CompileFunction(etsg); + } else { + ASSERT(topScope->IsGlobalScope()); + CompileSourceBlock(etsg, etsg->RootNode()->AsBlockStatement()); + } + + etsg->SortCatchTables(); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSfunction.h b/compiler/core/ETSfunction.h new file mode 100644 index 000000000..a4f22f96f --- /dev/null +++ b/compiler/core/ETSfunction.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETSFUNCTION_H +#define ES2PANDA_COMPILER_CORE_ETSFUNCTION_H + +#include "plugins/ecmascript/es2panda/ir/irnode.h" + +namespace panda::es2panda::ir { +class ScriptFunction; +class BlockStatement; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::compiler { +class ETSGen; + +class ETSFunction { +public: + ETSFunction() = delete; + + static void Compile(ETSGen *etsg); + +private: + static void GenerateEnumMembers(ETSGen *etsg, const ir::AstNode *node, VReg arrayObj, + const ir::TSEnumMember *enumMember, int32_t index); + static void CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block); + static void CompileFunctionParameterDeclaration(ETSGen *etsg, const ir::ScriptFunction *func); + static void CompileFunction(ETSGen *etsg); + static void CallImplicitCtor(ETSGen *etsg); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/JSemitter.cpp b/compiler/core/JSemitter.cpp new file mode 100644 index 000000000..6c59b9889 --- /dev/null +++ b/compiler/core/JSemitter.cpp @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "assembly-program.h" + +namespace panda::es2panda::compiler { +pandasm::Function *JSFunctionEmitter::GenFunctionSignature() +{ + auto *func = new pandasm::Function(Cg()->InternalName().Mutf8(), panda_file::SourceLang::ECMASCRIPT); + GetProgramElement()->SetFunction(func); + + size_t paramCount = Cg()->InternalParamCount(); + func->params.reserve(paramCount); + + for (uint32_t i = 0; i < paramCount; ++i) { + func->params.emplace_back(pandasm::Type("any", 0), panda_file::SourceLang::ECMASCRIPT); + } + + func->regs_num = VReg::REG_START - Cg()->TotalRegsNum(); + func->return_type = pandasm::Type("any", 0); + + return func; +} + +void JSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = "any"; + variableDebug.signature_type = "any"; +} + +void JSFunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) +{ + pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); + pandasm::AnnotationElement icSizeAnnotationElement( + "icSize", std::make_unique( + pandasm::ScalarValue::Create(Pg()->IcSize()))); + funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); + + pandasm::AnnotationElement parameterLengthAnnotationElement( + "parameterLength", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FormalParametersCount()))); + funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); + + pandasm::AnnotationElement funcNameAnnotationElement( + "funcName", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FunctionName().Mutf8()))); + funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); + + func->metadata->AddAnnotations({funcAnnotationData}); +} + +void JSEmitter::GenAnnotation() +{ + Program()->lang = panda_file::SourceLang::ECMASCRIPT; + GenESAnnoatationRecord(); + GenESModuleModeRecord(Context()->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); +} + +void JSEmitter::GenESAnnoatationRecord() +{ + auto annotationRecord = pandasm::Record("_ESAnnotation", Program()->lang); + annotationRecord.metadata->SetAttribute("external"); + annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); + Program()->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); +} + +void JSEmitter::GenESModuleModeRecord(bool isModule) +{ + auto modeRecord = pandasm::Record("_ESModuleMode", Program()->lang); + modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); + + auto modeField = pandasm::Field(Program()->lang); + modeField.name = "isModule"; + modeField.type = pandasm::Type("u8", 0); + modeField.metadata->SetValue( + pandasm::ScalarValue::Create(static_cast(isModule))); + + modeRecord.field_list.emplace_back(std::move(modeField)); + + Program()->record_table.emplace(modeRecord.name, std::move(modeRecord)); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/JSemitter.h b/compiler/core/JSemitter.h new file mode 100644 index 000000000..6a1147082 --- /dev/null +++ b/compiler/core/JSemitter.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_JS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_JS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::compiler { + +class JSFunctionEmitter : public FunctionEmitter { +public: + JSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~JSFunctionEmitter() = default; + NO_COPY_SEMANTIC(JSFunctionEmitter); + NO_MOVE_SEMANTIC(JSFunctionEmitter); + +protected: + const PandaGen *Pg() const + { + return reinterpret_cast(Cg()); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class JSEmitter : public Emitter { +public: + explicit JSEmitter(const CompilerContext *context) : Emitter(context) {} + ~JSEmitter() override = default; + NO_COPY_SEMANTIC(JSEmitter); + NO_MOVE_SEMANTIC(JSEmitter); + + void GenAnnotation() override; + +private: + void GenESAnnoatationRecord(); + void GenESModuleModeRecord(bool isModule); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/codeGen.cpp b/compiler/core/codeGen.cpp new file mode 100644 index 000000000..3c2004ce6 --- /dev/null +++ b/compiler/core/codeGen.cpp @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "codeGen.h" + +#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" + +namespace panda::es2panda::compiler { +Label *CodeGen::AllocLabel() +{ + std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); + return sa_.AllocLabel(std::move(id)); +} + +bool CodeGen::IsDebug() const +{ + return context_->IsDebug(); +} + +uint32_t CodeGen::ParamCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + return rootNode_->AsScriptFunction()->Params().size(); +} + +uint32_t CodeGen::FormalParametersCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + ASSERT(rootNode_->IsScriptFunction()); + + return rootNode_->AsScriptFunction()->FormalParamsLength(); +} + +uint32_t CodeGen::InternalParamCount() const +{ + static const uint32_t HIDDEN_PARAMS = 3; + return ParamCount() + HIDDEN_PARAMS; +} + +const util::StringView &CodeGen::InternalName() const +{ + return topScope_->InternalName(); +} + +const util::StringView &CodeGen::FunctionName() const +{ + return topScope_->Name(); +} + +binder::Binder *CodeGen::Binder() const +{ + return context_->Binder(); +} + +int32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf) +{ + programElement_->BuffStorage().emplace_back(std::move(buf)); + return literalBufferIdx_++; +} + +void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) +{ + sa_.Emit(node, str); +} + +void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) +{ + sa_.AddLabel(label); +} + +void CodeGen::Branch(const ir::AstNode *node, Label *label) +{ + sa_.Emit(node, label); +} + +bool CodeGen::CheckControlFlowChange() +{ + const auto *iter = dynamicContext_; + + while (iter != nullptr) { + if (iter->HasFinalizer()) { + return true; + } + + iter = iter->Prev(); + } + + return false; +} + +Label *CodeGen::ControlFlowChangeBreak(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + + util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL; + Label *breakTarget = nullptr; + + while (iter != nullptr) { + iter->AbortContext(ControlFlowChange::BREAK, labelName); + const auto *constIter = iter; + + const auto &labelTargetName = constIter->Target().BreakLabel(); + + if (constIter->Target().BreakTarget() != nullptr) { + breakTarget = constIter->Target().BreakTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return breakTarget; +} + +Label *CodeGen::ControlFlowChangeContinue(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL; + Label *continueTarget = nullptr; + + while (iter != nullptr) { + iter->AbortContext(ControlFlowChange::CONTINUE, labelName); + const auto *constIter = iter; + + const auto &labelTargetName = constIter->Target().ContinueLabel(); + + if (constIter->Target().ContinueTarget() != nullptr) { + continueTarget = constIter->Target().ContinueTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return continueTarget; +} + +uint32_t CodeGen::TryDepth() const +{ + const auto *iter = dynamicContext_; + uint32_t depth = 0; + + while (iter != nullptr) { + if (iter->HasTryCatch()) { + depth++; + } + + iter = iter->Prev(); + } + + return depth; +} + +CatchTable *CodeGen::CreateCatchTable() +{ + auto *catchTable = allocator_->New(this, TryDepth()); + catchList_.push_back(catchTable); + return catchTable; +} + +void CodeGen::SortCatchTables() +{ + std::sort(catchList_.begin(), catchList_.end(), + [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/codeGen.h b/compiler/core/codeGen.h new file mode 100644 index 000000000..e56b67fe1 --- /dev/null +++ b/compiler/core/codeGen.h @@ -0,0 +1,265 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_CODEGEN_H +#define ES2PANDA_COMPILER_CORE_CODEGEN_H + +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" + +namespace panda::es2panda::compiler { +class CatchTable; +class DynamicContext; + +enum class Constant { + JS_NAN, + JS_HOLE, + JS_INFINITY, + JS_UNDEFINED, + JS_NULL, + JS_TRUE, + JS_FALSE, + JS_SYMBOL, + JS_GLOBAL, +}; + +class DebugInfo { +public: + explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo_(allocator->Adapter()) {}; + DEFAULT_COPY_SEMANTIC(DebugInfo); + DEFAULT_MOVE_SEMANTIC(DebugInfo); + ~DebugInfo() = default; + + ArenaVector &VariableDebugInfo() + { + return variableDebugInfo_; + } + + const ArenaVector &VariableDebugInfo() const + { + return variableDebugInfo_; + } + + const ir::Statement *FirstStatement() const + { + return firstStmt; + } + +private: + friend class CodeGen; + + ArenaVector variableDebugInfo_; + const ir::Statement *firstStmt {}; +}; + +class CodeGen { +public: + explicit CodeGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : allocator_(allocator), + context_(context), + debugInfo_(allocator_), + topScope_(scope), + scope_(topScope_), + rootNode_(scope->Node()), + insns_(allocator_->Adapter()), + catchList_(allocator_->Adapter()), + programElement_(programElement), + sa_(this), + ra_(this, spiller), + rra_(this, spiller) + { + } + ~CodeGen() = default; + NO_COPY_SEMANTIC(CodeGen); + NO_MOVE_SEMANTIC(CodeGen); + + inline ArenaAllocator *Allocator() const + { + return allocator_; + } + + const ArenaVector &CatchList() const + { + return catchList_; + } + + binder::FunctionScope *TopScope() const + { + return topScope_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + const ir::AstNode *RootNode() const + { + return rootNode_; + } + + ArenaList &Insns() + { + return insns_; + } + + const ArenaList &Insns() const + { + return insns_; + } + + VReg AllocReg() + { + return VReg(usedRegs_--); + } + + VReg AllocReg(const checker::Type *type) + { + return VReg(usedRegs_--, type); + } + + VReg NextReg() const + { + return VReg(usedRegs_); + } + + uint32_t TotalRegsNum() const + { + return totalRegs_; + } + + size_t LabelCount() const + { + return labelId_; + } + + const DebugInfo &Debuginfo() const + { + return debugInfo_; + } + + uint32_t IcSize() const + { + return 0; + } + + bool IsDebug() const; + RegSpiller *GetRegSpiller() const; + uint32_t ParamCount() const; + uint32_t FormalParametersCount() const; + uint32_t InternalParamCount() const; + const util::StringView &InternalName() const; + const util::StringView &FunctionName() const; + binder::Binder *Binder() const; + + Label *AllocLabel(); + int32_t AddLiteralBuffer(LiteralBuffer &&buf); + + void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); + + void SetLabel(const ir::AstNode *node, Label *label); + void Branch(const ir::AstNode *node, class Label *label); + bool CheckControlFlowChange(); + Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); + Label *ControlFlowChangeContinue(const ir::Identifier *label); + + uint32_t TryDepth() const; + CatchTable *CreateCatchTable(); + void SortCatchTables(); + + void SetFirstStmt(const ir::Statement *stmt) + { + debugInfo_.firstStmt = stmt; + } + + [[noreturn]] static void Unimplemented() + { + throw Error(ErrorType::GENERIC, "", "Unimplemented code path"); + } + +protected: + SimpleAllocator &Sa() + { + return sa_; + } + + const SimpleAllocator &Sa() const + { + return sa_; + } + + RegAllocator &Ra() + { + return ra_; + } + + const RegAllocator &Ra() const + { + return ra_; + } + + RangeRegAllocator &Rra() + { + return rra_; + } + + const RangeRegAllocator &Rra() const + { + return rra_; + } + + CompilerContext *Context() const + { + return context_; + } + + ProgramElement *ProgElement() const + { + return programElement_; + } + +private: + ArenaAllocator *allocator_; + CompilerContext *context_; + DebugInfo debugInfo_; + binder::FunctionScope *topScope_; + binder::Scope *scope_; + const ir::AstNode *rootNode_; + ArenaList insns_; + ArenaVector catchList_; + ProgramElement *programElement_; + DynamicContext *dynamicContext_ {}; + + SimpleAllocator sa_; + RegAllocator ra_; + RangeRegAllocator rra_; + size_t labelId_ {0}; + int32_t literalBufferIdx_ {0}; + + uint32_t usedRegs_ {VReg::REG_START}; + uint32_t totalRegs_ {VReg::REG_START}; + friend class ScopeContext; + friend class RegScope; + friend class LocalRegScope; + friend class LoopRegScope; + friend class ParamRegScope; + friend class FunctionRegScope; + friend class DynamicContext; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileJob.cpp b/compiler/core/compileJob.cpp new file mode 100644 index 000000000..5af7d3eed --- /dev/null +++ b/compiler/core/compileJob.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "compileQueue.h" + +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" + +namespace panda::es2panda::compiler { + +void CompileJob::Run() +{ + std::unique_lock lock(m_); + cond_.wait(lock, [this] { return dependencies_ == 0; }); + + context_->GetCodeGenCb()(context_, scope_, &programElement_); + + if (dependant_ != nullptr) { + dependant_->Signal(); + } +} + +void CompileJob::DependsOn(CompileJob *job) +{ + job->dependant_ = this; + dependencies_++; +} + +void CompileJob::Signal() +{ + { + std::lock_guard lock(m_); + dependencies_--; + } + + cond_.notify_one(); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/compileJob.h b/compiler/core/compileJob.h new file mode 100644 index 000000000..687217f77 --- /dev/null +++ b/compiler/core/compileJob.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_COMPILEJOB_H +#define ES2PANDA_COMPILER_CORE_COMPILEJOB_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/programElement.h" + +#include +#include + +namespace panda::es2panda::binder { +class FunctionScope; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::compiler { +class CompilerContext; +class ProgramElement; + +class CompileJob { +public: + CompileJob() = default; + NO_COPY_SEMANTIC(CompileJob); + NO_MOVE_SEMANTIC(CompileJob); + ~CompileJob() = default; + + const ProgramElement *GetProgramElement() const + { + return &programElement_; + } + + ProgramElement *GetProgramElement() + { + return &programElement_; + } + + void SetConext(CompilerContext *context, binder::FunctionScope *scope) + { + context_ = context; + scope_ = scope; + } + + void Run(); + void DependsOn(CompileJob *job); + void Signal(); + +private: + std::mutex m_; + std::condition_variable cond_; + CompilerContext *context_ {}; + binder::FunctionScope *scope_ {}; + ProgramElement programElement_; + CompileJob *dependant_ {}; + size_t dependencies_ {0}; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileQueue.cpp b/compiler/core/compileQueue.cpp index f75127362..6af577190 100644 --- a/compiler/core/compileQueue.cpp +++ b/compiler/core/compileQueue.cpp @@ -23,43 +23,6 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -CompileJob::CompileJob() : programElement_(std::make_unique()) {} -CompileJob::~CompileJob() = default; - -void CompileJob::Run() -{ - std::unique_lock lock(m_); - cond_.wait(lock, [this] { return dependencies_ == 0; }); - - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - PandaGen pg(&allocator, context_, scope_, programElement_.get()); - - Function::Compile(&pg); - - FunctionEmitter funcEmitter(&pg, programElement_.get()); - funcEmitter.Generate(); - - if (dependant_ != nullptr) { - dependant_->Signal(); - } -} - -void CompileJob::DependsOn(CompileJob *job) -{ - job->dependant_ = this; - dependencies_++; -} - -void CompileJob::Signal() -{ - { - std::lock_guard lock(m_); - dependencies_--; - } - - cond_.notify_one(); -} - CompileQueue::CompileQueue(size_t threadCount) { threads_.reserve(threadCount); @@ -147,15 +110,16 @@ void CompileQueue::Wait(const JobsFinishedCb &onFinishedCb) std::unique_lock lock(m_); jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); + if (!errors_.empty()) { + delete[] jobs_; + // NOLINTNEXTLINE + throw errors_.front(); + } + for (uint32_t i = 0; i < totalJobsCount_; i++) { onFinishedCb(jobs_ + i); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } delete[] jobs_; - - if (!errors_.empty()) { - // NOLINTNEXTLINE - throw errors_.front(); - } } } // namespace panda::es2panda::compiler diff --git a/compiler/core/compileQueue.h b/compiler/core/compileQueue.h index 39d39f1bc..bd31c32f5 100644 --- a/compiler/core/compileQueue.h +++ b/compiler/core/compileQueue.h @@ -19,6 +19,7 @@ #include "macros.h" #include "os/thread.h" #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileJob.h" #include #include @@ -30,39 +31,6 @@ class FunctionScope; namespace panda::es2panda::compiler { class CompilerContext; -class ProgramElement; - -class CompileJob { -public: - CompileJob(); - NO_COPY_SEMANTIC(CompileJob); - NO_MOVE_SEMANTIC(CompileJob); - ~CompileJob(); - - ProgramElement *GetProgramElement() const - { - return programElement_.get(); - } - - void SetConext(CompilerContext *context, binder::FunctionScope *scope) - { - context_ = context; - scope_ = scope; - } - - void Run(); - void DependsOn(CompileJob *job); - void Signal(); - -private: - std::mutex m_; - std::condition_variable cond_; - CompilerContext *context_ {}; - binder::FunctionScope *scope_ {}; - std::unique_ptr programElement_; - CompileJob *dependant_ {}; - size_t dependencies_ {0}; -}; class CompileQueue { public: diff --git a/compiler/core/compilerContext.cpp b/compiler/core/compilerContext.cpp index 209d223a9..3e712f56a 100644 --- a/compiler/core/compilerContext.cpp +++ b/compiler/core/compilerContext.cpp @@ -14,16 +14,6 @@ */ #include "compilerContext.h" -#include - -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" namespace panda::es2panda::compiler { -CompilerContext::CompilerContext(binder::Binder *binder, CompilerOptions options) - : binder_(binder), emitter_(std::make_unique(this)), options_(options) -{ -} - -CompilerContext::~CompilerContext() = default; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerContext.h b/compiler/core/compilerContext.h index 7936fc1ab..d7b44de73 100644 --- a/compiler/core/compilerContext.h +++ b/compiler/core/compilerContext.h @@ -21,36 +21,62 @@ #include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include #include -namespace panda::es2panda::ir { -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Binder; +class FunctionScope; } // namespace panda::es2panda::binder +namespace panda::es2panda::checker { +class Checker; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { class Literal; class DebugInfo; class Emitter; +class CodeGen; +class ProgramElement; class CompilerContext { public: - CompilerContext(binder::Binder *binder, CompilerOptions options); + using CodeGenCb = + std::function; + + CompilerContext(binder::Binder *binder, checker::Checker *checker, CompilerOptions options, CodeGenCb codeGenCb) + : binder_(binder), checker_(checker), options_(std::move(options)), codeGenCb_(std::move(codeGenCb)) + { + } + NO_COPY_SEMANTIC(CompilerContext); NO_MOVE_SEMANTIC(CompilerContext); - ~CompilerContext(); + ~CompilerContext() = default; binder::Binder *Binder() const { return binder_; } + checker::Checker *Checker() const + { + return checker_; + } + Emitter *GetEmitter() const { - return emitter_.get(); + return emitter_; + } + + void SetEmitter(Emitter *emitter) + { + emitter_ = emitter; + } + + const CodeGenCb &GetCodeGenCb() const + { + return codeGenCb_; } int32_t AddContextLiteral(LiteralBuffer &&literals) @@ -69,6 +95,11 @@ public: return options_.isDebug; } + bool DumpDebugInfo() const + { + return options_.dumpDebugInfo; + } + bool IsDirectEval() const { return options_.isDirectEval; @@ -86,9 +117,11 @@ public: private: binder::Binder *binder_; + checker::Checker *checker_; + Emitter *emitter_ {}; std::vector buffStorage_; - std::unique_ptr emitter_; CompilerOptions options_; + CodeGenCb codeGenCb_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerImpl.cpp b/compiler/core/compilerImpl.cpp index 1531ad8ec..2899598d8 100644 --- a/compiler/core/compilerImpl.cpp +++ b/compiler/core/compilerImpl.cpp @@ -15,26 +15,35 @@ #include "compilerImpl.h" -#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerImpl.h" +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/JSemitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSemitter.h" +#include "plugins/ecmascript/es2panda/parser/parserImpl.h" +#include "plugins/ecmascript/es2panda/parser/JSparser.h" +#include "plugins/ecmascript/es2panda/parser/ASparser.h" +#include "plugins/ecmascript/es2panda/parser/TSparser.h" +#include "plugins/ecmascript/es2panda/parser/ETSparser.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/JSBinder.h" +#include "plugins/ecmascript/es2panda/binder/ASBinder.h" +#include "plugins/ecmascript/es2panda/binder/TSBinder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ASchecker.h" +#include "plugins/ecmascript/es2panda/checker/JSchecker.h" +#include "plugins/ecmascript/es2panda/es2panda.h" #include #include namespace panda::es2panda::compiler { -CompilerImpl::CompilerImpl(size_t threadCount) : queue_(new CompileQueue(threadCount)) {} -CompilerImpl::~CompilerImpl() -{ - delete queue_; -} - -panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options) +void CompilerImpl::HandleContextLiterals(CompilerContext *context) { auto *emitter = context->GetEmitter(); @@ -44,27 +53,98 @@ panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser: } emitter->LiteralBufferIndex() += context->ContextLiterals().size(); +} - if (program->Extension() == ScriptExtension::AS) { - /* TODO(): AS files are not yet compiled */ - return nullptr; - } +panda::pandasm::Program *CompilerImpl::Emit(CompilerContext *context) +{ + HandleContextLiterals(context); + + queue_.Schedule(context); + + /* Main thread can also be used instead of idling */ + queue_.Consume(); + auto *emitter = context->GetEmitter(); + queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); + + return emitter->Finalize(context->DumpDebugInfo(), Signatures::ETS_GLOBAL); +} + +template +static CompilerContext::CodeGenCb MakeCompileJob() +{ + return + [](CompilerContext *context, binder::FunctionScope *scope, compiler::ProgramElement *programElement) -> void { + RegSpiller rspl; + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + CodeGen cg(&allocator, &rspl, context, scope, programElement); + + FunctionEmitter funcEmitter(&cg, programElement); + funcEmitter.Generate(); + }; +} + +using EmitCb = std::function; + +template +static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const EmitCb &emitCb) +{ + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto program = parser::Program::NewProgram(&allocator); + auto parser = Parser(&program, unit.options.stdLib_, static_cast(unit.rawParserStatus)); + auto checker = Checker(); - if (program->Extension() == ScriptExtension::TS) { - ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - auto checker = std::make_unique(&localAllocator, context->Binder()); - checker->StartChecker(); + auto *binder = program.Binder(); + binder->SetProgram(&program); + CompilerContext context(binder, &checker, unit.options, + MakeCompileJob()); + binder->SetCompilerContext(&context); + + auto emitter = Emitter(&context); + context.SetEmitter(&emitter); + + parser.ParseScript(unit.input); + + if (!checker.StartChecker(binder, unit.options)) { return nullptr; } - queue_->Schedule(context); + emitter.GenAnnotation(); - /* Main thread can also be used instead of idling */ - queue_->Consume(); - queue_->Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); + return emitCb(&context); +} + +pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit) +{ + auto emitCb = [this](CompilerContext *context) -> pandasm::Program * { return Emit(context); }; - return emitter->Finalize(options.dumpDebugInfo); + switch (unit.ext) { + case ScriptExtension::TS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::AS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::ETS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::JS: { + return CreateCompiler( + unit, emitCb); + } + default: { + UNREACHABLE(); + return nullptr; + } + } } void CompilerImpl::DumpAsm(const panda::pandasm::Program *prog) diff --git a/compiler/core/compilerImpl.h b/compiler/core/compilerImpl.h index c81d92061..94629a0ee 100644 --- a/compiler/core/compilerImpl.h +++ b/compiler/core/compilerImpl.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_INCLUDE_COMPILER_IMPL_H #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "macros.h" #include "mem/arena_allocator.h" #include "os/thread.h" @@ -27,27 +28,38 @@ namespace panda::pandasm { struct Program; } // namespace panda::pandasm -namespace panda::es2panda::parser { -class Program; -} // namespace panda::es2panda::parser - namespace panda::es2panda::compiler { class CompileQueue; class CompilerContext; +class CompilationUnit { +public: + explicit CompilationUnit(const SourceFile &i, const CompilerOptions &o, uint32_t s, ScriptExtension e) + : input(i), options(o), rawParserStatus(s), ext(e) + { + } + const SourceFile &input; + const CompilerOptions &options; + uint32_t rawParserStatus; + ScriptExtension ext; +}; + class CompilerImpl { public: - explicit CompilerImpl(size_t threadCount); - ~CompilerImpl(); + explicit CompilerImpl(size_t threadCount) : queue_(threadCount) {} NO_COPY_SEMANTIC(CompilerImpl); NO_MOVE_SEMANTIC(CompilerImpl); + ~CompilerImpl() = default; + + pandasm::Program *Compile(const CompilationUnit &unit); - panda::pandasm::Program *Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options); static void DumpAsm(const panda::pandasm::Program *prog); private: - CompileQueue *queue_; + panda::pandasm::Program *Emit(CompilerContext *context); + static void HandleContextLiterals(CompilerContext *context); + + CompileQueue queue_; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.cpp b/compiler/core/dynamicContext.cpp index eb936f4b1..f4dfe5e51 100644 --- a/compiler/core/dynamicContext.cpp +++ b/compiler/core/dynamicContext.cpp @@ -17,31 +17,32 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" namespace panda::es2panda::compiler { -DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_) +DynamicContext::DynamicContext(CodeGen *cg, LabelTarget target) : cg_(cg), target_(target), prev_(Cg()->dynamicContext_) { - pg_->dynamicContext_ = this; + Cg()->dynamicContext_ = this; } DynamicContext::~DynamicContext() { - pg_->dynamicContext_ = prev_; + Cg()->dynamicContext_ = prev_; } -LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt) - : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) +LabelContext::LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt) + : DynamicContext(cg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) { if (!labelledStmt->Body()->IsBlockStatement()) { return; } - label_ = pg->AllocLabel(); - target_.SetBreakTarget(label_); + label_ = cg->AllocLabel(); + Target().SetBreakTarget(label_); } LabelContext::~LabelContext() @@ -50,7 +51,7 @@ LabelContext::~LabelContext() return; } - pg_->SetLabel(labelledStmt_, label_); + Cg()->SetLabel(labelledStmt_, label_); } LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target) @@ -60,11 +61,11 @@ LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget t return; } - catchTable_ = pg_->CreateCatchTable(); + catchTable_ = Cg()->CreateCatchTable(); const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryBegin()); + Cg()->SetLabel(node, labelSet.TryBegin()); } LexEnvContext::~LexEnvContext() @@ -76,14 +77,19 @@ LexEnvContext::~LexEnvContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + Cg()->SetLabel(node, labelSet.TryEnd()); + Cg()->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); - pg_->PopLexEnv(node); - pg_->EmitThrow(node); - pg_->SetLabel(node, labelSet.CatchEnd()); - pg_->PopLexEnv(node); + Cg()->SetLabel(node, labelSet.CatchBegin()); + AsPandaGen()->PopLexEnv(node); + AsPandaGen()->EmitThrow(node); + Cg()->SetLabel(node, labelSet.CatchEnd()); + AsPandaGen()->PopLexEnv(node); +} + +PandaGen *LexEnvContext::AsPandaGen() const +{ + return static_cast(Cg()); } bool LexEnvContext::HasTryCatch() const @@ -99,14 +105,14 @@ void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, } const auto *node = envScope_->Scope()->Node(); - pg_->PopLexEnv(node); + AsPandaGen()->PopLexEnv(node); } IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target) : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable()) { const auto &labelSet = catchTable_->LabelSet(); - pg_->SetLabel(iterator_.Node(), labelSet.TryBegin()); + pg->SetLabel(iterator_.Node(), labelSet.TryBegin()); } IteratorContext::~IteratorContext() @@ -114,18 +120,18 @@ IteratorContext::~IteratorContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = iterator_.Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + Cg()->SetLabel(node, labelSet.TryEnd()); + Cg()->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); + Cg()->SetLabel(node, labelSet.CatchBegin()); iterator_.Close(true); - pg_->SetLabel(node, labelSet.CatchEnd()); + Cg()->SetLabel(node, labelSet.CatchEnd()); } void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel) { - if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) { + if (cfc == ControlFlowChange::CONTINUE && Target().ContinueLabel() == targetLabel) { return; } @@ -140,16 +146,19 @@ void TryContext::InitFinalizer() return; } - finalizerRun_ = pg_->AllocReg(); - pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); + auto *pg = static_cast(Cg()); + + finalizerRun_ = pg->AllocReg(); + pg->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); } -void TryContext::InitCatchTable() +void CatchContext::InitCatchTable() { - catchTable_ = pg_->CreateCatchTable(); + auto *pg = static_cast(Cg()); + catchTable_ = pg->CreateCatchTable(); } -const TryLabelSet &TryContext::LabelSet() const +const TryLabelSet &CatchContext::LabelSet() const { return catchTable_->LabelSet(); } @@ -165,14 +174,10 @@ void TryContext::EmitFinalizer() return; } + auto *pg = static_cast(Cg()); inFinalizer_ = true; - tryStmt_->FinallyBlock()->Compile(pg_); + tryStmt_->FinallyBlock()->Compile(pg); inFinalizer_ = false; } -void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) -{ - EmitFinalizer(); -} } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.h b/compiler/core/dynamicContext.h index 44753babd..955ea5c17 100644 --- a/compiler/core/dynamicContext.h +++ b/compiler/core/dynamicContext.h @@ -28,12 +28,12 @@ class LabelledStatement; } // namespace panda::es2panda::ir namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class LoopEnvScope; class CatchTable; class TryLabelSet; -enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY }; +enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY, TRAP }; class DynamicContext { public: @@ -75,19 +75,28 @@ public: } protected: - explicit DynamicContext(PandaGen *pg, LabelTarget target); + explicit DynamicContext(CodeGen *cg, LabelTarget target); - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - PandaGen *pg_; + LabelTarget &Target() + { + return target_; + } + + CodeGen *Cg() const + { + return cg_; + } + +private: + CodeGen *cg_; LabelTarget target_; DynamicContext *prev_ {}; - // NOLINTEND(misc-non-private-member-variables-in-classes) }; class LabelContext : public DynamicContext { public: - explicit LabelContext(PandaGen *pg, LabelTarget target) : DynamicContext(pg, target) {} - explicit LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt); + explicit LabelContext(CodeGen *cg, LabelTarget target) : DynamicContext(cg, target) {} + explicit LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt); NO_COPY_SEMANTIC(LabelContext); NO_MOVE_SEMANTIC(LabelContext); ~LabelContext(); @@ -118,6 +127,9 @@ public: void AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel) override; +protected: + PandaGen *AsPandaGen() const; + private: LoopEnvScope *envScope_; CatchTable *catchTable_ {}; @@ -153,20 +165,46 @@ private: CatchTable *catchTable_; }; -class TryContext : public DynamicContext { +class CatchContext : public DynamicContext { public: - explicit TryContext(PandaGen *pg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) - : DynamicContext(pg, {}), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + NO_COPY_SEMANTIC(CatchContext); + NO_MOVE_SEMANTIC(CatchContext); + ~CatchContext() = default; + + CatchTable *GetCatchTable() const { - InitCatchTable(); - InitFinalizer(); + return catchTable_; } - explicit TryContext(PandaGen *pg) : DynamicContext(pg, {}) + const TryLabelSet &LabelSet() const; + + bool HasTryCatch() const override + { + return true; + } + +protected: + explicit CatchContext(CodeGen *cg) : DynamicContext(cg, {}) { InitCatchTable(); } +private: + void InitCatchTable(); + CatchTable *catchTable_ {}; +}; + +class TryContext : public CatchContext { +public: + explicit TryContext(CodeGen *cg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) + : CatchContext(cg), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + + { + InitFinalizer(); + } + + explicit TryContext(CodeGen *cg) : CatchContext(cg) {} + NO_COPY_SEMANTIC(TryContext); NO_MOVE_SEMANTIC(TryContext); ~TryContext() = default; @@ -176,38 +214,51 @@ public: return DynamicContextType::TRY; } - bool HasTryCatch() const override - { - return true; - } - VReg FinalizerRun() const { return finalizerRun_; } - CatchTable *GetCatchTable() const - { - return catchTable_; - } - - const TryLabelSet &LabelSet() const; bool HasFinalizer() const override; void InitFinalizer(); void EmitFinalizer(); void AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) override; + [[maybe_unused]] const util::StringView &targetLabel) override + { + EmitFinalizer(); + } private: - void InitCatchTable(); - const ir::TryStatement *tryStmt_ {}; - CatchTable *catchTable_ {}; VReg finalizerRun_ {}; bool hasFinalizer_ {}; bool inFinalizer_ {}; }; + +class TrapContext : public CatchContext { +public: + explicit TrapContext(CodeGen *cg) : CatchContext(cg) {} + + NO_COPY_SEMANTIC(TrapContext); + NO_MOVE_SEMANTIC(TrapContext); + ~TrapContext() = default; + + DynamicContextType Type() const override + { + return DynamicContextType::TRAP; + } + + bool HasTryCatch() const override + { + return true; + } + + bool HasFinalizer() const override + { + return false; + } +}; } // namespace panda::es2panda::compiler #endif diff --git a/compiler/core/emitter.cpp b/compiler/core/emitter.cpp index bb01bd1d3..d854586e2 100644 --- a/compiler/core/emitter.cpp +++ b/compiler/core/emitter.cpp @@ -16,21 +16,20 @@ #include "emitter.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/binder/binder.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/compiler/base/literals.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/regSpiller.h" #include "plugins/ecmascript/es2panda/compiler/debugger/debuginfoDumper.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" #include "plugins/ecmascript/es2panda/es2panda.h" -#include "generated/isa.h" -#include "plugins/ecmascript/es2panda/ir/expressions/literal.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "generated/isa.h" +#include "macros.h" #include #include @@ -108,33 +107,19 @@ static LiteralPair TransformLiteral(const compiler::Literal *literal) return {tagLit, valueLit}; } -constexpr const auto LANG_EXT = pandasm::extensions::Language::ECMASCRIPT; - void FunctionEmitter::Generate() { - auto *func = new panda::pandasm::Function(pg_->InternalName().Mutf8(), LANG_EXT); - programElement_->func = func; - - size_t paramCount = pg_->InternalParamCount(); - func->params.reserve(paramCount); - - for (uint32_t i = 0; i < paramCount; ++i) { - func->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT); - } - - func->regs_num = IRNode::REG_START - pg_->TotalRegsNum(); - func->return_type = panda::pandasm::Type("any", 0); - + auto *func = GenFunctionSignature(); GenFunctionInstructions(func); GenVariablesDebugInfo(func); GenSourceFileDebugInfo(func); GenFunctionCatchTables(func); - GenFunctionICSize(func); + GenFunctionAnnotations(func); } util::StringView FunctionEmitter::SourceCode() const { - return pg_->Binder()->Program()->SourceCode(); + return cg_->Binder()->Program()->SourceCode(); } static Format MatchFormat(const IRNode *node, const Formats &formats) @@ -155,8 +140,7 @@ static Format MatchFormat(const IRNode *node, const Formats &formats) } } - if (std::all_of(registers.begin(), registers.end(), - [limit](const VReg *reg) { return *reg >= IRNode::REG_START - limit; })) { + if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return reg->IsValid(limit); })) { return format; } } @@ -194,7 +178,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p ASSERT(astNode != nullptr); if (astNode == FIRST_NODE_OF_FUNCTION) { - astNode = pg_->Debuginfo().firstStmt; + astNode = cg_->Debuginfo().FirstStatement(); if (astNode == nullptr) { return; } @@ -202,7 +186,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p pandaIns->ins_debug.line_number = astNode->Range().start.line + 1; - if (pg_->IsDebug()) { + if (cg_->IsDebug()) { size_t insLen = GetIRNodeWholeLength(ins); if (insLen != 0) { pandaIns->ins_debug.bound_left = offset_; @@ -214,13 +198,13 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p } } -void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionInstructions(pandasm::Function *func) { - func->ins.reserve(pg_->Insns().size()); + func->ins.reserve(cg_->Insns().size()); - uint32_t totalRegs = pg_->TotalRegsNum(); + uint32_t totalRegs = cg_->TotalRegsNum(); - for (const auto *ins : pg_->Insns()) { + for (const auto *ins : cg_->Insns()) { auto &pandaIns = func->ins.emplace_back(); ins->Transform(&pandaIns, programElement_, totalRegs); @@ -228,32 +212,32 @@ void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) } } -void FunctionEmitter::GenFunctionICSize(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) { pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); pandasm::AnnotationElement icSizeAnnotationElement( "icSize", - std::make_unique(pandasm::ScalarValue::Create(pg_->IcSize()))); + std::make_unique(pandasm::ScalarValue::Create(cg_->IcSize()))); funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); pandasm::AnnotationElement parameterLengthAnnotationElement( "parameterLength", std::make_unique( - pandasm::ScalarValue::Create(pg_->FormalParametersCount()))); + pandasm::ScalarValue::Create(cg_->FormalParametersCount()))); funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); pandasm::AnnotationElement funcNameAnnotationElement( "funcName", std::make_unique( - pandasm::ScalarValue::Create(pg_->FunctionName().Mutf8()))); + pandasm::ScalarValue::Create(cg_->FunctionName().Mutf8()))); funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); func->metadata->AddAnnotations({funcAnnotationData}); } -void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionCatchTables(pandasm::Function *func) { - func->catch_blocks.reserve(pg_->CatchList().size()); + func->catch_blocks.reserve(cg_->CatchList().size()); - for (const auto *catchBlock : pg_->CatchList()) { + for (const auto *catchBlock : cg_->CatchList()) { const auto &labelSet = catchBlock->LabelSet(); auto &pandaCatchBlock = func->catch_blocks.emplace_back(); @@ -264,15 +248,15 @@ void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) } } -void FunctionEmitter::GenSourceFileDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func) { - func->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; + func->source_file = std::string {cg_->Binder()->Program()->SourceFile()}; - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - if (pg_->RootNode()->IsProgram()) { + if (cg_->RootNode()->IsProgram()) { func->source_code = SourceCode().EscapeSymbol(); } } @@ -283,12 +267,13 @@ static void GenLocalVariableInfo(pandasm::debuginfo::LocalVariable &variableDebu variableDebug.name = var->Name().Mutf8(); variableDebug.signature = "any"; variableDebug.signature_type = "any"; - variableDebug.reg = static_cast(IRNode::MapRegister(var->AsLocalVariable()->Vreg(), totalRegsNum)); + variableDebug.reg = + static_cast(IRNode::MapRegister(var->AsLocalVariable()->Vreg().GetIndex(), totalRegsNum)); variableDebug.start = start; variableDebug.length = static_cast(varsLength); } -void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const +void FunctionEmitter::GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const { const auto *startIns = scope->ScopeStart(); const auto *endIns = scope->ScopeEnd(); @@ -296,7 +281,7 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const uint32_t start = 0; uint32_t count = 0; - for (const auto *it : pg_->Insns()) { + for (const auto *it : cg_->Insns()) { if (startIns == it) { start = count; } else if (endIns == it) { @@ -305,7 +290,7 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const if (scope->IsFunctionScope()) { for (auto *param : scope->AsFunctionScope()->ParamScope()->Params()) { auto &variableDebug = func->local_variable_debug.emplace_back(); - GenLocalVariableInfo(variableDebug, param, start, varsLength, pg_->TotalRegsNum()); + GenLocalVariableInfo(variableDebug, param, start, varsLength, cg_->TotalRegsNum()); } } @@ -317,7 +302,7 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const } auto &variableDebug = func->local_variable_debug.emplace_back(); - GenLocalVariableInfo(variableDebug, variable, start, varsLength, pg_->TotalRegsNum()); + GenLocalVariableInfo(variableDebug, variable, start, varsLength, cg_->TotalRegsNum()); } break; @@ -327,27 +312,23 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const } } -void FunctionEmitter::GenVariablesDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenVariablesDebugInfo(pandasm::Function *func) { - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - for (const auto *scope : pg_->Debuginfo().variableDebugInfo) { + for (const auto *scope : cg_->Debuginfo().VariableDebugInfo()) { GenScopeVariableInfo(func, scope); } } // Emitter -Emitter::Emitter(const CompilerContext *context) +Emitter::Emitter(const CompilerContext *context) : context_(context) { prog_ = new pandasm::Program(); - prog_->lang = pandasm::extensions::Language::ECMASCRIPT; - prog_->function_table.reserve(context->Binder()->Functions().size()); - GenESAnnoatationRecord(); - GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -355,30 +336,6 @@ Emitter::~Emitter() delete prog_; } -void Emitter::GenESAnnoatationRecord() -{ - auto annotationRecord = pandasm::Record("_ESAnnotation", LANG_EXT); - annotationRecord.metadata->SetAttribute("external"); - annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); - prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); -} - -void Emitter::GenESModuleModeRecord(bool isModule) -{ - auto modeRecord = pandasm::Record("_ESModuleMode", LANG_EXT); - modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); - - auto modeField = pandasm::Field(LANG_EXT); - modeField.name = "isModule"; - modeField.type = pandasm::Type("u8", 0); - modeField.metadata->SetValue( - pandasm::ScalarValue::Create(static_cast(isModule))); - - modeRecord.field_list.emplace_back(std::move(modeField)); - - prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); -} - static void UpdateLiteralBufferId(panda::pandasm::Ins *ins, uint32_t offset) { switch (ins->opcode) { @@ -404,20 +361,20 @@ static void UpdateLiteralBufferId(panda::pandasm::Ins *ins, uint32_t offset) void Emitter::AddProgramElement(ProgramElement *programElement) { - prog_->strings.merge(programElement->strings); + prog_->strings.merge(programElement->Strings()); uint32_t newLiteralBufferIndex = literalBufferIndex_; - for (const auto &buff : programElement->buffStorage) { + for (const auto &buff : programElement->BuffStorage()) { AddLiteralBuffer(buff, newLiteralBufferIndex++); } - for (auto *ins : programElement->literalBufferIns) { + for (auto *ins : programElement->LiteralBufferIns()) { UpdateLiteralBufferId(ins, literalBufferIndex_); } literalBufferIndex_ = newLiteralBufferIndex; - auto *function = programElement->func; + auto *function = programElement->Function(); prog_->function_table.emplace(function->name, std::move(*function)); } @@ -470,13 +427,17 @@ void Emitter::AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index) prog_->literalarray_table.emplace(std::to_string(index), std::move(literalArrayInstance)); } -pandasm::Program *Emitter::Finalize(bool dumpDebugInfo) +pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, std::string_view globalClass) { if (dumpDebugInfo) { debuginfo::DebugInfoDumper dumper(prog_); dumper.Dump(); } + if (context_->Binder()->IsGenStdLib()) { + auto it = prog_->record_table.find(std::string(globalClass)); + prog_->record_table.erase(it); + } auto *prog = prog_; prog_ = nullptr; return prog; diff --git a/compiler/core/emitter.h b/compiler/core/emitter.h index 64f61251b..c27159e7f 100644 --- a/compiler/core/emitter.h +++ b/compiler/core/emitter.h @@ -13,12 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_IR_EMITTER_H -#define ES2PANDA_COMPILER_IR_EMITTER_H +#ifndef ES2PANDA_COMPILER_CORE_EMITTER_H +#define ES2PANDA_COMPILER_CORE_EMITTER_H #include "plugins/ecmascript/es2panda/compiler/base/literals.h" -#include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include @@ -32,29 +30,29 @@ namespace panda::pandasm { struct Program; struct Function; struct Ins; +namespace debuginfo { +struct LocalVariable; +} // namespace debuginfo } // namespace panda::pandasm -namespace panda::es2panda::ir { -class Statement; -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Scope; +class LocalVariable; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class DebugInfo; class Label; class IRNode; class CompilerContext; class ProgramElement; +class RegSpiller; class FunctionEmitter { public: - explicit FunctionEmitter(const PandaGen *pg, ProgramElement *programElement) - : pg_(pg), programElement_(programElement) + explicit FunctionEmitter(const CodeGen *cg, ProgramElement *programElement) + : cg_(cg), programElement_(programElement) { } @@ -64,44 +62,70 @@ public: void Generate(); -private: +protected: + virtual pandasm::Function *GenFunctionSignature() = 0; + virtual void GenFunctionAnnotations(pandasm::Function *func) = 0; + virtual void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const = 0; + void GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns); - void GenFunctionInstructions(panda::pandasm::Function *func); + void GenFunctionInstructions(pandasm::Function *func); + void GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const; + void GenSourceFileDebugInfo(pandasm::Function *func); void GenFunctionCatchTables(panda::pandasm::Function *func); - void GenFunctionICSize(panda::pandasm::Function *func); - void GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const; - void GenSourceFileDebugInfo(panda::pandasm::Function *func); - void GenVariablesDebugInfo(panda::pandasm::Function *func); + void GenVariablesDebugInfo(pandasm::Function *func); util::StringView SourceCode() const; - const PandaGen *pg_; + const CodeGen *Cg() const + { + return cg_; + } + + ProgramElement *GetProgramElement() const + { + return programElement_; + } + +private: + const CodeGen *cg_; ProgramElement *programElement_; size_t offset_ {0}; }; class Emitter { public: - explicit Emitter(const CompilerContext *context); - ~Emitter(); + virtual ~Emitter(); NO_COPY_SEMANTIC(Emitter); NO_MOVE_SEMANTIC(Emitter); - void AddFunction(FunctionEmitter *func); void AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index); void AddProgramElement(ProgramElement *programElement); - static void DumpAsm(const panda::pandasm::Program *prog); - panda::pandasm::Program *Finalize(bool dumpDebugInfo); + static void DumpAsm(const pandasm::Program *prog); + pandasm::Program *Finalize(bool dumpDebugInfo, std::string_view globalClass = ""); uint32_t &LiteralBufferIndex() { return literalBufferIndex_; } -private: - void GenESAnnoatationRecord(); - void GenESModuleModeRecord(bool isModule); + virtual void GenAnnotation() = 0; + +protected: + explicit Emitter(const CompilerContext *context); + + pandasm::Program *Program() const + { + return prog_; + } - panda::pandasm::Program *prog_; + const CompilerContext *Context() const + { + return context_; + } + +private: + pandasm::Program *prog_; + const CompilerContext *context_; uint32_t literalBufferIndex_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/envScope.cpp b/compiler/core/envScope.cpp index 6dd355c88..2b9b849e8 100644 --- a/compiler/core/envScope.cpp +++ b/compiler/core/envScope.cpp @@ -15,18 +15,19 @@ #include "envScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/ir/statement.h" namespace panda::es2panda::compiler { -ScopeContext::ScopeContext(PandaGen *pg, binder::Scope *newScope) : pg_(pg), prevScope_(pg_->scope_) +ScopeContext::ScopeContext(CodeGen *cg, binder::Scope *newScope) : cg_(cg), prevScope_(cg_->scope_) { - pg_->scope_ = newScope; + cg->scope_ = newScope; } ScopeContext::~ScopeContext() { - pg_->scope_ = prevScope_; + cg_->scope_ = prevScope_; } void EnvScope::Initialize(PandaGen *pg, VReg lexEnv) diff --git a/compiler/core/envScope.h b/compiler/core/envScope.h index ce0548c03..7de54780b 100644 --- a/compiler/core/envScope.h +++ b/compiler/core/envScope.h @@ -32,14 +32,14 @@ class PandaGen; class ScopeContext { public: - explicit ScopeContext(PandaGen *pg, binder::Scope *newScope); + explicit ScopeContext(CodeGen *cg, binder::Scope *newScope); ~ScopeContext(); NO_COPY_SEMANTIC(ScopeContext); NO_MOVE_SEMANTIC(ScopeContext); private: - PandaGen *pg_; + CodeGen *cg_; binder::Scope *prevScope_; }; diff --git a/compiler/core/function.cpp b/compiler/core/function.cpp index 17d8c1d27..8a31670d3 100644 --- a/compiler/core/function.cpp +++ b/compiler/core/function.cpp @@ -71,7 +71,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu uint32_t index = 0; for (const auto *param : func->Params()) { - LReference ref = LReference::CreateLRef(pg, param, true); + auto ref = JSLReference::Create(pg, param, true); [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); @@ -82,7 +82,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu ASSERT(paramVar && paramVar->IsLocalVariable()); - VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + IRNode::PARAM_START + index++; + VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg); if (param->IsAssignmentPattern()) { @@ -175,11 +175,11 @@ void Function::CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *dec const auto *prop = element->AsClassProperty(); - if ((prop->Modifiers() & ir::ModifierFlags::STATIC) != 0) { + if ((prop->IsStatic())) { continue; } - if (prop->IsPrivate()) { + if (prop->IsPrivateElement()) { if (prop->Value() == nullptr) { pg->LoadConst(element, Constant::JS_UNDEFINED); } else { diff --git a/compiler/core/labelTarget.cpp b/compiler/core/labelTarget.cpp index f8b39bbc6..b5cb85866 100644 --- a/compiler/core/labelTarget.cpp +++ b/compiler/core/labelTarget.cpp @@ -15,11 +15,11 @@ #include "labelTarget.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" namespace panda::es2panda::compiler { -LabelTarget::LabelTarget(PandaGen *pg) - : LabelPair(pg->AllocLabel(), pg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) +LabelTarget::LabelTarget(CodeGen *cg) + : LabelPair(cg->AllocLabel(), cg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) { } } // namespace panda::es2panda::compiler diff --git a/compiler/core/labelTarget.h b/compiler/core/labelTarget.h index e31db8f01..870d37b66 100644 --- a/compiler/core/labelTarget.h +++ b/compiler/core/labelTarget.h @@ -28,7 +28,7 @@ class Identifier; namespace panda::es2panda::compiler { class LabelTarget; -class PandaGen; +class CodeGen; enum class ControlFlowChange { CONTINUE, @@ -37,7 +37,7 @@ enum class ControlFlowChange { class LabelTarget : public LabelPair { public: - explicit LabelTarget(PandaGen *pg); + explicit LabelTarget(CodeGen *cg); explicit LabelTarget(const util::StringView &label) : LabelTarget(nullptr, label) {} explicit LabelTarget(Label *target, const util::StringView &label) : LabelPair(target, nullptr), breakLabel_(label), continueLabel_(label) diff --git a/compiler/core/pandagen.cpp b/compiler/core/pandagen.cpp index 6ff9b530d..9bacc03ce 100644 --- a/compiler/core/pandagen.cpp +++ b/compiler/core/pandagen.cpp @@ -39,132 +39,154 @@ #include "plugins/ecmascript/es2panda/ir/expressions/literals/stringLiteral.h" namespace panda::es2panda::compiler { -// PandaGen -Label *PandaGen::AllocLabel() +void PandaGen::FunctionInit(CatchTable *catchTable) { - std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); - return sa_.AllocLabel(std::move(id)); -} + if (RootNode()->IsProgram()) { + builder_ = Allocator()->New(this, catchTable); + return; + } -bool PandaGen::IsDebug() const -{ - return context_->IsDebug(); -} + const ir::ScriptFunction *func = RootNode()->AsScriptFunction(); -uint32_t PandaGen::ParamCount() const -{ - if (rootNode_->IsProgram()) { - return IsDirectEval() ? 1 : 0; + if (func->IsAsyncFunc()) { + if (func->IsGenerator()) { + builder_ = Allocator()->New(this, catchTable); + return; + } + + builder_ = Allocator()->New(this, catchTable); + return; } - return rootNode_->AsScriptFunction()->Params().size(); + if (func->IsGenerator()) { + builder_ = Allocator()->New(this, catchTable); + return; + } + + builder_ = Allocator()->New(this, catchTable); } -uint32_t PandaGen::FormalParametersCount() const +bool PandaGen::FunctionHasFinalizer() const { - if (rootNode_->IsProgram()) { - return 0; + if (RootNode()->IsProgram()) { + return false; } - ASSERT(rootNode_->IsScriptFunction()); + const ir::ScriptFunction *func = RootNode()->AsScriptFunction(); - return rootNode_->AsScriptFunction()->FormalParamsLength(); + return func->IsAsyncFunc() || func->IsGenerator(); } -uint32_t PandaGen::InternalParamCount() const +void PandaGen::FunctionEnter() { - static const uint32_t HIDDEN_PARAMS = 3; - return ParamCount() + HIDDEN_PARAMS; + builder_->Prepare(RootNode()->AsScriptFunction()); } -const util::StringView &PandaGen::InternalName() const +void PandaGen::FunctionExit() { - return topScope_->InternalName(); + builder_->CleanUp(RootNode()->AsScriptFunction()); } -const util::StringView &PandaGen::FunctionName() const +void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) { - return topScope_->Name(); + Ra().Emit(node, vreg); } -binder::Binder *PandaGen::Binder() const +void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) { - return context_->Binder(); + Ra().Emit(node, reg); } -void PandaGen::FunctionInit(CatchTable *catchTable) +void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) { - if (rootNode_->IsProgram()) { - builder_ = allocator_->New(this, catchTable); - return; - } - - const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); - - if (func->IsAsync()) { - if (func->IsGenerator()) { - builder_ = allocator_->New(this, catchTable); - return; - } - - builder_ = allocator_->New(this, catchTable); - return; - } - - if (func->IsGenerator()) { - builder_ = allocator_->New(this, catchTable); - return; - } - - builder_ = allocator_->New(this, catchTable); + Ra().Emit(node, vd, vs); } -bool PandaGen::FunctionHasFinalizer() const +void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) { - if (rootNode_->IsProgram()) { - return false; - } - - const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); + Sa().Emit(node, num); +} - return func->IsAsync() || func->IsGenerator(); +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) +{ + Sa().Emit(node, num); } -void PandaGen::FunctionEnter() +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) { - builder_->Prepare(rootNode_->AsScriptFunction()); + Sa().Emit(node, static_cast(num)); } -void PandaGen::FunctionExit() +void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) { - builder_->CleanUp(rootNode_->AsScriptFunction()); + LoadConst(node, id); + StoreAccumulator(node, reg); } -int32_t PandaGen::AddLiteralBuffer(LiteralBuffer &&buf) +void PandaGen::LoadConst(const ir::AstNode *node, Constant id) { - programElement_->buffStorage.emplace_back(std::move(buf)); - return literalBufferIdx_++; + switch (id) { + case Constant::JS_HOLE: { + Sa().Emit(node); + break; + } + case Constant::JS_NAN: { + Sa().Emit(node); + break; + } + case Constant::JS_INFINITY: { + Sa().Emit(node); + break; + } + case Constant::JS_GLOBAL: { + Sa().Emit(node); + break; + } + case Constant::JS_UNDEFINED: { + Sa().Emit(node); + break; + } + case Constant::JS_SYMBOL: { + Sa().Emit(node); + break; + } + case Constant::JS_NULL: { + Sa().Emit(node); + break; + } + case Constant::JS_TRUE: { + Sa().Emit(node); + break; + } + case Constant::JS_FALSE: { + Sa().Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } } void PandaGen::GetFunctionObject(const ir::AstNode *node) { - LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_FUNC)); + LoadAccFromLexEnv(node, Scope()->Find(binder::Binder::MANDATORY_PARAM_FUNC)); } void PandaGen::GetNewTarget(const ir::AstNode *node) { - LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_NEW_TARGET)); + LoadAccFromLexEnv(node, Scope()->Find(binder::Binder::MANDATORY_PARAM_NEW_TARGET)); } void PandaGen::GetThis(const ir::AstNode *node) { - LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS)); + LoadAccFromLexEnv(node, Scope()->Find(binder::Binder::MANDATORY_PARAM_THIS)); } void PandaGen::SetThis(const ir::AstNode *node) { - StoreAccToLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS), true); + StoreAccToLexEnv(node, Scope()->Find(binder::Binder::MANDATORY_PARAM_THIS), true); } void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result) @@ -217,20 +239,13 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & StoreAccToLexEnv(node, result, isDeclaration); } -void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) -{ - ra_.Emit(node, vreg); -} - void PandaGen::LoadAccFromArgs(const ir::AstNode *node) { - const auto *varScope = scope_->AsVariableScope(); - - if (!varScope->HasFlag(binder::VariableScopeFlags::USE_ARGS)) { + if (!Scope()->HasFlag(binder::ScopeFlags::USE_ARGS)) { return; } - binder::ScopeFindResult res = scope_->Find(binder::Binder::FUNCTION_ARGUMENTS); + binder::ScopeFindResult res = Scope()->Find(binder::Binder::FUNCTION_ARGUMENTS); ASSERT(res.scope); GetUnmappedArgs(node); @@ -287,77 +302,72 @@ void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand void PandaGen::TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::TryStoreGlobalByName(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::LoadObjByName(const ir::AstNode *node, const util::StringView &prop) { - ra_.Emit(node, prop); + Ra().Emit(node, prop); } void PandaGen::StoreObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) { - ra_.Emit(node, prop, obj); + Ra().Emit(node, prop, obj); } void PandaGen::LoadObjByIndex(const ir::AstNode *node, int64_t index) { - ra_.Emit(node, index); + Ra().Emit(node, index); } void PandaGen::LoadObjByValue(const ir::AstNode *node, VReg obj) { - ra_.Emit(node, obj); + Ra().Emit(node, obj); } void PandaGen::StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop) { - ra_.Emit(node, obj, prop); + Ra().Emit(node, obj, prop); } void PandaGen::StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index) { - ra_.Emit(node, index, obj); + Ra().Emit(node, index, obj); } void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) { - ra_.Emit(node, prop, obj); + Ra().Emit(node, prop, obj); } void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop) { - ra_.Emit(node, obj, prop); + Ra().Emit(node, obj, prop); } void PandaGen::StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index) { - ra_.Emit(node, index, obj); + Ra().Emit(node, index, obj); } void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop) { - ra_.Emit(node, obj, prop); -} - -void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) -{ - ra_.Emit(node, reg); + Ra().Emit(node, obj, prop); } void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } VReg PandaGen::LexEnv() const @@ -375,196 +385,44 @@ void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFind VirtualStoreVar::Expand(this, node, result, isDeclaration); } -void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) -{ - sa_.Emit(node, str); -} - void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt) { - sa_.Emit(node, bigInt); -} - -void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) -{ - sa_.Emit(node, static_cast(num)); -} - -void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) -{ - LoadConst(node, id); - StoreAccumulator(node, reg); -} - -void PandaGen::LoadConst(const ir::AstNode *node, Constant id) -{ - switch (id) { - case Constant::JS_HOLE: { - sa_.Emit(node); - break; - } - case Constant::JS_NAN: { - sa_.Emit(node); - break; - } - case Constant::JS_INFINITY: { - sa_.Emit(node); - break; - } - case Constant::JS_GLOBAL: { - sa_.Emit(node); - break; - } - case Constant::JS_UNDEFINED: { - sa_.Emit(node); - break; - } - case Constant::JS_SYMBOL: { - sa_.Emit(node); - break; - } - case Constant::JS_NULL: { - sa_.Emit(node); - break; - } - case Constant::JS_TRUE: { - sa_.Emit(node); - break; - } - case Constant::JS_FALSE: { - sa_.Emit(node); - break; - } - default: { - UNREACHABLE(); - } - } -} - -void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) -{ - ra_.Emit(node, vd, vs); -} - -void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) -{ - sa_.AddLabel(label); -} - -void PandaGen::Branch(const ir::AstNode *node, Label *label) -{ - sa_.Emit(node, label); -} - -bool PandaGen::CheckControlFlowChange() -{ - const auto *iter = dynamicContext_; - - while (iter != nullptr) { - if (iter->HasFinalizer()) { - return true; - } - - iter = iter->Prev(); - } - - return false; -} - -Label *PandaGen::ControlFlowChangeBreak(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL; - Label *breakTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::BREAK, labelName); - - const auto &labelTargetName = iter->Target().BreakLabel(); - - if (iter->Target().BreakTarget() != nullptr) { - breakTarget = iter->Target().BreakTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return breakTarget; -} - -Label *PandaGen::ControlFlowChangeContinue(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL; - Label *continueTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::CONTINUE, labelName); - - const auto &labelTargetName = iter->Target().ContinueLabel(); - - if (iter->Target().ContinueTarget() != nullptr) { - continueTarget = iter->Target().ContinueTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return continueTarget; + Sa().Emit(node, bigInt); } void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) { switch (op) { case lexer::TokenType::PUNCTUATOR_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } default: { @@ -579,27 +437,27 @@ void PandaGen::Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand) { switch (op) { case lexer::TokenType::PUNCTUATOR_PLUS: { - ra_.Emit(node, operand); + Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_MINUS: { - ra_.Emit(node, operand); + Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_TILDE: { - ra_.Emit(node, operand); + Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { - sa_.Emit(node); + Sa().Emit(node); break; } case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { - ra_.Emit(node, operand); + Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { - ra_.Emit(node, operand); + Ra().Emit(node, operand); break; } case lexer::TokenType::KEYW_VOID: @@ -617,103 +475,103 @@ void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) { switch (op) { case lexer::TokenType::PUNCTUATOR_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_PLUS: case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_MULTIPLY: case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_DIVIDE: case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_MOD: case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL: case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_BITWISE_AND: case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_BITWISE_OR: case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::KEYW_IN: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::KEYW_INSTANCEOF: { - ra_.Emit(node, lhs); + Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: @@ -729,56 +587,56 @@ void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) void PandaGen::BranchIfUndefined(const ir::AstNode *node, Label *target) { - sa_.Emit(node); + Sa().Emit(node); BranchIfTrue(node, target); } void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target) { - sa_.Emit(node); + Sa().Emit(node); BranchIfFalse(node, target); } void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target) { - sa_.Emit(node, target); + Sa().Emit(node, target); } void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) { - sa_.Emit(node); + Sa().Emit(node); BranchIfFalse(node, target); } void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target) { - sa_.Emit(node, target); + Sa().Emit(node, target); } void PandaGen::BranchIfCoercible(const ir::AstNode *node, Label *target) { - sa_.Emit(node); + Sa().Emit(node); BranchIfTrue(node, target); } void PandaGen::EmitThrow(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::EmitRethrow(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::EmitReturn(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::EmitReturnUndefined(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::ImplicitReturn(const ir::AstNode *node) @@ -825,25 +683,25 @@ void PandaGen::EmitAwait(const ir::AstNode *node) void PandaGen::Call0This(const ir::AstNode *node, VReg callee, VReg thisReg) { LoadAccumulator(node, thisReg); - ra_.Emit(node, callee); + Ra().Emit(node, callee); } void PandaGen::Call1This(const ir::AstNode *node, VReg callee, VReg thisReg, VReg arg0) { LoadAccumulator(node, arg0); - ra_.Emit(node, callee, thisReg); + Ra().Emit(node, callee, thisReg); } void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); switch (arguments.size()) { case 0: { // 0 args if (hasThis) { Call0This(node, callee, thisReg); } else { - sa_.Emit(node); + Sa().Emit(node); } return; } @@ -852,9 +710,9 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar arg0->Compile(this); if (hasThis) { - ra_.Emit(node, callee, thisReg); + Ra().Emit(node, callee, thisReg); } else { - ra_.Emit(node, callee); + Ra().Emit(node, callee); } return; } @@ -868,9 +726,9 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar arg1->Compile(this); if (hasThis) { - ra_.Emit(node, callee, thisReg, arg0Reg); + Ra().Emit(node, callee, thisReg, arg0Reg); } else { - ra_.Emit(node, callee, arg0Reg); + Ra().Emit(node, callee, arg0Reg); } return; } @@ -889,9 +747,9 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar arg2->Compile(this); if (hasThis) { - ra_.Emit(node, callee, thisReg, arg0Reg, arg1Reg); + Ra().Emit(node, callee, thisReg, arg0Reg, arg1Reg); } else { - ra_.Emit(node, callee, arg0Reg, arg1Reg); + Ra().Emit(node, callee, arg0Reg, arg1Reg); } return; } @@ -909,26 +767,26 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar if (hasThis) { size_t argCount = arguments.size() + 1; auto constexpr extraArgs = 2; - rra_.Emit(node, callee, argCount + extraArgs, static_cast(argCount), callee); + Rra().Emit(node, callee, argCount + extraArgs, static_cast(argCount), callee); } else { size_t argCount = arguments.size(); - rra_.Emit(node, callee, argCount + 1, static_cast(argCount), callee); + Rra().Emit(node, callee, argCount + 1, static_cast(argCount), callee); } } void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); StoreAccumulator(node, callee); Literals::GetTemplateObject(this, node->AsTaggedTemplateExpression()); if (arguments.empty()) { if (hasThis) { - ra_.Emit(node, callee, thisReg); + Ra().Emit(node, callee, thisReg); } else { - sa_.Emit(node, callee); + Sa().Emit(node, callee); } return; } @@ -942,9 +800,9 @@ void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, arg->Compile(this); if (hasThis) { - ra_.Emit(node, callee, thisReg, arg0Reg); + Ra().Emit(node, callee, thisReg, arg0Reg); } else { - ra_.Emit(node, callee, arg0Reg); + Ra().Emit(node, callee, arg0Reg); } return; } @@ -958,9 +816,9 @@ void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, arg2->Compile(this); if (hasThis) { - ra_.Emit(node, callee, thisReg, arg0Reg, arg1Reg); + Ra().Emit(node, callee, thisReg, arg0Reg, arg1Reg); } else { - ra_.Emit(node, callee, arg0Reg, arg1Reg); + Ra().Emit(node, callee, arg0Reg, arg1Reg); } return; } @@ -978,237 +836,237 @@ void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, if (hasThis) { auto constexpr extraArgs = 2; size_t argCount = arguments.size() + extraArgs; - rra_.Emit(node, callee, argCount + extraArgs, static_cast(argCount), callee); + Rra().Emit(node, callee, argCount + extraArgs, static_cast(argCount), callee); } else { size_t argCount = arguments.size() + 1; - rra_.Emit(node, callee, argCount + 1, static_cast(argCount), callee); + Rra().Emit(node, callee, argCount + 1, static_cast(argCount), callee); } } void PandaGen::SuperCall(const ir::AstNode *node, VReg startReg, size_t argCount) { - rra_.Emit(node, startReg, argCount, static_cast(argCount), startReg); + Rra().Emit(node, startReg, argCount, static_cast(argCount), startReg); } void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs) { - ra_.Emit(node, vs); + Ra().Emit(node, vs); } void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount) { - rra_.Emit(node, startReg, argCount, static_cast(argCount), startReg); + Rra().Emit(node, startReg, argCount, static_cast(argCount), startReg); } void PandaGen::LoadHomeObject(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::DefineMethod(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) { - if (realNode->IsAsync()) { + if (realNode->IsAsyncFunc()) { if (realNode->IsGenerator()) { - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } else { - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } } else if (realNode->IsGenerator()) { - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } else if (realNode->IsArrow()) { LoadHomeObject(node); - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } else if (realNode->IsMethod()) { DefineMethod(node, name); } else { - ra_.Emit(node, name, LexEnv()); + Ra().Emit(node, name, LexEnv()); } } void PandaGen::TypeOf(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args) { - ra_.Emit(node, func, thisReg, args); + Ra().Emit(node, func, thisReg, args); } void PandaGen::NewObjSpread(const ir::AstNode *node, VReg obj, VReg target) { - ra_.Emit(node, obj, target); + Ra().Emit(node, obj, target); } void PandaGen::GetUnmappedArgs(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::Negate(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::ToBoolean(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::ToNumber(const ir::AstNode *node, VReg arg) { - ra_.Emit(node, arg); + Ra().Emit(node, arg); } void PandaGen::GetMethod(const ir::AstNode *node, VReg obj, const util::StringView &name) { - ra_.Emit(node, name, obj); + Ra().Emit(node, name, obj); } void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj) { - ra_.Emit(node, funcObj); + Ra().Emit(node, funcObj); } void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj) { - ra_.Emit(node, funcObj); + Ra().Emit(node, funcObj); } void PandaGen::CreateIterResultObject(const ir::AstNode *node, bool done) { - ra_.Emit(node, static_cast(done)); + Ra().Emit(node, static_cast(done)); } void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj); + Ra().Emit(node, genObj); } void PandaGen::SuspendAsyncGenerator(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + Ra().Emit(node, asyncGenObj); } void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj, static_cast(GeneratorState::SUSPENDED_YIELD)); + Ra().Emit(node, genObj, static_cast(GeneratorState::SUSPENDED_YIELD)); } void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj, static_cast(GeneratorState::COMPLETED)); + Ra().Emit(node, genObj, static_cast(GeneratorState::COMPLETED)); } void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj); + Ra().Emit(node, genObj); } void PandaGen::GetResumeMode(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj); + Ra().Emit(node, genObj); } void PandaGen::AsyncFunctionEnter(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj) { - ra_.Emit(node, asyncFuncObj); + Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj) { - ra_.Emit(node, asyncFuncObj); + Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj) { - ra_.Emit(node, asyncFuncObj); + Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + Ra().Emit(node, asyncGenObj); } void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + Ra().Emit(node, asyncGenObj); } void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value) { - ra_.Emit(node, value); + Ra().Emit(node, value); } void PandaGen::CopyRestArgs(const ir::AstNode *node, uint32_t index) { - sa_.Emit(node, index); + Sa().Emit(node, index); } void PandaGen::GetPropIterator(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::GetNextPropName(const ir::AstNode *node, VReg iter) { - ra_.Emit(node, iter); + Ra().Emit(node, iter); } void PandaGen::CreateEmptyObject(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx) { ASSERT(util::Helpers::IsInteger(idx)); - sa_.Emit(node, util::Helpers::ToStringView(allocator_, idx)); + Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } void PandaGen::CreateObjectHavingMethod(const ir::AstNode *node, uint32_t idx) { ASSERT(util::Helpers::IsInteger(idx)); LoadAccumulator(node, LexEnv()); - sa_.Emit(node, util::Helpers::ToStringView(allocator_, idx)); + Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } void PandaGen::SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj) { - ra_.Emit(node, proto, obj); + Ra().Emit(node, proto, obj); } void PandaGen::CopyDataProperties(const ir::AstNode *node, VReg dst, VReg src) { - ra_.Emit(node, dst, src); + Ra().Emit(node, dst, src); } void PandaGen::DefineGetterSetterByValue(const ir::AstNode *node, VReg obj, VReg name, VReg getter, VReg setter, bool setName) { LoadConst(node, setName ? Constant::JS_TRUE : Constant::JS_FALSE); - ra_.Emit(node, obj, name, getter, setter); + Ra().Emit(node, obj, name, getter, setter); } void PandaGen::CreateEmptyArray(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx) { ASSERT(util::Helpers::IsInteger(idx)); - sa_.Emit(node, util::Helpers::ToStringView(allocator_, idx)); + Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector &elements, VReg obj) @@ -1312,144 +1170,144 @@ void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector(node, array, index); + Ra().Emit(node, array, index); } void PandaGen::CreateRegExpWithLiteral(const ir::AstNode *node, const util::StringView &pattern, uint8_t flags) { - sa_.Emit(node, pattern, flags); + Sa().Emit(node, pattern, flags); } void PandaGen::ThrowIfNotObject(const ir::AstNode *node) { - ra_.Emit(node); + Ra().Emit(node); } void PandaGen::ThrowThrowNotExist(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::GetIterator(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::GetAsyncIterator(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) { - ASSERT(argStart == obj - 1); + ASSERT(argStart.GetIndex() == obj.GetIndex() - 1); if (argCount == 0) { // Do not emit undefined register argStart = obj; } - rra_.Emit(node, argStart, argCount, static_cast(argCount), obj, - argStart); + Rra().Emit(node, argStart, argCount, static_cast(argCount), obj, + argStart); } void PandaGen::ThrowObjectNonCoercible(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter) { - ra_.Emit(node, iter); + Ra().Emit(node, iter); } void PandaGen::ImportModule(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::SetClassComputedFields(const ir::AstNode *node, VReg classReg, VReg computedInstanceFieldArray) { - ra_.Emit(node, classReg, computedInstanceFieldArray); + Ra().Emit(node, classReg, computedInstanceFieldArray); } void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg lexenv, VReg base) { - ra_.Emit(node, ctorId, litIdx, lexenv, base); + Ra().Emit(node, ctorId, litIdx, lexenv, base); } void PandaGen::LoadClassComputedInstanceFields(const ir::AstNode *node, VReg ctor) { - sa_.Emit(node, ctor); + Sa().Emit(node, ctor); } void PandaGen::DefineClassPrivateFields(const ir::AstNode *node, int32_t privateBufIdx) { - sa_.Emit(node, util::Helpers::ToStringView(allocator_, privateBufIdx), LexEnv()); + Sa().Emit(node, util::Helpers::ToStringView(Allocator(), privateBufIdx), LexEnv()); } void PandaGen::ClassFieldAdd(const ir::AstNode *node, VReg obj, VReg prop) { - ra_.Emit(node, obj, prop); + Ra().Emit(node, obj, prop); } void PandaGen::ClassPrivateFieldAdd(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { - ra_.Emit(node, prop, ctor, obj); + Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateMethodOrAccessorAdd(const ir::AstNode *node, VReg ctor, VReg obj) { - ra_.Emit(node, ctor, obj); + Ra().Emit(node, ctor, obj); } void PandaGen::ClassPrivateFieldGet(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { - ra_.Emit(node, prop, ctor, obj); + Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateFieldSet(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { - ra_.Emit(node, prop, ctor, obj); + Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateFieldIn(const ir::AstNode *node, VReg ctor, const util::StringView &prop) { - ra_.Emit(node, prop, ctor); + Ra().Emit(node, prop, ctor); } void PandaGen::LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name) { - ra_.Emit(node, name, module); + Ra().Emit(node, name, module); } void PandaGen::StoreModuleVar(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::CopyModule(const ir::AstNode *node, VReg module) { - ra_.Emit(node, module); + Ra().Emit(node, module); } void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) { - ra_.Emit(node, key, obj); + Ra().Emit(node, key, obj); } void PandaGen::LdSuperByName(const ir::AstNode *node, const util::StringView &key) { - ra_.Emit(node, key); + Ra().Emit(node, key); } void PandaGen::StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop) { - ra_.Emit(node, obj, prop); + Ra().Emit(node, obj, prop); } void PandaGen::LdSuperByValue(const ir::AstNode *node, VReg obj) { - ra_.Emit(node, obj); + Ra().Emit(node, obj); } void PandaGen::StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop) @@ -1476,91 +1334,62 @@ void PandaGen::LoadSuperProperty(const ir::AstNode *node, const Operand &prop) void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) { - sa_.Emit(node, level, slot); + Sa().Emit(node, level, slot); } void PandaGen::LoadLexical(const ir::AstNode *node, const util::StringView &name, uint32_t level, uint32_t slot) { - sa_.Emit(node, name, level, slot); + Sa().Emit(node, name, level, slot); } void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) { - ra_.Emit(node, level, slot); + Ra().Emit(node, level, slot); } void PandaGen::StoreLexical(const ir::AstNode *node, const util::StringView &name, uint32_t level, uint32_t slot) { - ra_.Emit(node, name, level, slot); + Ra().Emit(node, name, level, slot); } void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num) { - sa_.Emit(node, num); + Sa().Emit(node, num); } void PandaGen::ThrowTdz(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + Sa().Emit(node, name); } void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, name); + Ra().Emit(node, name); } void PandaGen::PopLexEnv(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::CopyLexEnv(const ir::AstNode *node) { - sa_.Emit(node); + Sa().Emit(node); } void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num) { - sa_.Emit(node, num); + Sa().Emit(node, num); } void PandaGen::LdLexEnv(const ir::AstNode *node) { - sa_.Emit(node); -} - -uint32_t PandaGen::TryDepth() const -{ - const auto *iter = dynamicContext_; - uint32_t depth = 0; - - while (iter != nullptr) { - if (iter->HasTryCatch()) { - depth++; - } - - iter = iter->Prev(); - } - - return depth; -} - -CatchTable *PandaGen::CreateCatchTable() -{ - auto *catchTable = allocator_->New(this, TryDepth()); - catchList_.push_back(catchTable); - return catchTable; -} - -void PandaGen::SortCatchTables() -{ - std::sort(catchList_.begin(), catchList_.end(), - [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); + Sa().Emit(node); } Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed) { - VReg res {IRNode::REG_START}; + VReg res {VReg::REG_START}; if (!isComputed) { if (prop->IsIdentifier()) { @@ -1586,7 +1415,7 @@ Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed } if (prop->IsNumberLiteral()) { - auto num = prop->AsNumberLiteral()->Number(); + auto num = prop->AsNumberLiteral()->Number().GetDouble(); if (util::Helpers::IsIndex(num)) { return static_cast(num); } @@ -1660,7 +1489,7 @@ void PandaGen::LoadEvalVariable(const ir::AstNode *node, const util::StringView { RegScope rs(this); LoadLexicalContext(node); - ra_.Emit(node, name); + Ra().Emit(node, name); } void PandaGen::StoreEvalVariable(const ir::AstNode *node, const util::StringView &name) @@ -1669,7 +1498,7 @@ void PandaGen::StoreEvalVariable(const ir::AstNode *node, const util::StringView VReg value = AllocReg(); StoreAccumulator(node, value); LoadLexicalContext(node); - ra_.Emit(node, name, value); + Ra().Emit(node, name, value); } void PandaGen::DirectEval(const ir::AstNode *node, uint32_t parserStatus) @@ -1698,12 +1527,12 @@ void PandaGen::DirectEval(const ir::AstNode *node, uint32_t parserStatus) LoadAccumulator(node, LexEnv()); StOwnByIndex(node, evalBindings, evalBindingsIndex++); - const auto *iter = scope_->EnclosingVariableScope(); + const auto *iter = Scope()->EnclosingVariableScope(); while (true) { uint32_t scopeBindingsBuf = iter->EvalBindings(); if (scopeBindingsBuf != INVALID_LITERAL_BUFFER_ID) { - sa_.Emit(node, util::Helpers::ToStringView(allocator_, scopeBindingsBuf)); + Sa().Emit(node, util::Helpers::ToStringView(Allocator(), scopeBindingsBuf)); StOwnByIndex(node, evalBindings, evalBindingsIndex++); } @@ -1717,22 +1546,22 @@ void PandaGen::DirectEval(const ir::AstNode *node, uint32_t parserStatus) LoadAccumulator(node, evalBindings); StOwnByIndex(node, bindings, index++); - sa_.Emit(node, static_cast(parserStatus), arg0, bindings); + Sa().Emit(node, static_cast(parserStatus), arg0, bindings); } void PandaGen::LoadLexicalContext(const ir::AstNode *node) { - auto result = scope_->Find(binder::Binder::LEXICAL_CONTEXT_PARAM); + auto result = Scope()->Find(binder::Binder::LEXICAL_CONTEXT_PARAM); LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx()); } bool PandaGen::IsDirectEval() const { - return context_->IsDirectEval(); + return Context()->IsDirectEval(); } bool PandaGen::IsEval() const { - return context_->IsEval(); + return Context()->IsEval(); } } // namespace panda::es2panda::compiler diff --git a/compiler/core/pandagen.h b/compiler/core/pandagen.h index 03b65f927..0c9aff7de 100644 --- a/compiler/core/pandagen.h +++ b/compiler/core/pandagen.h @@ -16,10 +16,11 @@ #ifndef ES2PANDA_COMPILER_CORE_PANDAGEN_H #define ES2PANDA_COMPILER_CORE_PANDAGEN_H -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/base/optionalChain.h" #include "plugins/ecmascript/es2panda/compiler/core/envScope.h" -#include "plugins/ecmascript/es2panda/compiler/core/inlineCache.h" +#include "plugins/ecmascript/es2panda/compiler/core/function.h" + #include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" #include "plugins/ecmascript/es2panda/compiler/core/regScope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -46,115 +47,20 @@ namespace panda::es2panda::compiler { class FunctionBuilder; class CompilerContext; class DynamicContext; -class CatchTable; - -enum class Constant { - JS_NAN, - JS_HOLE, - JS_INFINITY, - JS_UNDEFINED, - JS_NULL, - JS_TRUE, - JS_FALSE, - JS_SYMBOL, - JS_GLOBAL, -}; - -class DebugInfo { -public: - explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {}; - DEFAULT_COPY_SEMANTIC(DebugInfo); - DEFAULT_MOVE_SEMANTIC(DebugInfo); - ~DebugInfo() = default; - - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - ArenaVector variableDebugInfo; - const ir::Statement *firstStmt {}; - // NOLINTEND(misc-non-private-member-variables-in-classes) -}; -class PandaGen { +class PandaGen : public CodeGen { public: - explicit PandaGen(ArenaAllocator *allocator, CompilerContext *context, binder::FunctionScope *scope, - ProgramElement *programElement) - : allocator_(allocator), - context_(context), - debugInfo_(allocator_), - topScope_(scope), - scope_(topScope_), - rootNode_(scope->Node()), - insns_(allocator_->Adapter()), - catchList_(allocator_->Adapter()), - programElement_(programElement), - sa_(this), - ra_(this), - rra_(this) + explicit PandaGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement) { + Function::Compile(this); } + ~PandaGen() = default; NO_COPY_SEMANTIC(PandaGen); NO_MOVE_SEMANTIC(PandaGen); - inline ArenaAllocator *Allocator() const - { - return allocator_; - } - - const ArenaVector &CatchList() const - { - return catchList_; - } - - binder::FunctionScope *TopScope() const - { - return topScope_; - } - - binder::Scope *Scope() const - { - return scope_; - } - - const ir::AstNode *RootNode() const - { - return rootNode_; - } - - ArenaList &Insns() - { - return insns_; - } - - const ArenaList &Insns() const - { - return insns_; - } - - VReg AllocReg() - { - return usedRegs_--; - } - - VReg NextReg() const - { - return usedRegs_; - } - - uint32_t TotalRegsNum() const - { - return totalRegs_; - } - - size_t LabelCount() const - { - return labelId_; - } - - const DebugInfo &Debuginfo() const - { - return debugInfo_; - } - FunctionBuilder *FuncBuilder() const { return builder_; @@ -172,21 +78,6 @@ public: } } - uint32_t IcSize() const - { - return ic_.Size(); - } - - bool IsDebug() const; - uint32_t ParamCount() const; - uint32_t FormalParametersCount() const; - uint32_t InternalParamCount() const; - const util::StringView &InternalName() const; - const util::StringView &FunctionName() const; - binder::Binder *Binder() const; - - Label *AllocLabel(); - VReg LexEnv() const; bool FunctionHasFinalizer() const; @@ -194,7 +85,16 @@ public: void FunctionEnter(); void FunctionExit(); - int32_t AddLiteralBuffer(LiteralBuffer &&buf); + void StoreAccumulator(const ir::AstNode *node, VReg vreg); + void LoadAccumulator(const ir::AstNode *node, VReg reg); + void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); + + void LoadAccumulatorFloat(const ir::AstNode *node, double num); + void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); + void LoadAccumulatorInt(const ir::AstNode *node, size_t num); + + void LoadConst(const ir::AstNode *node, Constant id); + void StoreConst(const ir::AstNode *node, VReg reg, Constant id); void GetFunctionObject(const ir::AstNode *node); void GetNewTarget(const ir::AstNode *node); @@ -203,7 +103,6 @@ public: void LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result); void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void StoreAccumulator(const ir::AstNode *node, VReg vreg); void LoadAccFromArgs(const ir::AstNode *node); void LoadObjProperty(const ir::AstNode *node, const Operand &prop); @@ -212,7 +111,6 @@ public: void StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop); - void LoadAccumulator(const ir::AstNode *node, VReg reg); void LoadGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalLet(const ir::AstNode *node, const util::StringView &name); @@ -225,21 +123,7 @@ public: void LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result); void StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); void LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt); - void LoadAccumulatorFloat(const ir::AstNode *node, double num); - void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); - void LoadAccumulatorInt(const ir::AstNode *node, size_t num); - - void LoadConst(const ir::AstNode *node, Constant id); - void StoreConst(const ir::AstNode *node, VReg reg, Constant id); - void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); - - void SetLabel(const ir::AstNode *node, Label *label); - void Branch(const ir::AstNode *node, class Label *label); - bool CheckControlFlowChange(); - Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); - Label *ControlFlowChangeContinue(const ir::Identifier *label); void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, class Label *ifFalse); void Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand); @@ -248,6 +132,7 @@ public: void BranchIfUndefined(const ir::AstNode *node, class Label *target); void BranchIfNotUndefined(const ir::AstNode *node, class Label *target); void BranchIfHole(const ir::AstNode *node, class Label *target); + void BranchIfTrue(const ir::AstNode *node, class Label *target); void BranchIfNotTrue(const ir::AstNode *node, class Label *target); void BranchIfFalse(const ir::AstNode *node, class Label *target); @@ -369,10 +254,6 @@ public: void ThrowTdz(const ir::AstNode *node, const util::StringView &name); void ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name); - uint32_t TryDepth() const; - CatchTable *CreateCatchTable(); - void SortCatchTables(); - void LoadObjByIndex(const ir::AstNode *node, int64_t index); void LoadObjByValue(const ir::AstNode *node, VReg obj); @@ -397,52 +278,17 @@ public: bool IsDirectEval() const; bool IsEval() const; - void SetFirstStmt(const ir::Statement *stmt) - { - debugInfo_.firstStmt = stmt; - } - - [[noreturn]] static void Unimplemented() - { - throw Error(ErrorType::GENERIC, "Unimplemented code path"); - } - private: void LoadEvalBindings(const ir::AstNode *node); - ArenaAllocator *allocator_; - CompilerContext *context_; FunctionBuilder *builder_ {}; - DebugInfo debugInfo_; - binder::FunctionScope *topScope_; - binder::Scope *scope_; - const ir::AstNode *rootNode_; - ArenaList insns_; - ArenaVector catchList_; - ProgramElement *programElement_; - EnvScope *envScope_ {}; - DynamicContext *dynamicContext_ {}; OptionalChain *optionalChain_ {}; - InlineCache ic_; - SimpleAllocator sa_; - RegAllocator ra_; - RangeRegAllocator rra_; - - uint32_t usedRegs_ {IRNode::REG_START}; - uint32_t totalRegs_ {IRNode::REG_START}; - int32_t literalBufferIdx_ {0}; - friend class ScopeContext; - friend class RegScope; - friend class LocalRegScope; - friend class LoopRegScope; - friend class ParamRegScope; - friend class FunctionRegScope; + friend class EnvScope; friend class LoopEnvScope; friend class DynamicContext; friend class OptionalChain; - size_t labelId_ {0}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/programElement.cpp b/compiler/core/programElement.cpp new file mode 100644 index 000000000..64a9951a1 --- /dev/null +++ b/compiler/core/programElement.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "programElement.h" + +#include + +namespace panda::es2panda::compiler { +std::unordered_set &ProgramElement::Strings() +{ + return strings_; +} + +std::vector &ProgramElement::LiteralBufferIns() +{ + return literalBufferIns_; +} + +std::vector &ProgramElement::BuffStorage() +{ + return buffStorage_; +} + +pandasm::Function *ProgramElement::Function() +{ + return func_; +} + +void ProgramElement::SetFunction(pandasm::Function *func) +{ + func_ = func; +} + +ProgramElement::~ProgramElement() +{ + delete func_; +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/programElement.h b/compiler/core/programElement.h new file mode 100644 index 000000000..4a750dc7b --- /dev/null +++ b/compiler/core/programElement.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H +#define ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" + +namespace panda::pandasm { +struct Ins; +struct Function; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { +class ProgramElement { +public: + explicit ProgramElement() = default; + ~ProgramElement(); + NO_COPY_SEMANTIC(ProgramElement); + NO_MOVE_SEMANTIC(ProgramElement); + + std::unordered_set &Strings(); + std::vector &LiteralBufferIns(); + std::vector &BuffStorage(); + pandasm::Function *Function(); + void SetFunction(pandasm::Function *func); + +private: + std::unordered_set strings_; + std::vector literalBufferIns_; + std::vector buffStorage_; + pandasm::Function *func_ {}; +}; +} // namespace panda::es2panda::compiler +#endif diff --git a/compiler/core/regAllocator.cpp b/compiler/core/regAllocator.cpp index 13a408947..e95c6c7d4 100644 --- a/compiler/core/regAllocator.cpp +++ b/compiler/core/regAllocator.cpp @@ -15,70 +15,76 @@ #include "regAllocator.h" -#include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" #include namespace panda::es2panda::compiler { -// RegAllocatorBase void AllocatorBase::PushBack(IRNode *ins) { - pg_->Insns().push_back(ins); + cg_->Insns().push_back(ins); } ArenaAllocator *AllocatorBase::Allocator() const { - return pg_->Allocator(); + return cg_->Allocator(); } // SimpleAllocator Label *SimpleAllocator::AllocLabel(std::string &&id) { - const auto *lastInsNode = pg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : pg_->Insns().back()->Node(); + const auto *lastInsNode = cg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : cg_->Insns().back()->Node(); return Alloc - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -543,4 +543,4 @@ java.util.ServiceConfigurationError - \ No newline at end of file + diff --git a/migrator/test/java-mapper/CallExpressionRules2.java.sts b/migrator/test/java-mapper/CallExpressionRules2.java.sts index 94338300f..0fffa6ed2 100644 --- a/migrator/test/java-mapper/CallExpressionRules2.java.sts +++ b/migrator/test/java-mapper/CallExpressionRules2.java.sts @@ -28,4 +28,3 @@ open class CallExpressiontRules1 { // // System.out.println(d); } - diff --git a/migrator/test/java-mapper/ImportRules1.java b/migrator/test/java-mapper/ImportRules1.java index eac157cee..9f9925794 100644 --- a/migrator/test/java-mapper/ImportRules1.java +++ b/migrator/test/java-mapper/ImportRules1.java @@ -41,4 +41,4 @@ class ImportRules1 { int[] c = Arrays.copyOf(array, array.length); } -} \ No newline at end of file +} -- Gitee From 154e75a3708a20bc91c9427faa87b45a96b12ec8 Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Wed, 16 Nov 2022 12:40:16 +0300 Subject: [PATCH 14/15] A special targed 'test_java_api' is added to the build script to run API mapping tests. Change-Id: Ia8d1807ab910593020e71ac6dd73e803dbbb7532 Signed-off-by: Alexander Pavlyuk --- migrator/config/java-api-mapper.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/migrator/config/java-api-mapper.xml b/migrator/config/java-api-mapper.xml index 76724836a..9c6fd4902 100644 --- a/migrator/config/java-api-mapper.xml +++ b/migrator/config/java-api-mapper.xml @@ -474,20 +474,20 @@ java.util.ServiceConfigurationError - - - - - - - - - - - - - - + + + + + + + + + + + + + + -- Gitee From 50f0f846a5ea07d5150d3705397b939791fb6703 Mon Sep 17 00:00:00 2001 From: Alexander Pavlyuk Date: Tue, 22 Nov 2022 15:39:23 +0300 Subject: [PATCH 15/15] Post merge fix after rebase to master. Change-Id: I17771e5bf1bc92866650214e8bfbaebbf924f5b5 Signed-off-by: Alexander Pavlyuk --- migrator/build.xml | 10 +++++++++- migrator/src/com/ohos/migrator/TestRunner.java | 1 + .../src/com/ohos/migrator/java/JavaTranspiler.java | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/migrator/build.xml b/migrator/build.xml index 14f3fdfdd..d5bcd10d3 100644 --- a/migrator/build.xml +++ b/migrator/build.xml @@ -222,6 +222,14 @@ + + + + + + + + @@ -247,7 +255,7 @@ - diff --git a/migrator/src/com/ohos/migrator/TestRunner.java b/migrator/src/com/ohos/migrator/TestRunner.java index cf31671bd..fc9073e94 100644 --- a/migrator/src/com/ohos/migrator/TestRunner.java +++ b/migrator/src/com/ohos/migrator/TestRunner.java @@ -38,6 +38,7 @@ public class TestRunner { // NOTE: Add languages here when comments // migration is implemented for them! langsWithCommentsMigration.add("java"); + langsWithCommentsMigration.add("java-mapper"); } private static boolean usesOffset(String lang) { diff --git a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java index f7ad0436e..ebeb8c4b8 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java +++ b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java @@ -115,6 +115,10 @@ public class JavaTranspiler extends AbstractTranspiler { { try { File path = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); + if (path.getName().toLowerCase().endsWith(".jar")) { + path = path.getParentFile(); + } + File configDir = new File(path, "config"); File f = new File(configDir, "java-api-mapper.xml"); String rulesFilePath = f.getPath(); -- Gitee