add ark ts2abc

Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I3f5f1ddb0ff30ce85c8cccace6d78b7030cff2c6
This commit is contained in:
wanyanglan
2021-09-04 15:59:33 +08:00
parent 8b2cecfdab
commit d035862fba
147 changed files with 48551 additions and 63 deletions
+5
View File
@@ -0,0 +1,5 @@
as2panda/bin/* text eol=lf
as2panda/dist/* binary
as2panda/scripts/*.sh eol=lf
as2panda/lib/binaryen.js binary
as2panda/tests/compiler/std/string-encoding.ts eol=lf
+4
View File
@@ -0,0 +1,4 @@
test262/data/
test262/eshost/
test262/harness/
out/
+196
View File
@@ -0,0 +1,196 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
The "ts2panda\scripts\diagnosticMessages.json" file may contain
some information or content from the following software:
TypeScript
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
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
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
Apache License 2.0
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<policy name="defaultPolicy" desc="" >
<policyitem type="compatibility" name="Apache" path="ark/ts2abc" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter" desc=""/>
</policy>
<filefilterlist>
<filefilter name="binaryFileTypePolicyFilter" desc="二进制文件校验策略的过滤条件" >
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="copyright文件头校验策略的过滤条件" >
</filefilter>
<filefilter name="defaultPolicyFilter" desc="根目录LICENSE文件校验策略的过滤条件xxx" >
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>
-36
View File
@@ -1,36 +0,0 @@
# ark_ts2abc
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+181 -27
View File
@@ -1,39 +1,193 @@
# ark_ts2abc
# ts2abc <a name="EN-US_TOPIC_0000001137330686"></a>
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
- [Introduction](#section11660541593)
- [Directory Structure](#section161941989596)
- [Note](#section0446154755015)
- [Usage Guidelines](#section33105542504)
#### 软件架构
软件架构说明
- [Repositories Involved](#section1371113476307)
## Introduction<a name="section11660541593"></a>
#### 安装教程
As a module of the ARK platform, ts2abc is a front-end tool for JavaScript \(JS\) in the ARK compiler. It converts JS files into ARK bytecode files.
1. xxxx
2. xxxx
3. xxxx
## Directory Structure<a name="section161941989596"></a>
#### 使用说明
```
/ark/ts2abc/
├── ts2panda
├── doc # Documents
├── scripts # Dependency scripts
├── src # Source code directory
├── templates # Ruby templates
├── tests # Unit test cases
├── tools # Tools provided by ts2abc
└── ts2abc # ts2abc source code
```
1. xxxx
2. xxxx
3. xxxx
## Note<a name="section0446154755015"></a>
#### 参与贡献
ts2abc uses the command line interaction mode and converts JS code into ARK bytecode files that can be run on an ARK runtime system. ts2abc supports Windows, Linux, and macOS.
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
### Usage Guidelines<a name="section33105542504"></a>
You can run **node --expose-gc _your\_path_\_to/index.js \[options\] _your\_file_.js** to convert a JS file into an ARK bytecode file using ts2abc. If no parameter is specified for **\[options\]**, an ARK binary file is generated by default. The **index.js** file is the executable file generated after ts2abc compilation.
#### 特技
<a name="table2035444615598"></a>
<table><thead align="left"><tr id="row535415467591"><th class="cellrowborder" valign="top" width="12.898710128987101%" id="mcps1.1.6.1.1"><p id="p13354134619595"><a name="p13354134619595"></a><a name="p13354134619595"></a>Option</p>
</th>
<th class="cellrowborder" valign="top" width="6.869313068693131%" id="mcps1.1.6.1.2"><p id="p1584312189018"><a name="p1584312189018"></a><a name="p1584312189018"></a>Abbreviation</p>
</th>
<th class="cellrowborder" valign="top" width="19.33806619338066%" id="mcps1.1.6.1.3"><p id="p157281281906"><a name="p157281281906"></a><a name="p157281281906"></a>Description</p>
</th>
<th class="cellrowborder" valign="top" width="25.82741725827417%" id="mcps1.1.6.1.4"><p id="p103276335016"><a name="p103276335016"></a><a name="p103276335016"></a>Value Range</p>
</th>
<th class="cellrowborder" valign="top" width="35.066493350664935%" id="mcps1.1.6.1.5"><p id="p1835494695915"><a name="p1835494695915"></a><a name="p1835494695915"></a>Default Value</p>
</th>
</tr>
</thead>
<tbody><tr id="row1435412465598"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p881325510017"><a name="p881325510017"></a><a name="p881325510017"></a>--modules</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p148431189013"><a name="p148431189013"></a><a name="p148431189013"></a>-m</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p072882813015"><a name="p072882813015"></a><a name="p072882813015"></a>Compiles the code based on the module.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p10327833305"><a name="p10327833305"></a><a name="p10327833305"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p076075115014"><a name="p076075115014"></a><a name="p076075115014"></a>-</p>
</td>
</tr>
<tr id="row3355346105920"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p163552462595"><a name="p163552462595"></a><a name="p163552462595"></a>--debug-log</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p48431918607"><a name="p48431918607"></a><a name="p48431918607"></a>-l</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p127284281905"><a name="p127284281905"></a><a name="p127284281905"></a>Enables the log function.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p93278335012"><a name="p93278335012"></a><a name="p93278335012"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1976019511306"><a name="p1976019511306"></a><a name="p1976019511306"></a>-</p>
</td>
</tr>
<tr id="row9355174675912"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p6355104616592"><a name="p6355104616592"></a><a name="p6355104616592"></a>--dump-assembly</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p20843161819020"><a name="p20843161819020"></a><a name="p20843161819020"></a>-a</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p187287280015"><a name="p187287280015"></a><a name="p187287280015"></a>Outputs an assembly file.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p932819331104"><a name="p932819331104"></a><a name="p932819331104"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1475975114013"><a name="p1475975114013"></a><a name="p1475975114013"></a>-</p>
</td>
</tr>
<tr id="row53551046175917"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p13575501218"><a name="p13575501218"></a><a name="p13575501218"></a>--debug</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p48431818104"><a name="p48431818104"></a><a name="p48431818104"></a>-d</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p1372811281608"><a name="p1372811281608"></a><a name="p1372811281608"></a>Provides debug information.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p133287335020"><a name="p133287335020"></a><a name="p133287335020"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p37585513019"><a name="p37585513019"></a><a name="p37585513019"></a>-</p>
</td>
</tr>
<tr id="row8355204635911"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p657125010117"><a name="p657125010117"></a><a name="p657125010117"></a>--show-statistics</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p98433181905"><a name="p98433181905"></a><a name="p98433181905"></a>-s</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p77281528704"><a name="p77281528704"></a><a name="p77281528704"></a>Displays statistics about bytecodes.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p83281633208"><a name="p83281633208"></a><a name="p83281633208"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p17580511404"><a name="p17580511404"></a><a name="p17580511404"></a>-</p>
</td>
</tr>
<tr id="row6355124665910"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p105611505114"><a name="p105611505114"></a><a name="p105611505114"></a>--output</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1884310183014"><a name="p1884310183014"></a><a name="p1884310183014"></a>-o</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p20728192819015"><a name="p20728192819015"></a><a name="p20728192819015"></a>Specifies the path of the output file.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p1332810331508"><a name="p1332810331508"></a><a name="p1332810331508"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p157577519014"><a name="p157577519014"></a><a name="p157577519014"></a>-</p>
</td>
</tr>
<tr id="row235584610599"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p95515501012"><a name="p95515501012"></a><a name="p95515501012"></a>--timeout</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1684312184012"><a name="p1684312184012"></a><a name="p1684312184012"></a>-t</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p37282028600"><a name="p37282028600"></a><a name="p37282028600"></a>Specifies the timeout threshold.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p133281033804"><a name="p133281033804"></a><a name="p133281033804"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p675665112019"><a name="p675665112019"></a><a name="p675665112019"></a>-</p>
</td>
</tr>
<tr id="row135584635915"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p4551501217"><a name="p4551501217"></a><a name="p4551501217"></a>--opt-log-level</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1843181819011"><a name="p1843181819011"></a><a name="p1843181819011"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p157285282020"><a name="p157285282020"></a><a name="p157285282020"></a>Specifies the log level for compilation optimization.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p1532819334016"><a name="p1532819334016"></a><a name="p1532819334016"></a>['debug', 'info', 'error', 'fatal']</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p475510516018"><a name="p475510516018"></a><a name="p475510516018"></a>error</p>
</td>
</tr>
<tr id="row133555461596"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p3541550416"><a name="p3541550416"></a><a name="p3541550416"></a>--opt-level</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p148441518404"><a name="p148441518404"></a><a name="p148441518404"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p27281728502"><a name="p27281728502"></a><a name="p27281728502"></a>Specifies the level for compilation optimization.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p832833312018"><a name="p832833312018"></a><a name="p832833312018"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1975514517020"><a name="p1975514517020"></a><a name="p1975514517020"></a>1</p>
</td>
</tr>
<tr id="row23556463595"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p135313506120"><a name="p135313506120"></a><a name="p135313506120"></a>--help</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p168448187012"><a name="p168448187012"></a><a name="p168448187012"></a>-h</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p97284281607"><a name="p97284281607"></a><a name="p97284281607"></a>Displays help information.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p43281335010"><a name="p43281335010"></a><a name="p43281335010"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p57545511102"><a name="p57545511102"></a><a name="p57545511102"></a>-</p>
</td>
</tr>
<tr id="row5356124655916"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p185311501910"><a name="p185311501910"></a><a name="p185311501910"></a>--bc-version</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p6844141810019"><a name="p6844141810019"></a><a name="p6844141810019"></a>-v</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p1872818281006"><a name="p1872818281006"></a><a name="p1872818281006"></a>Outputs the current bytecode version.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p73281733408"><a name="p73281733408"></a><a name="p73281733408"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p77537511606"><a name="p77537511606"></a><a name="p77537511606"></a>-</p>
</td>
</tr>
<tr id="row1335654635915"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p175213504115"><a name="p175213504115"></a><a name="p175213504115"></a>--bc-min-version</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p384481811016"><a name="p384481811016"></a><a name="p384481811016"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p20729728003"><a name="p20729728003"></a><a name="p20729728003"></a>Outputs the lowest bytecode version supported.</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p4328533205"><a name="p4328533205"></a><a name="p4328533205"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p175385118014"><a name="p175385118014"></a><a name="p175385118014"></a>-</p>
</td>
</tr>
</tbody>
</table>
## Repositories Involved<a name="section1371113476307"></a>
[ARK Runtime Subsystem](https://gitee.com/wanyanglan/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem.md)
[ark/runtime\_core](https://gitee.com/openharmony/ark_runtime_core/blob/master/README.md)
[ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README.md)
**[ark/ts2abc](README.md)**
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+193
View File
@@ -0,0 +1,193 @@
# ts2abc组件<a name="ZH-CN_TOPIC_0000001137330686"></a>
- [简介](#section11660541593)
- [目录](#section161941989596)
- [说明](#section0446154755015)
- [使用说明](#section33105542504)
- [相关仓](#section1371113476307)
## 简介<a name="section11660541593"></a>
ts2abc组件是方舟平台的一个组件,其作为方舟编译器中JavaScript语言的前端工具,支持将JavaScript文件转换为方舟字节码文件。
## 目录<a name="section161941989596"></a>
```
/ark/ts2abc/
├── ts2panda
├── doc # 文档
├── scripts # 依赖的脚本
├── src # 源码存放目录
├── templates # ruby模板文件
├── tests # UT单元测试目录
├── tools # ts2abc提供的工具
└── ts2abc # abc文件生成相关
```
## 说明<a name="section0446154755015"></a>
ts2abc组件采用命令行交互方式,支持将JavaScript代码转换为方舟字节码文件,使其能够在方舟运行时上运行。支持Windows/Linux/MacOS平台。
### 使用说明<a name="section33105542504"></a>
ts2abc组件将JavaScript文件转换为方舟字节码文件,命令行格式为: node --expose-gc your\_path\_to/index.js \[options\] your\_file.js。当不输入任何option参数时,默认生成方舟二进制文件。其中index.js是ts2abc组件编译后的可执行文件。
<a name="table2035444615598"></a>
<table><thead align="left"><tr id="row535415467591"><th class="cellrowborder" valign="top" width="12.898710128987101%" id="mcps1.1.6.1.1"><p id="p13354134619595"><a name="p13354134619595"></a><a name="p13354134619595"></a>选项</p>
</th>
<th class="cellrowborder" valign="top" width="6.869313068693131%" id="mcps1.1.6.1.2"><p id="p1584312189018"><a name="p1584312189018"></a><a name="p1584312189018"></a>缩写</p>
</th>
<th class="cellrowborder" valign="top" width="19.33806619338066%" id="mcps1.1.6.1.3"><p id="p157281281906"><a name="p157281281906"></a><a name="p157281281906"></a>描述</p>
</th>
<th class="cellrowborder" valign="top" width="25.82741725827417%" id="mcps1.1.6.1.4"><p id="p103276335016"><a name="p103276335016"></a><a name="p103276335016"></a>取值范围</p>
</th>
<th class="cellrowborder" valign="top" width="35.066493350664935%" id="mcps1.1.6.1.5"><p id="p1835494695915"><a name="p1835494695915"></a><a name="p1835494695915"></a>默认值</p>
</th>
</tr>
</thead>
<tbody><tr id="row1435412465598"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p881325510017"><a name="p881325510017"></a><a name="p881325510017"></a>--modules</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p148431189013"><a name="p148431189013"></a><a name="p148431189013"></a>-m</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p072882813015"><a name="p072882813015"></a><a name="p072882813015"></a>按照module模式编译</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p10327833305"><a name="p10327833305"></a><a name="p10327833305"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p076075115014"><a name="p076075115014"></a><a name="p076075115014"></a>-</p>
</td>
</tr>
<tr id="row3355346105920"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p163552462595"><a name="p163552462595"></a><a name="p163552462595"></a>--debug-log</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p48431918607"><a name="p48431918607"></a><a name="p48431918607"></a>-l</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p127284281905"><a name="p127284281905"></a><a name="p127284281905"></a>使能log信息</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p93278335012"><a name="p93278335012"></a><a name="p93278335012"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1976019511306"><a name="p1976019511306"></a><a name="p1976019511306"></a>-</p>
</td>
</tr>
<tr id="row9355174675912"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p6355104616592"><a name="p6355104616592"></a><a name="p6355104616592"></a>--dump-assembly</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p20843161819020"><a name="p20843161819020"></a><a name="p20843161819020"></a>-a</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p187287280015"><a name="p187287280015"></a><a name="p187287280015"></a>输出为汇编文件</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p932819331104"><a name="p932819331104"></a><a name="p932819331104"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1475975114013"><a name="p1475975114013"></a><a name="p1475975114013"></a>-</p>
</td>
</tr>
<tr id="row53551046175917"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p13575501218"><a name="p13575501218"></a><a name="p13575501218"></a>--debug</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p48431818104"><a name="p48431818104"></a><a name="p48431818104"></a>-d</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p1372811281608"><a name="p1372811281608"></a><a name="p1372811281608"></a>携带debug信息</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p133287335020"><a name="p133287335020"></a><a name="p133287335020"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p37585513019"><a name="p37585513019"></a><a name="p37585513019"></a>-</p>
</td>
</tr>
<tr id="row8355204635911"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p657125010117"><a name="p657125010117"></a><a name="p657125010117"></a>--show-statistics</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p98433181905"><a name="p98433181905"></a><a name="p98433181905"></a>-s</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p77281528704"><a name="p77281528704"></a><a name="p77281528704"></a>显示字节码相关的统计信息</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p83281633208"><a name="p83281633208"></a><a name="p83281633208"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p17580511404"><a name="p17580511404"></a><a name="p17580511404"></a>-</p>
</td>
</tr>
<tr id="row6355124665910"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p105611505114"><a name="p105611505114"></a><a name="p105611505114"></a>--output</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1884310183014"><a name="p1884310183014"></a><a name="p1884310183014"></a>-o</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p20728192819015"><a name="p20728192819015"></a><a name="p20728192819015"></a>输出文件路径</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p1332810331508"><a name="p1332810331508"></a><a name="p1332810331508"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p157577519014"><a name="p157577519014"></a><a name="p157577519014"></a>-</p>
</td>
</tr>
<tr id="row235584610599"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p95515501012"><a name="p95515501012"></a><a name="p95515501012"></a>--timeout</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1684312184012"><a name="p1684312184012"></a><a name="p1684312184012"></a>-t</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p37282028600"><a name="p37282028600"></a><a name="p37282028600"></a>超时门限</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p133281033804"><a name="p133281033804"></a><a name="p133281033804"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p675665112019"><a name="p675665112019"></a><a name="p675665112019"></a>-</p>
</td>
</tr>
<tr id="row135584635915"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p4551501217"><a name="p4551501217"></a><a name="p4551501217"></a>--opt-log-level</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p1843181819011"><a name="p1843181819011"></a><a name="p1843181819011"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p157285282020"><a name="p157285282020"></a><a name="p157285282020"></a>指定编译优化log等级</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p1532819334016"><a name="p1532819334016"></a><a name="p1532819334016"></a>['debug', 'info', 'error', 'fatal']</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p475510516018"><a name="p475510516018"></a><a name="p475510516018"></a>error</p>
</td>
</tr>
<tr id="row133555461596"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p3541550416"><a name="p3541550416"></a><a name="p3541550416"></a>--opt-level</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p148441518404"><a name="p148441518404"></a><a name="p148441518404"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p27281728502"><a name="p27281728502"></a><a name="p27281728502"></a>指定编译优化等级</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p832833312018"><a name="p832833312018"></a><a name="p832833312018"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p1975514517020"><a name="p1975514517020"></a><a name="p1975514517020"></a>1</p>
</td>
</tr>
<tr id="row23556463595"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p135313506120"><a name="p135313506120"></a><a name="p135313506120"></a>--help</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p168448187012"><a name="p168448187012"></a><a name="p168448187012"></a>-h</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p97284281607"><a name="p97284281607"></a><a name="p97284281607"></a>帮助提示</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p43281335010"><a name="p43281335010"></a><a name="p43281335010"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p57545511102"><a name="p57545511102"></a><a name="p57545511102"></a>-</p>
</td>
</tr>
<tr id="row5356124655916"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p185311501910"><a name="p185311501910"></a><a name="p185311501910"></a>--bc-version</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p6844141810019"><a name="p6844141810019"></a><a name="p6844141810019"></a>-v</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p1872818281006"><a name="p1872818281006"></a><a name="p1872818281006"></a>输出当前字节码版本</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p73281733408"><a name="p73281733408"></a><a name="p73281733408"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p77537511606"><a name="p77537511606"></a><a name="p77537511606"></a>-</p>
</td>
</tr>
<tr id="row1335654635915"><td class="cellrowborder" valign="top" width="12.898710128987101%" headers="mcps1.1.6.1.1 "><p id="p175213504115"><a name="p175213504115"></a><a name="p175213504115"></a>--bc-min-version</p>
</td>
<td class="cellrowborder" valign="top" width="6.869313068693131%" headers="mcps1.1.6.1.2 "><p id="p384481811016"><a name="p384481811016"></a><a name="p384481811016"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="19.33806619338066%" headers="mcps1.1.6.1.3 "><p id="p20729728003"><a name="p20729728003"></a><a name="p20729728003"></a>输出当前支持的最低字节码版本</p>
</td>
<td class="cellrowborder" valign="top" width="25.82741725827417%" headers="mcps1.1.6.1.4 "><p id="p4328533205"><a name="p4328533205"></a><a name="p4328533205"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="35.066493350664935%" headers="mcps1.1.6.1.5 "><p id="p175385118014"><a name="p175385118014"></a><a name="p175385118014"></a>-</p>
</td>
</tr>
</tbody>
</table>
## 相关仓<a name="section1371113476307"></a>
[方舟运行时子系统](https://gitee.com/wanyanglan/ark_js_runtime/blob/master/docs/%E6%96%B9%E8%88%9F%E8%BF%90%E8%A1%8C%E6%97%B6%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
[ark/runtime\_core](https://gitee.com/openharmony/ark_runtime_core/blob/master/README_zh.md)
[ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README_zh.md)
**[ark/ts2abc](README_zh.md)**
+16
View File
@@ -0,0 +1,16 @@
{
"subsystem": "ark",
"parts": {
"ark_ts2abc": {
"variants": [
"phone"
],
"module_list": [
"//ark/ts2abc/ts2panda:ark_ts2abc_build"
],
"inner_kits": [],
"system_kits": [],
"test_list": []
}
}
}
+177
View File
@@ -0,0 +1,177 @@
## File overview:
```
es5_tests.txt: This file contains a list of ES5 test cases. If useful cases are found missing, you can add them as needed.
es2015_tests.txt: This file contains a full list of use cases of ES2015 except those filtered out with'es6id'. If useful cases are found missing, you can add them as needed.
skip_tests.json: This file contains a list of use cases that do not meet the requirements. If useful cases are found missing, you can add them according to the specified format.
```
## 1. Compile ts2abc and ark_js_vm project
```
./build.sh --product-name Hi3516DV300 --build-target ark_js_vm --build-target ark_ts2abc_build
```
## 2 Run test cases
### 2.1 Options
```
usage: run_test262.py [-h] [--dir DIR] [--file FILE] [--mode [{1,2,3}]]
[--es51] [--es2015 [{all,only}]] [--esnext]
[--engine FILE] [--babel] [--timeout TIMEOUT]
[--threads THREADS] [--hostArgs HOSTARGS]
[--ark-tool ARK_TOOL]
[--ark-frontend-tool ARK_FRONTEND_TOOL]
[--libs-dir LIBS_DIR]
[--ark-frontend [{ts2panda,es2panda}]]
optional arguments:
-h, --help show this help message and exit
--dir DIR Directory to test
--file FILE File to test
--mode [{1,2,3}] selection information as: 1: only default 2:
only strict mode 3: both default and strict mode
--es51 Run test262 ES5.1 version
--es2015 [{all,only}]
Run test262 - ES2015. all: Contains all use cases for
ES5 and ES2015, only: Only include use cases for
ES2015
--esnext Run test262 - ES.next.
--engine FILE Other engine binarys to run tests with
(as:d8,hermes,jsc,qjs...)
--babel Whether to use Babel conversion
--timeout TIMEOUT Set a custom test timeout in milliseconds !!!
--threads THREADS Run this many tests in parallel. Note that the browser
runners don't work great with t > 1.
--hostArgs HOSTARGS command-line arguments to pass to eshost host
--ark-tool ARK_TOOL ark's binary tool
--ark-frontend-tool ARK_FRONTEND_TOOL
ark frontend conversion tool
--libs-dir LIBS_DIR The path collection of dependent so has been divided
by':'
--ark-frontend [{ts2panda,es2panda}]
Choose one of them
```
### 2.2 run all the test cases
```
python3 test262/run_test262.py
```
### 2.3 run `es51` related test cases
```python
python3 test262/run_test262.py --es51
```
After the execution finished, a directory named `test_es51` is created under directory `test262/data` , which is used to store all `es51` cases.
### 2.4 run `es2015` related test cases
#### 2.4.1 only include use cases for ES2015
```python
python3 test262/run_test262.py --es2015 only
```
#### 2.4.2 contains all use cases for ES5 and ES2015
```python
python3 test262/run_test262.py --es2015 all
```
### 2.5 run single test case
```python
python3 test262/run_test262.py --file test262/data/test_es5/language/statements/break/12.8-1.js
```
### 2.6 run all the test cases under specified directory
```python
python3 test262/run_test262.py --dir test262/data/test_es5/language/statements
```
### 2.7 run single test case with other engines. Take d8 as an example
```python
python3 test262/run_test262.py --engine="/home/share/v8-code/v8/out.gn/x64.release/d8" --file test262/data/test_es5/language/statements/break/12.8-1.js
```
### 2.8 run single test case with `babel` conversion
```
python3 test262/run_test262.py --babel --file test262/data/test_es5/language/statements/break/12.8-1.js
```
### 2.9 Get test result
take the following code as an example:
```shell
zgy@lfgphicprd23154:/home/share/OpenHarmony2.0_20210604/ark/ts2abc$ python3 -B test262/run_test262.py --file test262/data/test_es51/language/statements/break/12.8-1.js
Wait a moment..........
07-30 16:56:03.857383 D:>>> command: npm install | dir: /home/share/OpenHarmony2.0_20210604/out/ohos-arm-release/clang_x64/ark/ark/build/src/..
npm WARN ts2panda@1.0.0 No description
npm WARN ts2panda@1.0.0 No repository field.
npm WARN ts2panda@1.0.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
up to date in 2.225s
28 packages are looking for funding
run `npm fund` for details
07-30 16:56:06.746184 D:>>> command: npm install | dir: test262/eshost
up to date in 1.446s
1 package is looking for funding
run `npm fund` for details
07-30 16:56:08.767037 D:>>> command: npm install | dir: test262/harness
up to date in 2.412s
07-30 16:56:11.836409 D:>>> command: git checkout -- . | dir: test262/data
07-30 16:56:12.012115 D:>>> command: git checkout 9ca13b12728b7e0089c7eb03fa2bd17f8abe297f | dir: test262/data
HEAD is now at 9ca13b1272 Fix typo in BigIntArray property descriptor test
07-30 16:56:12.275768 D:>>> command: git checkout -- . | dir: test262/eshost
07-30 16:56:12.280134 D:>>> command: git apply ../eshost.patch | dir: test262/eshost
07-30 16:56:12.283263 D:>>> command: git checkout -- . | dir: test262/harness
07-30 16:56:12.288134 D:>>> command: git apply ../harness.patch | dir: test262/harness
Test command:
node
test262/harness/bin/run.js
--hostType=panda
--hostPath=python3
--hostArgs='-B test262/run_sunspider.py --ark-tool=/home/share/OpenHarmony2.0_20210604/out/ohos-arm-release/clang_x64/ark/ark/ark_js_vm --ark-frontend-tool=/home/share/OpenHarmony2.0_20210604/out/ohos-arm-release/clang_x64/ark/ark/build/src/index.js --libs-dir=/home/share/OpenHarmony2.0_20210604/out/ohos-arm-release/clang_x64/ark/ark:/home/share/OpenHarmony2.0_20210604/out/ohos-arm-release/clang_x64/global/i18n_standard:/home/share/OpenHarmony2.0_20210604/prebuilts/clang/ohos/linux-x86_64/llvm/lib/ --ark-frontend=ts2panda '
--threads=15
--mode=only strict mode
--timeout=60000
--tempDir=out/test262
--test262Dir=test262/data
--saveCompiledTests
test262/data/test_es51/language/statements/break/12.8-1.js
FAIL test262/data/test_es51/language/statements/break/12.8-1.js (strict mode)
Ran 1 tests
0 passed
1 failed
used time is: 0:00:13.303865
```
* `default` indicates `non-strict` mode, `strict mode` indicates the strict mode.
* After the execution finished, the following files are generated under directory `out/test262/` (you can specified it in `test262/config.py`):
```
-rw-rw-r-- 1 zgy zgy 7583 Nov 21 18:18 12.8-1-default.abc
-rw-rw-r-- 1 zgy zgy 415 Nov 21 18:18 12.8-1.js.panda.default.err
-rw-rw-r-- 1 zgy zgy 4389 Nov 21 18:18 12.8-1.js.panda.default.fail
-rw-rw-r-- 1 zgy zgy 415 Nov 21 18:18 12.8-1.js.panda.strict.err
-rw-rw-r-- 1 zgy zgy 4403 Nov 21 18:18 12.8-1.js.panda.strict.fail
-rw-rw-r-- 1 zgy zgy 7601 Nov 21 18:18 12.8-1-strict.abc
```
`.abc` indicates the generated binary `abc` file.
`.err` indicates error occurs during the test.
`.fail/.pass` is the file saved after `js` file has been preprocessed.
The `result.txt` file is generated under directory `out/test262` to save statistics after the test finished.
+32
View File
@@ -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.
*/
const babel = require("@babel/core");
const config = {
"presets": ["@babel/preset-env"],
};
module.exports = function(test) {
try {
test.contents = babel.transform(test.contents, config).code;
} catch (error) {
test.result = {
stderr: `${error.name}: ${error.message}\n`,
stdout: '',
error
};
}
return test;
};
+102
View File
@@ -0,0 +1,102 @@
# coding: utf-8
#!/usr/bin/python3
"""
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.
Description: Execute 262 test suite configuration file
"""
import os
DATA_DIR = os.path.join("test262", "data")
ESHOST_DIR = os.path.join("test262", "eshost")
HARNESS_DIR = os.path.join("test262", "harness")
BASE_OUT_DIR = os.path.join("out", "test262")
CUR_FILE_DIR = os.path.dirname(__file__)
CODE_ROOT = os.path.abspath(os.path.join(CUR_FILE_DIR, "../../.."))
ARK_DIR = f"{CODE_ROOT}/out/ohos-arm-release/clang_x64/ark/ark"
ICUI_DIR = f"{CODE_ROOT}/out/ohos-arm-release/clang_x64/global/i18n_standard"
LLVM_DIR = f"{CODE_ROOT}/prebuilts/clang/ohos/linux-x86_64/llvm/lib/"
# " mode_type": {
# "1": "only default",
# "2": "only strict mode",
# "3": "both default and strict mode"
# }
DEFAULT_MODE = 2
TEST_ES5_DIR = os.path.join(DATA_DIR, "test_es51")
TEST_ES2015_DIR = os.path.join(DATA_DIR, "test_es2015")
DEFAULT_ARK_FRONTEND_TOOL = os.path.join(ARK_DIR, "build", "src", "index.js")
DEFAULT_ARK_TOOL = os.path.join(ARK_DIR, "..", "ark_js_runtime", "ark_js_vm")
DEFAULT_LIBS_DIR = f"{ARK_DIR}:{ICUI_DIR}:{LLVM_DIR}"
DEFAULT_HOST_TYPE = "panda"
DEFAULT_HOST_PATH = "python3"
DEFAULT_THREADS = 8
DEFAULT_OTHER_ARGS = "--saveCompiledTests"
TEST262_RUNNER_SCRIPT = os.path.join(HARNESS_DIR, "bin", "run.js")
DEFAULT_TIMEOUT = 60000
ES5_LIST_FILE = os.path.join("test262", "es5_tests.txt")
ES2015_LIST_FILE = os.path.join("test262", "es2015_tests.txt")
TEST262_GIT_HASH = "9ca13b12728b7e0089c7eb03fa2bd17f8abe297f"
HARNESS_GIT_HASH = "9c499f028eb24e67781435c0bb442e00343eb39d"
ESHOST_GIT_HASH = "fa2d4d27d9d6152002bdef36ee2d17e98b886268"
ESNEXT_GIT_HASH = "281eb10b2844929a7c0ac04527f5b42ce56509fd"
TEST262_GIT_URL = "https://gitee.com/Han00000000/test262.git"
ESHOST_GIT_URL = "https://gitee.com/Han00000000/eshost.git"
HARNESS_GIT_URL = "https://gitee.com/Han00000000/test262-harness.git"
SKIP_LIST_FILE = os.path.join("test262", "skip_tests.json")
ALL_SKIP_TESTS = []
ARK_FRONTEND_LIST = [
"ts2panda",
"es2panda"
]
DEFAULT_ARK_FRONTEND = ARK_FRONTEND_LIST[0]
MODULE_FILES_LIST = [
"early-dup-export-decl.js",
"early-dup-export-dflt-id.js",
"early-dup-export-dflt.js",
"early-dup-export-id-as.js",
"early-dup-export-id.js",
"early-dup-lables.js",
"early-dup-lex.js",
"early-export-global.js",
"early-lex-and-var.js",
"early-new-target.js",
"early-strict-mode.js",
"early-super.js",
"early-undef-break.js",
"early-undef-continue.js",
"parse-err-export-dflt-const.js",
"parse-err-export-dflt-let.js",
"parse-err-export-dflt-var.js",
"parse-err-return.js",
"parse-err-yield.js",
"dup-bound-names.js",
"await-module.js"
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+233
View File
@@ -0,0 +1,233 @@
From ed6584a8304882dc14a25cbd1f27f70961658147 Mon Sep 17 00:00:00 2001
Date: Thu, 15 Jul 2021 09:34:47 +0800
Subject: [PATCH] fix test
---
lib/Agent.js | 1 +
lib/ConsoleAgent.js | 29 ++++++++++-----
lib/agents/panda.js | 88 +++++++++++++++++++++++++++++++++++++++++++++
runtimes/panda.js | 44 +++++++++++++++++++++++
4 files changed, 154 insertions(+), 8 deletions(-)
create mode 100644 lib/agents/panda.js
create mode 100644 runtimes/panda.js
diff --git a/lib/Agent.js b/lib/Agent.js
index edcdf0e..7e655c5 100644
--- a/lib/Agent.js
+++ b/lib/Agent.js
@@ -7,6 +7,7 @@ class Agent {
this.args = options.hostArguments || [];
this.transform = options.transform || (x => x);
this.out = options.out || '';
+ this.test262Dir = options.test262Dir;
if (typeof this.args === 'string') {
this.args = this.args.includes(' ') ?
diff --git a/lib/ConsoleAgent.js b/lib/ConsoleAgent.js
index 947c1db..dc14ded 100644
--- a/lib/ConsoleAgent.js
+++ b/lib/ConsoleAgent.js
@@ -19,7 +19,7 @@ const {
const cpSym = Symbol.for('cp');
const tpSym = Symbol.for('tp');
-function generateTempFileName() {
+function generateTempFileName(file) {
const now = Date.now();
return `f-${now}-${process.pid}-${(Math.random() * 0x100000000 + 1).toString(36)}.js`;
}
@@ -47,9 +47,23 @@ class ConsoleAgent extends Agent {
}
}
+ genTempFileName(code){
+ let file = code.file;
+ let scenario = code.scenario === 'strict mode' ? 'strict' : code.scenario;
+ let tmps = file.split(this.test262Dir);
+ let tempfile = path.join(this.out,tmps[1]);
+ tempfile = tempfile.substring(0,tempfile.indexOf('.js'));
+ tempfile = path.normalize(
+ `${tempfile}-${scenario}.js`
+ );
+ return tempfile;
+ }
+
evalScript(code, options = {}) {
- let tempfile = path.join(this[tpSym], generateTempFileName());
- let temppath = this[tpSym];
+
+ let tempfile = this.genTempFileName(code);
+ //let tempfile = path.join(this.out, generateTempFileName(code.file));
+ let temppath = this.out;
let isExpectingRawSource = false;
let hasDependencies = false;
@@ -57,10 +71,10 @@ class ConsoleAgent extends Agent {
const sources = [];
const dependencies = [];
- if (this.out) {
- tempfile = tempfile.replace(temppath, this.out);
- temppath = this.out;
- }
+ // if (this.out) {
+ // tempfile = tempfile.replace(temppath, this.out);
+ // temppath = this.out;
+ // }
// When evalScript is called with a test262-stream test record:
if (typeof code === 'object' && code.contents) {
@@ -161,7 +175,6 @@ class ConsoleAgent extends Agent {
sources.forEach(({0: file}) => fs.unlink(file, () => { /* ignore */ }));
const result = this.normalizeResult({ stderr, stdout });
-
result.error = this.parseError(result.stderr);
return result;
diff --git a/lib/agents/panda.js b/lib/agents/panda.js
new file mode 100644
index 0000000..ab22b47
--- /dev/null
+++ b/lib/agents/panda.js
@@ -0,0 +1,88 @@
+'use strict';
+
+const fs = require('fs');
+const runtimePath = require('../runtime-path');
+const ConsoleAgent = require('../ConsoleAgent');
+
+const errorRe = /[(](\d+),(\d+)[)]: (.*)/;
+const errorRe1 = /^(\w+): (.*)$/m;
+// const errorRe2 = /^(?:(\w+): (.*))|(?:(\w+))$/m;
+const errorRe2 = /(\w+): (\w+): (.*)$/m;
+
+function parseSyntaxError(syntaxErrorMessage) {
+ const matches = syntaxErrorMessage.match();
+ if (matches && matches.length) {
+ return {
+ message: matches[3],
+ lineNumber: Number(matches[1]),
+ columnNumber: Number(matches[2])
+ };
+ }
+ return null;
+}
+
+class PandaAgent extends ConsoleAgent{
+ constructor(options) {
+ super(options);
+ }
+
+ createChildProcess(args) {
+ let js_file = args[0]
+ args = []
+ args.unshift(`--js-file=${js_file}`)
+ return super.createChildProcess(args);
+ }
+
+ evalScript(code, options = {}) {
+ return super.evalScript(code, options);
+ }
+
+ parseError(str) {
+ let match = str.match(errorRe1);
+ if (match) {
+ return {
+ name: match[1],
+ message: match[2],
+ stack: [],
+ };
+ } else {
+ // Syntax errors don't have nice error messages...
+ let error = null;
+ let errors = str.match(/[(](\d+),(\d+)[)]: (.*)/gm);
+
+ if (errors && errors.length) {
+ error = {
+ name: 'SyntaxError',
+ message: errors[0],
+ stack: []
+ };
+
+ const stack = parseSyntaxError(errors[0]);
+
+ if (stack) {
+ error.stack.push(stack);
+ error.message = stack.message;
+ }
+ }
+
+ if (error) {
+ return error;
+ }
+
+ // Last chance...
+ errors = str.match(errorRe2);
+ if (errors && errors.length >3) {
+ return {
+ name: errors[2],
+ message: errors[0],
+ stack: [],
+ };
+ }
+ }
+
+ return null;
+ }
+}
+
+PandaAgent.runtime = fs.readFileSync(runtimePath.for('panda'), 'utf8');
+module.exports = PandaAgent;
\ No newline at end of file
diff --git a/runtimes/panda.js b/runtimes/panda.js
new file mode 100644
index 0000000..0acbd09
--- /dev/null
+++ b/runtimes/panda.js
@@ -0,0 +1,44 @@
+if (!globalThis.$262) {
+ globalThis.$262 = {
+ global: globalThis,
+ evalScript(code) {
+ try {
+ global.evalScript(code);
+ return { type: 'normal', value: undefined };
+ } catch (e) {
+ return { type: 'throw', value: e };
+ }
+ },
+ gc() {
+ throw new Test262Error('gc() not yet supported.');
+ },
+ getGlobal(name) {
+ return global[name];
+ },
+ setGlobal(name, value) {
+ global[name] = value;
+ },
+ agent: (function() {
+ function thrower() {
+ throw new Test262Error('agent.* not yet supported.');
+ };
+ return {
+ start: thrower,
+ broadcast: thrower,
+ getReport: thrower,
+ sleep: thrower,
+ monotonicNow: thrower,
+ };
+ })(),
+ };
+}
+
+$262.IsHTMLDDA = function() {};
+$262.destroy = function() {};
+$262.getGlobal = function(name) {
+ return this.global[name];
+};
+$262.setGlobal = function(name, value) {
+ this.global[name] = value;
+};
+$262.source = $SOURCE;
--
+242
View File
@@ -0,0 +1,242 @@
diff --git a/bin/run.js b/bin/run.js
index 650f19a..b2a554b 100755
--- a/bin/run.js
+++ b/bin/run.js
@@ -76,6 +76,7 @@ if (argv.prelude) {
let hostType;
let hostPath;
let features;
+let mode;
if (argv.hostType) {
hostType = argv.hostType;
@@ -123,6 +124,12 @@ if (argv.features) {
features = argv.features.split(',').map(feature => feature.trim());
}
+mode = "only strict mode"
+
+if (argv.mode) {
+ mode = argv.mode
+}
+
// Show help if no arguments provided
if (!argv._.length) {
cli.showHelp();
@@ -130,15 +137,18 @@ if (!argv._.length) {
return;
}
-// Test Pipeline
-const pool = new AgentPool(
- Number(argv.threads), hostType, argv.hostArgs, hostPath, { tempDir, timeout, transform }
-);
if (!test262Dir) {
test262Dir = test262Finder(argv._[0]);
}
+
reporterOpts.test262Dir = test262Dir;
+reporterOpts.tempDir = tempDir
+
+// Test Pipeline
+const pool = new AgentPool(
+ Number(argv.threads), hostType, argv.hostArgs, hostPath, { tempDir, timeout, transform, test262Dir }
+);
const remove = path.relative(process.cwd(), test262Dir);
argv._ = argv._.map(p => path.relative(remove, p));
@@ -166,6 +176,7 @@ if (preprocessor) {
tests = tests.pipe(filter(preprocessor));
}
+tests = tests.pipe(filter(operMode));
const results = zip(pool, tests).pipe(
flatMap(pair => {
return pool.runTest(pair);
@@ -209,3 +220,11 @@ function hasFeatures(test) {
}
return features.filter(feature => (test.attrs.features || []).includes(feature)).length > 0;
}
+
+function operMode(test) {
+ test_scenario = test.scenario
+ if (mode.indexOf(test_scenario) != -1) {
+ return true;
+ }
+ return false;
+}
diff --git a/lib/agent-pool.js b/lib/agent-pool.js
index ad14b84..1b8a184 100644
--- a/lib/agent-pool.js
+++ b/lib/agent-pool.js
@@ -1,6 +1,6 @@
'use strict';
const {Subject} = require('rxjs');
-const eshost = require('eshost');
+const eshost = require('../../eshost/lib/eshost');
const internal = new WeakMap();
@@ -18,6 +18,7 @@ class AgentPool extends Subject {
shortName: '$262',
transform: options.transform,
out: options.tempDir,
+ test262Dir: options.test262Dir,
})
.then(agent => {
this.agents.push(agent);
diff --git a/lib/cli.js b/lib/cli.js
index 4a74309..91d1735 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -1,4 +1,4 @@
-const { supportedHosts } = require("eshost");
+const { supportedHosts } = require("./../../eshost/lib/eshost");
const yargs = require('yargs');
const yargv = yargs
.strict()
@@ -22,6 +22,9 @@ const yargv = yargs
.nargs('threads', 1)
.default('threads', 1)
.alias('threads', 't')
+ .nargs('mode', 1)
+ .default('mode', 1)
+ .alias('mode', 'm')
.describe('reporter', 'format of data written to standard output')
.choices('reporter', ['simple', 'json'])
.nargs('reporter', 1)
diff --git a/lib/reporters/simple.js b/lib/reporters/simple.js
index 08f9a55..a386924 100644
--- a/lib/reporters/simple.js
+++ b/lib/reporters/simple.js
@@ -1,5 +1,6 @@
'use strict';
const path = require('path');
+const fs = require('fs');
const saveCompiledTest = require('../saveCompiledTest');
function simpleReporter(results, opts) {
@@ -12,11 +13,13 @@ function simpleReporter(results, opts) {
clearPassed();
lastPassed = true;
- process.stdout.write(`PASS ${test.file}`);
+ let mess = `PASS ${test.file} (${test.scenario})\n`
+ console.log(mess);
+ writeStatistics(mess,opts);
if (opts.saveCompiledTests && !opts.saveOnlyFailed) {
test.savedTestPath = saveCompiledTest(test, opts);
- process.stdout.write(`\nSaved compiled passed test as ${test.savedTestPath}\n`);
+ // process.stdout.write(`\nSaved compiled passed test as ${test.savedTestPath}\n`);
}
});
@@ -24,14 +27,21 @@ function simpleReporter(results, opts) {
failed++;
clearPassed();
lastPassed = false;
- console.log(`FAIL ${test.file} (${test.scenario})`);
- console.log(` ${test.result.message}`);
+
+ let mess = `FAIL ${test.file} (${test.scenario})\n`
+ saveInfoToFile(test,opts);
+
+ console.log(mess);
+ console.log(`${test.result.message}`);
console.log('');
+ writeStatistics(mess,opts);
+
if (opts.saveCompiledTests) {
test.savedTestPath = saveCompiledTest(test, opts);
- process.stdout.write(`Saved compiled failed test as ${test.savedTestPath}\n`);
+ // process.stdout.write(`Saved compiled failed test as ${test.savedTestPath}\n`);
}
+
});
results.on('end', function () {
@@ -52,6 +62,29 @@ function simpleReporter(results, opts) {
}
}
}
+
+ function saveInfoToFile(test,opts){
+ let filePath = test.file;
+ let tmps = filePath.split(opts.test262Dir);
+ let outFile = path.join(opts.tempDir,tmps[1]);
+ let scenario = test.scenario === 'strict mode' ? 'strict' : test.scenario;
+ let outcome = 'err';
+ let savedTestPath = path.normalize(
+ `${outFile}.${opts.hostType}.${scenario}.${outcome}`
+ );
+ fs.writeFileSync(savedTestPath, ` ${test.result.message}`);
+ }
+
+ function writeStatistics(data,opts) {
+ let save_file = path.join(opts.tempDir,"result.txt");
+ fs.appendFile(save_file,data,'utf8',function(err){
+ if(err)
+ {
+ console.error(err);
+ }
+ });
+ }
+
}
module.exports = simpleReporter;
diff --git a/lib/saveCompiledTest.js b/lib/saveCompiledTest.js
index c233adb..7739946 100644
--- a/lib/saveCompiledTest.js
+++ b/lib/saveCompiledTest.js
@@ -6,8 +6,11 @@ const path = require('path');
module.exports = function saveCompiledTest(test, options) {
let outcome = test.result.pass ? 'pass' : 'fail';
let scenario = test.scenario === 'strict mode' ? 'strict' : test.scenario;
+ let filePath = test.file;
+ let tmps = filePath.split(options.test262Dir);
+ let outFile = path.join(options.tempDir,tmps[1]);
let savedTestPath = path.normalize(
- `${test.file}.${options.hostType}.${scenario}.${outcome}`
+ `${outFile}.${options.hostType}.${scenario}.${outcome}`
);
fs.writeFileSync(savedTestPath, test.compiled);
return savedTestPath;
diff --git a/lib/validator.js b/lib/validator.js
index e7cb695..38a113c 100644
--- a/lib/validator.js
+++ b/lib/validator.js
@@ -35,7 +35,7 @@ module.exports = function validate(test) {
} else {
return {
pass: false,
- message: `Expected no error, got ${result.error.name}: ${result.error.message}`,
+ message: `Expected no error, but got ${result.error.name}: \n ${result.stderr}`,
};
}
} else if (!ranToFinish && !test.attrs.flags.raw) {
@@ -46,7 +46,7 @@ module.exports = function validate(test) {
}
return {
pass: false,
- message,
+ message: `Expected no error, but got : \n ${result.stderr}`,
};
} else {
return {
@@ -78,9 +78,9 @@ module.exports = function validate(test) {
} else {
return {
pass: false,
- message: `Expected test to throw error of type ${test.attrs.negative.type}, got ${result.error.name}: ${result.error.message}`,
+ message: `Expected test to throw error of type ${test.attrs.negative.type}, but got ${result.error.name}: \n ${result.stderr}`,
};
}
}
}
-};
+};
\ No newline at end of file
+189
View File
@@ -0,0 +1,189 @@
# coding: utf-8
#!/usr/bin/python3
"""
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.
Description: Use ark to execute js files
"""
import argparse
import os
import platform
import sys
import signal
import subprocess
from utils import *
from config import *
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--ark-tool',
help="ark's binary tool")
parser.add_argument('--ark-frontend-tool',
help="ark frontend conversion tool")
parser.add_argument("--libs-dir",
help="The path collection of dependent so has been divided by':'")
parser.add_argument("--js-file",
help="js file")
parser.add_argument('--ark-frontend',
nargs='?', choices=ARK_FRONTEND_LIST, type=str,
help="Choose one of them")
arguments = parser.parse_args()
return arguments
ARK_ARGS = "--gc-type=epsilon"
ARK_TOOL = DEFAULT_ARK_TOOL
ARK_FRONTEND_TOOL = DEFAULT_ARK_FRONTEND_TOOL
LIBS_DIR = DEFAULT_LIBS_DIR
ARK_FRONTEND = DEFAULT_ARK_FRONTEND
def output(retcode, msg):
if retcode == 0:
if msg != '':
print(str(msg))
elif retcode == -6:
sys.stderr.write("Aborted (core dumped)")
elif retcode == -11:
sys.stderr.write("Segmentation fault (core dumped)")
elif msg != '':
sys.stderr.write(str(msg))
else:
sys.stderr.write("Unknown Error: " + str(retcode))
def exec_command(cmd_args, timeout=DEFAULT_TIMEOUT):
proc = subprocess.Popen(cmd_args,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
close_fds=True,
start_new_session=True)
cmd_string = " ".join(cmd_args)
code_format = 'utf-8'
if platform.system() == "Windows":
code_format = 'gbk'
try:
(msg, errs) = proc.communicate(timeout=timeout)
ret_code = proc.poll()
if errs.decode(code_format, 'ignore') != '':
output(1, errs.decode(code_format, 'ignore'))
return 1
if ret_code and ret_code != 1:
code = ret_code
msg = f"Command {cmd_string}: \n"
msg += f"error: {str(errs.decode(code_format,'ignore'))}"
else:
code = 0
msg = str(msg.decode(code_format, 'ignore'))
except subprocess.TimeoutExpired:
proc.kill()
proc.terminate()
os.kill(proc.pid, signal.SIGTERM)
code = 1
msg = f"Timeout:'{cmd_string}' timed out after' {str(timeout)} seconds"
except Exception as err:
code = 1
msg = f"{cmd_string}: unknown error: {str(err)}"
output(code, msg)
return code
class ArkProgram():
def __init__(self, args):
self.args = args
self.ark_tool = ARK_TOOL
self.ark_frontend_tool = ARK_FRONTEND_TOOL
self.libs_dir = LIBS_DIR
self.ark_frontend = ARK_FRONTEND
self.js_file = ""
def proce_parameters(self):
if self.args.ark_tool:
self.ark_tool = self.args.ark_tool
if self.args.ark_frontend_tool:
self.ark_frontend_tool = self.args.ark_frontend_tool
if self.args.libs_dir:
self.libs_dir = self.args.libs_dir
if self.args.ark_frontend:
self.ark_frontend = self.args.ark_frontend
self.js_file = self.args.js_file
def gen_abc(self):
js_file = self.js_file
file_name_pre = os.path.splitext(js_file)[0]
file_name = os.path.basename(js_file)
out_file = f"{file_name_pre}.abc"
mod_opt_index = 0
cmd_args = []
frontend_tool = self.ark_frontend_tool
if self.ark_frontend == ARK_FRONTEND_LIST[0]:
mod_opt_index = 3
cmd_args = ['node', '--expose-gc', frontend_tool,
js_file, '-o', out_file]
elif self.ark_frontend == ARK_FRONTEND_LIST[1]:
mod_opt_index = 1
cmd_args = [frontend_tool, '-c',
'-e', 'js', '-o', out_file, '-i', js_file]
if file_name in MODULE_FILES_LIST:
cmd_args.insert(mod_opt_index, "-m")
retcode = exec_command(cmd_args)
return retcode
def execute(self):
os.environ["LD_LIBRARY_PATH"] = self.libs_dir
file_name_pre = os.path.splitext(self.js_file)[0]
cmd_args = [self.ark_tool, ARK_ARGS,
f'{file_name_pre}.abc']
retcode = exec_command(cmd_args)
return retcode
def is_legal_frontend(self):
if self.ark_frontend not in ARK_FRONTEND_LIST:
sys.stderr.write("Wrong ark front-end option")
return False
return True
def execute_ark(self):
self.proce_parameters()
if not self.is_legal_frontend():
return
if self.gen_abc():
return
self.execute()
def main():
args = parse_args()
ark = ArkProgram(args)
ark.execute_ark()
if __name__ == "__main__":
sys.exit(main())
+446
View File
@@ -0,0 +1,446 @@
# coding: utf-8
#!/usr/bin/python3
"""
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.
Description: Use ark to execute test 262 test suite
"""
import argparse
import datetime
import collections
import json
import os
import sys
import subprocess
from multiprocessing import Pool
from utils import *
from config import *
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--dir', metavar='DIR',
help='Directory to test ')
parser.add_argument('--file', metavar='FILE',
help='File to test')
parser.add_argument('--mode',
nargs='?', choices=[1, 2, 3], type=int,
help='selection information as: ' +
'1: only default \n ' +
'2: only strict mode \n' +
'3: both default and strict mode\n')
parser.add_argument('--es51', action='store_true',
help='Run test262 ES5.1 version')
parser.add_argument('--es2015', default=False, const='all',
nargs='?', choices=['all', 'only'],
help='Run test262 - ES2015. ' +
'all: Contains all use cases for ES5 and ES2015' +
'only: Only include use cases for ES2015')
parser.add_argument('--esnext', action='store_true',
help='Run test262 - ES.next.')
parser.add_argument('--engine', metavar='FILE',
help='Other engine binarys to run tests(as:d8,qjs...)')
parser.add_argument('--babel', action='store_true',
help='Whether to use Babel conversion')
parser.add_argument('--timeout', default=DEFAULT_TIMEOUT, type=int,
help='Set a custom test timeout in milliseconds !!!\n')
parser.add_argument('--threads', default=DEFAULT_THREADS, type=int,
help="Run this many tests in parallel.")
parser.add_argument('--hostArgs',
help="command-line arguments to pass to eshost host\n")
parser.add_argument('--ark-tool',
help="ark's binary tool")
parser.add_argument('--ark-frontend-tool',
help="ark frontend conversion tool")
parser.add_argument("--libs-dir",
help="The path collection of dependent so has been divided by':'")
parser.add_argument('--ark-frontend',
nargs='?', choices=ARK_FRONTEND_LIST, type=str,
help="Choose one of them")
args = parser.parse_args()
return args
def run_check(runnable, env=None):
report_command('Test command:', runnable, env=env)
if env is not None:
full_env = dict(os.environ)
full_env.update(env)
env = full_env
proc = subprocess.Popen(runnable, env=env)
proc.wait()
return proc.returncode
def excuting_npm_install(args):
ark_frontend = DEFAULT_ARK_FRONTEND
if args.ark_frontend:
ark_frontend = args.ark_frontend
if ark_frontend != DEFAULT_ARK_FRONTEND:
return
ark_frontend_tool = os.path.join(DEFAULT_ARK_FRONTEND_TOOL)
if args.ark_frontend_tool:
ark_frontend_tool = os.path.join(args.ark_frontend_tool)
ts2abc_build_dir = os.path.join(os.path.dirname(
os.path.realpath(ark_frontend_tool)), "..")
if os.path.exists(os.path.join(ts2abc_build_dir, "package.json")):
npm_install(ts2abc_build_dir)
elif os.path.exists(os.path.join(ts2abc_build_dir, "..", "package.json")):
npm_install(os.path.join(ts2abc_build_dir, ".."))
def init(args):
remove_dir(BASE_OUT_DIR)
remove_dir(TEST_ES5_DIR)
remove_dir(TEST_ES2015_DIR)
get_all_skip_tests(SKIP_LIST_FILE)
excuting_npm_install(args)
def get_all_skip_tests(file):
with open(file) as jsonfile:
json_data = json.load(jsonfile)
for key in json_data:
ALL_SKIP_TESTS.extend(key["files"])
def collect_files(path):
if os.path.isfile(path):
yield path
return
if not os.path.isdir(path):
raise ValueError(f'Not found: "{path}"')
for root, _, file_names in os.walk(path):
for file_name in file_names:
if file_name.startswith('.') or not file_name.endswith(".js"):
continue
yield os.path.join(root, file_name)
def mkdstdir(file, src_dir, dist_dir):
idx = file.rfind(src_dir)
if idx == -1:
raise SystemExit(f'{file} can not found in {src_dir}')
fpath, fname = os.path.split(file[idx:])
fpath = fpath.replace(src_dir, dist_dir)
mkdir(fpath)
class TestPrepare():
def __init__(self, args):
self.args = args
self.out_dir = BASE_OUT_DIR
def prepare_test262_code(self):
if not os.path.isdir(os.path.join(DATA_DIR, '.git')):
git_clone(TEST262_GIT_URL, DATA_DIR)
git_checkout(TEST262_GIT_HASH, DATA_DIR)
if not os.path.isdir(os.path.join(ESHOST_DIR, '.git')):
git_clone(ESHOST_GIT_URL, ESHOST_DIR)
git_checkout(ESHOST_GIT_HASH, ESHOST_DIR)
git_apply('../eshost.patch', ESHOST_DIR)
npm_install(ESHOST_DIR)
if not os.path.isdir(os.path.join(HARNESS_DIR, '.git')):
git_clone(HARNESS_GIT_URL, HARNESS_DIR)
git_checkout(HARNESS_GIT_HASH, HARNESS_DIR)
git_apply('../harness.patch', HARNESS_DIR)
npm_install(HARNESS_DIR)
def prepare_clean_data(self):
git_clean(DATA_DIR)
git_checkout(TEST262_GIT_HASH, DATA_DIR)
def patching_the_plugin(self):
remove_file(os.path.join(ESHOST_DIR, "lib/agents/panda.js"))
remove_file(os.path.join(ESHOST_DIR, "runtimes/panda.js"))
git_clean(ESHOST_DIR)
git_apply("../eshost.patch", ESHOST_DIR)
git_clean(HARNESS_DIR)
git_apply("../harness.patch", HARNESS_DIR)
def prepare_args_es51_es2015(self):
if self.args.dir:
if TEST_ES5_DIR in self.args.dir:
self.args.es51 = True
elif TEST_ES2015_DIR in self.args.dir:
self.args.es2015 = "all"
if self.args.file:
if TEST_ES5_DIR in self.args.file:
self.args.es51 = True
elif TEST_ES2015_DIR in self.args.file:
self.args.es2015 = "all"
def prepare_out_dir(self):
if self.args.es51:
self.out_dir = os.path.join(BASE_OUT_DIR, "test_es51")
elif self.args.es2015:
self.out_dir = os.path.join(BASE_OUT_DIR, "test_es2015")
else:
self.out_dir = os.path.join(BASE_OUT_DIR, "test")
def prepare_args_testdir(self):
if self.args.dir:
return
if self.args.es51:
self.args.dir = TEST_ES5_DIR
elif self.args.es2015:
self.args.dir = TEST_ES2015_DIR
else:
self.args.dir = os.path.join(DATA_DIR, "test")
def copyfile(self, file):
dstdir = os.path.join(DATA_DIR, "test")
file = file.strip()
if file in ALL_SKIP_TESTS:
return
srcdir = os.path.join(DATA_DIR, "test", file)
if self.args.es51:
dstdir = os.path.join(TEST_ES5_DIR, file)
elif self.args.es2015:
dstdir = os.path.join(TEST_ES2015_DIR, file)
subprocess.getstatusoutput("cp %s %s" % (srcdir, dstdir))
def collect_tests(self):
files = []
origin_dir = os.path.join(DATA_DIR, "test/")
file_names = collect_files(origin_dir)
esid = ""
if self.args.es51:
esid = "es5id"
elif self.args.es2015:
esid = "es6id"
for file_name in file_names:
with open(file_name, 'r') as file:
content = file.read()
if esid in content:
files.append(file_name.split(origin_dir)[1])
return files
def get_tests_from_file(self, file):
fopen = open(file)
files = fopen.readlines()
fopen.close()
return files
def prepare_es2015_tests(self):
files = []
files = self.collect_tests()
files.extend(self.get_tests_from_file(ES2015_LIST_FILE))
if self.args.es2015 == "all":
files.extend(self.get_tests_from_file(ES5_LIST_FILE))
return files
def prepare_test_suit(self):
files = []
test_dir = ""
if self.args.es51:
test_dir = TEST_ES5_DIR
files = self.get_tests_from_file(ES5_LIST_FILE)
elif self.args.es2015:
test_dir = TEST_ES2015_DIR
files = self.prepare_es2015_tests()
for file in files:
path = os.path.split(file)[0]
path = os.path.join(test_dir, path)
mkdir(path)
pool = Pool(DEFAULT_THREADS)
pool.map(self.copyfile, files)
pool.close()
pool.join()
def prepare_test262_test(self):
src_dir = os.path.join(DATA_DIR, "test")
if self.args.es51:
self.prepare_test_suit()
src_dir = TEST_ES5_DIR
elif self.args.es2015:
self.prepare_test_suit()
src_dir = TEST_ES2015_DIR
elif self.args.esnext:
git_checkout(ESNEXT_GIT_HASH, DATA_DIR)
else:
git_checkout(TEST262_GIT_HASH, DATA_DIR)
if self.args.file:
mkdstdir(self.args.file, src_dir, self.out_dir)
return
files = collect_files(self.args.dir)
for file in files:
mkdstdir(file, src_dir, self.out_dir)
def run(self):
self.prepare_test262_code()
self.prepare_clean_data()
self.patching_the_plugin()
self.prepare_args_es51_es2015()
self.prepare_out_dir()
self.prepare_args_testdir()
self.prepare_test262_test()
def run_test262_prepare(args):
init(args)
test_prepare = TestPrepare(args)
test_prepare.run()
def modetype_to_string(mode):
if mode == 1:
return "only default"
if mode == 2:
return "only strict mode"
return "both default and strict mode"
def run_test262_mode(args):
if args.mode:
return modetype_to_string(args.mode)
return modetype_to_string(DEFAULT_MODE)
def get_execute_arg(args):
execute_args = ""
if args.file:
execute_args = args.file
else:
execute_args = os.path.join(args.dir, "**", "*.js")
return execute_args
def get_host_path_type(args):
host_path = DEFAULT_HOST_PATH
host_type = DEFAULT_HOST_TYPE
if args.engine:
host_path = args.engine
host_type = os.path.split(args.engine.strip())[1]
return host_path, host_type
def get_timeout(args, threads):
timeout = DEFAULT_TIMEOUT * threads
if args.timeout:
timeout = args.timeout
return timeout
def get_threads(args):
threads = DEFAULT_THREADS
if args.threads:
threads = args.threads
return threads
def get_host_args(args, host_type):
host_args = ""
ark_tool = DEFAULT_ARK_TOOL
ark_frontend_tool = DEFAULT_ARK_FRONTEND_TOOL
libs_dir = DEFAULT_LIBS_DIR
ark_frontend = DEFAULT_ARK_FRONTEND
if args.hostArgs:
host_args = args.hostArgs
if args.ark_tool:
ark_tool = args.ark_tool
if args.ark_frontend_tool:
ark_frontend_tool = args.ark_frontend_tool
if args.libs_dir:
libs_dir = args.libs_dir
if args.ark_frontend:
ark_frontend = args.ark_frontend
if host_type == DEFAULT_HOST_TYPE:
host_args = f"-B test262/run_sunspider.py "
host_args += f"--ark-tool={ark_tool} "
host_args += f"--ark-frontend-tool={ark_frontend_tool} "
host_args += f"--libs-dir={libs_dir} "
host_args += f"--ark-frontend={ark_frontend} "
return host_args
def run_test262_test(args):
execute_args = get_execute_arg(args)
host_path, host_type = get_host_path_type(args)
host_args = get_host_args(args, host_type)
threads = get_threads(args)
timeout = get_timeout(args, threads)
test_cmd = ["node", TEST262_RUNNER_SCRIPT]
test_cmd.append(f"--hostType={host_type}")
test_cmd.append(f"--hostPath={host_path}")
if host_args != "":
test_cmd.append(f"--hostArgs='{host_args}'")
test_cmd.append(f"--threads={threads}")
test_cmd.append(f"--mode={run_test262_mode(args)}")
test_cmd.append(f"--timeout={timeout}")
test_cmd.append(f"--tempDir={BASE_OUT_DIR}")
test_cmd.append(f"--test262Dir={DATA_DIR}")
if args.babel:
test_cmd.append("--preprocessor='test262/babel-preprocessor.js'")
test_cmd.append(DEFAULT_OTHER_ARGS)
test_cmd.append(execute_args)
run_check(test_cmd)
Check = collections.namedtuple('Check', ['enabled', 'runner', 'arg'])
def main(args):
print("\nWait a moment..........\n")
starttime = datetime.datetime.now()
run_test262_prepare(args)
check = Check(True, run_test262_test, args)
ret = check.runner(check.arg)
if ret:
sys.exit(ret)
endtime = datetime.datetime.now()
print(f"used time is: {str(endtime - starttime)}")
if __name__ == "__main__":
sys.exit(main(parse_args()))
File diff suppressed because it is too large Load Diff
+157
View File
@@ -0,0 +1,157 @@
# coding: utf-8
#!/usr/bin/python3
"""
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.
Description: Implement the public interface in the 262 use case
"""
import os
import sys
import subprocess
import datetime
import time
import shutil
TERM_NORMAL = '\033[0m'
TERM_YELLOW = '\033[1;33m'
TERM_BLUE = '\033[1;34m'
TERM_RED = '\033[1;31m'
TERM_FUCHSIA = '\033[1;35m'
def current_time():
dt_ms = datetime.datetime.now().strftime('%m-%d %H:%M:%S.%f')
return dt_ms
class Logging():
def __init__(self):
self.is_logging = True
def debug(self, info):
if self.is_logging:
print(
f'{current_time()} D:>>> {TERM_BLUE}{str(info)}{TERM_NORMAL}')
def info(self, info):
if self.is_logging:
if len(str(info)) > 100:
print(f'{current_time()} I:>>> \n{str(info)} ')
else:
print(f'{current_time()} I:>>> {str(info)} ')
LOGGING = Logging()
class Command():
def __init__(self, cmd):
self.cmd = cmd
def run(self):
LOGGING.debug("command: " + self.cmd)
out = os.popen(self.cmd).read()
LOGGING.info(out)
return out
def run_cmd(command):
cmd = Command(command)
return cmd.run()
class CommandCwd():
def __init__(self, cmds, cwd):
self.cmds = cmds
self.cwd = cwd
def run(self):
cmd = " ".join(self.cmds)
LOGGING.debug("command: " + cmd + " | " + "dir: " + self.cwd)
proc = subprocess.Popen(self.cmds, cwd=self.cwd)
ret = proc.wait()
return ret
def run_cmd_cwd(commands, cwd=os.getcwd()):
cmd = CommandCwd(commands, cwd)
return cmd.run()
def sleep(duration):
LOGGING.debug("sleeping %d" % duration)
time.sleep(duration)
def write_file(save_file, result):
LOGGING.debug(f"write file:{save_file}")
with open(save_file, "a+") as file:
file.write(result + "\n")
file.flush()
def remove_dir(path):
if os.path.exists(path):
shutil.rmtree(path)
def remove_file(file):
if os.path.exists(file):
os.remove(file)
def mkdir(path):
if not os.path.exists(path):
os.makedirs(path)
def report_command(cmd_type, cmd, env=None):
sys.stderr.write(f'{TERM_BLUE}{cmd_type}{TERM_NORMAL}\n')
if env is not None:
sys.stderr.write(''.join(f'{TERM_BLUE}{var}={val} \\{TERM_NORMAL}\n'
for var, val in sorted(env.items())))
cmd_str = (f'{TERM_NORMAL}\n\t{TERM_BLUE}').join(cmd)
sys.stderr.write(f'\t{TERM_BLUE}{cmd_str}{TERM_NORMAL}\n')
sys.stderr.write("\n")
def git_clone(git_url, code_dir):
cmd = ['git', 'clone', git_url, code_dir]
ret = run_cmd_cwd(cmd)
assert not ret, f"\n error: Cloning '{git_url}' failed."
def git_checkout(git_bash, cwd):
cmd = ['git', 'checkout', git_bash]
ret = run_cmd_cwd(cmd, cwd)
assert not ret, f"\n error: git checkout '{git_bash}' failed."
def git_apply(patch_file, cwd):
cmd = ['git', 'apply', patch_file]
ret = run_cmd_cwd(cmd, cwd)
assert not ret, f"\n error: Failed to apply '{patch_file}'"
def git_clean(cwd):
cmd = ['git', 'checkout', '--', '.']
run_cmd_cwd(cmd, cwd)
def npm_install(cwd):
cmd = ['npm', 'install']
ret = run_cmd_cwd(cmd, cwd)
assert not ret, f"\n error: Failed to 'npm install'"
+5
View File
@@ -0,0 +1,5 @@
node_modules/
build
src/builtinsMap.ts
src/irnodes.ts
src/diagnostic.ts
+322
View File
@@ -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.
import("//ark/runtime_core/ark_config.gni")
import("//ark/ts2abc/ts2panda/ts2abc_config.gni")
import("//build/config/clang/clang.gni")
import("//build/ohos.gni")
src_dir = target_out_dir + "/src"
ohos_copy("ts2abc_src") {
sources = [ "${ts2abc_root}/src" ]
outputs = [ src_dir ]
module_install_name = ""
}
ohos_copy("tsconfig_json") {
sources = [ "${ts2abc_root}/tsconfig.json" ]
outputs = [ target_out_dir + "/{{source_file_part}}" ]
module_install_name = ""
}
action("ts2abc_diagnostic_ts") {
visibility = [ ":*" ]
script = "scripts/gen_diagnostic.rb"
args = [
"--template",
rebase_path("templates/diagnostic.ts.erb", root_build_dir),
"--data",
rebase_path("scripts/diagnosticMessages.json", root_build_dir),
"--output",
rebase_path("${src_dir}/diagnostic.ts"),
]
outputs = [ "${src_dir}/diagnostic.ts" ]
deps = [ "$ts2abc_root:ts2abc_src" ]
}
ark_gen_file("ts2abc_irnodes_ts") {
template_file = "templates/irnodes.ts.erb"
data_file = "$ark_root/isa/isa.yaml"
requires = [
"$ark_root/isa/isapi.rb",
"$ark_root/libpandafile/pandafile_isapi.rb",
]
output_file = "$src_dir/irnodes.ts"
extra_dependencies = [ "$ts2abc_root:ts2abc_src" ]
}
ark_gen_file("ts2abc_builtinsMap_ts") {
template_file = "templates/builtinsMap.ts.erb"
data_file = "$ark_root/isa/builtins.yaml"
requires = [
"$ark_root/isa/builtinsapi.rb",
"//ark/js_runtime/ecmascript/ecma_builtins.rb",
]
output_file = "$src_dir/builtinsMap.ts"
extra_dependencies = [ "$ts2abc_root:ts2abc_src" ]
}
action("npm_run_build") {
visibility = [ ":*" ]
deps = [
"$ts2abc_root:ts2abc_builtinsMap_ts",
"$ts2abc_root:ts2abc_diagnostic_ts",
"$ts2abc_root:ts2abc_irnodes_ts",
"$ts2abc_root:ts2abc_src",
"$ts2abc_root:tsconfig_json",
]
script = "${ts2abc_root}/scripts/run.py"
args = [
"--src-dir",
rebase_path(ts2abc_root),
"--dist-dir",
rebase_path(target_out_dir),
"--node",
rebase_path(node_path),
"--node-modules",
rebase_path(node_modules),
]
if (is_linux) {
args += [
"--platform",
"linux",
]
} else if (is_mingw) {
args += [
"--platform",
"win",
]
} else if (is_mac) {
args += [
"--platform",
"mac",
]
}
outputs = []
if (is_mingw) {
outputs += [ "${target_out_dir}/build-win" ]
} else if (is_mac) {
outputs += [ "${target_out_dir}/build-mac" ]
} else {
outputs += [ "${target_out_dir}/build" ]
}
}
if (is_linux) {
ohos_copy("src_linux") {
deps = [ "$ts2abc_root:npm_run_build" ]
sources = [ "${target_out_dir}/build" ]
outputs = [ "${root_out_dir}/ark/ark/build" ]
module_source_dir = target_out_dir + "/build/src"
module_install_name = ""
}
ohos_copy("ts2abc_tool") {
sources = [ "${root_out_dir}/ark/ark/js2abc" ]
outputs = [ "${root_out_dir}/ark/ark/build/bin/{{source_file_part}}" ]
module_install_name = ""
deps = [
":src_linux",
"$ts2abc_root/ts2abc:ts2abc",
]
}
ohos_copy("ts2abc_linux") {
deps = [
":ts2abc_tool",
"$ts2abc_root/ts2abc:ts2abc",
]
sources = [ "${root_out_dir}/ark/ark/js2abc" ]
outputs = [ "${target_out_dir}/build/bin/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build/bin"
module_install_name = ""
}
ohos_copy("ts2abc_build") {
deps = [
":panda_ts2abc",
":ts2abc_linux",
]
sources = [
"${ts2abc_root}/package-lock.json",
"${ts2abc_root}/package.json",
]
outputs = [ "${root_out_dir}/ark/ark/build/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build"
module_install_name = ""
}
ohos_copy("ts2abc_build_ets") {
deps = [
":src_linux",
":ts2abc_build",
]
sources = [ "${root_out_dir}/ark/ark/build" ]
outputs = [ "${root_out_dir}/ark/ark/build-ets" ]
module_source_dir = "${root_out_dir}/ark/ark/build-ets"
module_install_name = ""
}
}
if (is_mingw) {
ohos_copy("src_win") {
deps = [ "$ts2abc_root:npm_run_build" ]
sources = [ "${target_out_dir}/build-win" ]
outputs = [ "${root_out_dir}/ark/ark/build-win" ]
module_source_dir = target_out_dir + "/build-win/src"
module_install_name = ""
}
ohos_copy("ts2abc_tool_win") {
sources = [ "${root_out_dir}/ark/ark/js2abc.exe" ]
outputs = [ "${root_out_dir}/ark/ark/build-win/bin/{{source_file_part}}" ]
module_install_name = ""
deps = [
":src_win",
"$ts2abc_root/ts2abc:ts2abc",
]
}
ohos_copy("ts2abc_win") {
deps = [
":ts2abc_tool_win",
"$ts2abc_root/ts2abc:ts2abc",
]
sources = [ "${root_out_dir}/ark/ark/js2abc.exe" ]
outputs = [ "${target_out_dir}/build-win/bin/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build-win/bin"
module_install_name = ""
}
ohos_copy("ts2abc_build_win") {
deps = [
":panda_ts2abc",
":ts2abc_win",
]
sources = [
"${ts2abc_root}/package-lock.json",
"${ts2abc_root}/package.json",
]
outputs = [ "${root_out_dir}/ark/ark/build-win/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build-win"
module_install_name = ""
}
ohos_copy("ts2abc_build_win_ets") {
deps = [
":src_win",
":ts2abc_build_win",
]
sources = [ "${root_out_dir}/ark/ark/build-win" ]
outputs = [ "${root_out_dir}/ark/ark/build-win-ets" ]
module_source_dir = "${root_out_dir}/ark/ark/build-win-ets"
module_install_name = ""
}
}
if (is_mac) {
ohos_copy("src_mac") {
deps = [ "$ts2abc_root:npm_run_build" ]
sources = [ "${target_out_dir}/build-mac" ]
outputs = [ "${root_out_dir}/ark/ark/build-mac" ]
module_source_dir = target_out_dir + "/build-mac/src"
module_install_name = ""
}
ohos_copy("ts2abc_tool_mac") {
sources = [ "${root_out_dir}/ark/ark/js2abc" ]
outputs = [ "${root_out_dir}/ark/ark/build-mac/bin/{{source_file_part}}" ]
module_install_name = ""
deps = [
":src_mac",
"$ts2abc_root/ts2abc:ts2abc",
]
}
ohos_copy("ts2abc_mac") {
deps = [
":ts2abc_tool_mac",
"$ts2abc_root/ts2abc:ts2abc",
]
sources = [ "${root_out_dir}/ark/ark/js2abc" ]
outputs = [ "${target_out_dir}/build-mac/bin/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build-mac/bin"
module_install_name = ""
}
ohos_copy("ts2abc_build_mac") {
deps = [
":panda_ts2abc",
":ts2abc_mac",
]
sources = [
"${ts2abc_root}/package-lock.json",
"${ts2abc_root}/package.json",
]
outputs = [ "${root_out_dir}/ark/ark/build-mac/{{source_file_part}}" ]
module_source_dir = "${root_out_dir}/ark/ark/build-mac"
module_install_name = ""
}
ohos_copy("ts2abc_build_mac_ets") {
deps = [
":src_mac",
":ts2abc_build_mac",
]
sources = [ "${root_out_dir}/ark/ark/build-mac" ]
outputs = [ "${root_out_dir}/ark/ark/build-mac-ets" ]
module_source_dir = "${root_out_dir}/ark/ark/build-mac-ets"
module_install_name = ""
}
}
ohos_copy("panda_ts2abc") {
sources = [ "${ts2abc_root}/scripts/ts2abc.js" ]
outputs = [ target_out_dir + "/$target_name/{{source_file_part}}" ]
module_source_dir = target_out_dir + "/$target_name/"
module_install_name = ""
}
ohos_copy("panda_ts2abc_ets") {
sources = [ "${ts2abc_root}/scripts/ts2abc.js" ]
outputs = [ target_out_dir + "/$target_name/{{source_file_part}}" ]
module_source_dir = target_out_dir + "/$target_name/"
module_install_name = ""
}
group("ark_ts2abc_build") {
deps = []
if (host_os != "mac") {
deps += [
"${ts2abc_root}:ts2abc_build(${buildtool_linux})",
"${ts2abc_root}:ts2abc_build_ets(${buildtool_linux})",
"${ts2abc_root}:ts2abc_build_win(${buildtool_win})",
"${ts2abc_root}:ts2abc_build_win_ets(${buildtool_win})",
]
}
}
+22
View File
@@ -0,0 +1,22 @@
### ts2panda
ts2panda aims to translate JavaScript source files into ARK bytecode which could be executed by the ARK runtime.
The whole converter could be splited into several phases.
* tsc(TypeScript compiler) automatically builds the AST for us
* translate TypeScript AST into panda instruction arrays
* apply several passes with the instruction arrays, including:
* [register allocator](doc/register_allocator.md)
* [intrinsic expander](doc/intrinsic_expander.md)
* [panda assembly dumper](doc/assembly_dumper.md)
* [panda binary dumper](doc/binary_dumper.md)
### Run a case
The whole ARK project needs to be built before running cases.
#### dump panda binary
```
node --expose-gc ../../out/release/clang_x64/ark/ark/build/src/index.js <your/path/to/case_jsFile> <--> <--output> <output-filename>
```
#### dump panda assembly
```
node --expose-gc ../../out/release/clang_x64/ark/ark/build/src/index.js <your/path/to/case_jsFile> --dump-assembly
```
+2509
View File
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
{
"name": "ts2panda",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build:ts2abc-linux": "mkdir -p build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=../../submodules/panda/cmake/toolchain/host_clang_8.cmake ../ts2abc && make ts2abc -j4",
"build:ts2abc-win": "mkdir -p build-win && cd build-win && cmake -DCMAKE_TOOLCHAIN_FILE=../../submodules/panda/cmake/toolchain/cross-clang-8-x86_64-w64-mingw32-static.cmake ../ts2abc && make ts2abc -j4",
"build:ts2abc-mac": "mkdir -p build-mac && cd build-mac && cmake -DPANDA_ENABLE_CLANG_TIDY=false ../ts2abc && make ts2abc -j4",
"build": "npm run build:irnodes && npm run build:diagnostic && npm run build:ts2abc-linux && npm run build:sources-linux",
"build-win": "npm run build:irnodes && npm run build:diagnostic && npm run build:ts2abc-win && npm run build:sources-win",
"build-mac": "npm run build:irnodes && npm run build:diagnostic && npm run build:ts2abc-mac && npm run build:sources-mac",
"build-full": "npm run build && npm run build-win && npm run build-mac",
"build:irnodes": "scripts/gen_irnodes.sh",
"build:diagnostic": "scripts/gen_diagnostic.sh",
"build:sources-linux": "tsc -b src",
"build:sources-win": "tsc -b src/tsconfig.win.json",
"build:sources-mac": "node_modules/typescript/bin/tsc -b src/tsconfig.mac.json",
"build:tests": "tsc -b src tests",
"run:tests": "mocha \"build/tests/**/*.test.js\"",
"test": "npm run build:tests && npm run run:tests",
"ast": "tsc -b tools && node build/tools/astPrinter.js",
"dev": "node --expose-gc build/src/index.js",
"clean": "rm -rf build && rm -fr build-win && rm -fr build-mac && rm -f src/irnodes.ts && rm -rf src/diagnostic.ts && rm -rf src/builtinsMap.ts"
},
"author": "",
"license": "",
"devDependencies": {
"@types/chai": "^4.2.12",
"@types/mocha": "^8.0.2",
"@types/node": "^14.0.27",
"chai": "^4.2.0",
"mocha": "^8.1.1",
"sinon": "^9.0.3",
"ts-sinon": "^1.2.1",
"typescript": "^3.9.7"
},
"dependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@types/command-line-args": "^5.0.0",
"@types/command-line-usage": "^5.0.1",
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.1",
"minimatch": "^3.0.4",
"recast": "^0.20.4",
"regexpp": "^3.1.0",
"rxjs": "^6.6.3",
"test262-stream": "^1.3.0",
"unique-temp-dir": "^1.0.0",
"yargs": "^16.2.0"
}
}
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env ruby
# 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.
module Diagnostic
module_function
def datas
@data
end
def wrap_data(data)
@data = data
end
end
def Gen.on_require(data)
Diagnostic.wrap_data(data)
end
+515
View File
@@ -0,0 +1,515 @@
{
"Identifier expected.": {
"category": "Error",
"code": 1003
},
"A rest parameter or binding pattern may not have a trailing comma.": {
"category": "Error",
"code": 1013
},
"A rest parameter must be last in a parameter list.": {
"category": "Error",
"code": 1014
},
"Parameter cannot have question mark and initializer.": {
"category": "Error",
"code": 1015
},
"A required parameter cannot follow an optional parameter.": {
"category": "Error",
"code": 1016
},
"The 'readonly' modifier can only appear on a property declaration or index signature.": {
"category": "Error",
"code": 1024
},
"Accessibility modifier already seen.": {
"category": "Error",
"code": 1028
},
"'{0}' modifier must precede '{1}' modifier.": {
"category": "Error",
"code": 1029
},
"'{0}' modifier already seen.": {
"category": "Error",
"code": 1030
},
"'{0}' modifier cannot appear on class elements of this kind.": {
"category": "Error",
"code": 1031
},
"A 'declare' modifier cannot be used in an already ambient context.": {
"category": "Error",
"code": 1038
},
"'{0}' modifier cannot be used in an ambient context.": {
"category": "Error",
"code": 1040
},
"'{0}' modifier cannot be used here.": {
"category": "Error",
"code": 1042
},
"'{0}' modifier cannot appear on a module or namespace element.": {
"category": "Error",
"code": 1044
},
"A rest parameter cannot be optional.": {
"category": "Error",
"code": 1047
},
"A rest parameter cannot have an initializer.": {
"category": "Error",
"code": 1048
},
"'{0}' modifier cannot appear on a type member.": {
"category": "Error",
"code": 1070
},
"'{0}' modifier cannot appear on an index signature.": {
"category": "Error",
"code": 1071
},
"A '{0}' modifier cannot be used with an import declaration.": {
"category": "Error",
"code": 1079
},
"'{0}' modifier cannot appear on a constructor declaration.": {
"category": "Error",
"code": 1089
},
"'{0}' modifier cannot appear on a parameter.": {
"category": "Error",
"code": 1090
},
"Only a single variable declaration is allowed in a 'for...in' statement.": {
"category": "Error",
"code": 1091
},
"Invalid use of '{0}' in strict mode.": {
"category": "Error",
"code": 1100
},
"A 'with' statements are not allowed in strict mode.": {
"category": "Error",
"code": 1101
},
"A 'delete' cannot be called on an identifier in strict mode.": {
"category": "Error",
"code": 1102
},
"A 'continue' statement can only be used within an enclosing iteration statement.": {
"category": "Error",
"code": 1104
},
"A 'break' statement can only be used within an enclosing iteration or switch statement.": {
"category": "Error",
"code": 1105
},
"Jump target cannot cross function boundary.": {
"category": "Error",
"code": 1107
},
"A 'return' statement can only be used within a function body.": {
"category": "Error",
"code": 1108
},
"A 'default' clause cannot appear more than once in a 'switch' statement.": {
"category": "Error",
"code": 1113
},
"Duplicate label '{0}'.": {
"category": "Error",
"code": 1114
},
"A 'continue' statement can only jump to a label of an enclosing iteration statement.": {
"category": "Error",
"code": 1115
},
"A 'break' statement can only jump to a label of an enclosing statement.": {
"category": "Error",
"code": 1116
},
"An object literal cannot have multiple properties with the same name in strict mode.": {
"category": "Error",
"code": 1117
},
"An object literal cannot have multiple get/set accessors with the same name.": {
"category": "Error",
"code": 1118
},
"An object literal cannot have property and accessor with the same name.": {
"category": "Error",
"code": 1119
},
"Octal literals are not allowed in strict mode.": {
"category": "Error",
"code": 1121
},
"Octal escape sequences are not allowed in strict mode.": {
"category": "Error",
"code": 1122
},
"Variable declaration list cannot be empty.": {
"category": "Error",
"code": 1123
},
"Line break not permitted here.": {
"category": "Error",
"code": 1142
},
"The 'const' declarations can only be declared inside a block.": {
"category": "Error",
"code": 1156
},
"The 'const' declarations must be initialized.": {
"category": "Error",
"code": 1155
},
"The 'let' declarations can only be declared inside a block.": {
"category": "Error",
"code": 1157
},
"Unterminated regular expression literal.": {
"category": "Error",
"code": 1161
},
"An object member cannot be declared optional.": {
"category": "Error",
"code": 1162
},
"A 'yield' expression is only allowed in a generator body.": {
"category": "Error",
"code": 1163
},
"A comma expression is not allowed in a computed property name.": {
"category": "Error",
"code": 1171
},
"The 'extends' clause already seen.": {
"category": "Error",
"code": 1172
},
"Classes can only extend a single class.": {
"category": "Error",
"code": 1174
},
"The 'implements' clause already seen.": {
"category": "Error",
"code": 1175
},
"Property destructuring pattern expected.": {
"category": "Error",
"code": 1180
},
"A destructuring declaration must have an initializer.": {
"category": "Error",
"code": 1182
},
"A_rest_element_cannot_have_an_initializer.": {
"category": "Error",
"code": 1186
},
"A parameter property may not be declared using a binding pattern.": {
"category": "Error",
"code": 1187
},
"Only a single variable declaration is allowed in a 'for...of' statement.": {
"category": "Error",
"code": 1188
},
"The variable declaration of a 'for...in' statement cannot have an initializer.": {
"category": "Error",
"code": 1189
},
"The variable declaration of a 'for...of' statement cannot have an initializer.": {
"category": "Error",
"code": 1190
},
"Line terminator not permitted before arrow.": {
"category": "Error",
"code": 1200
},
"Decorators are not valid here.": {
"category": "Error",
"code": 1206
},
"Decorators cannot be applied to multiple get/set accessors of the same name.": {
"category": "Error",
"code": 1207
},
"Invalid use of '{0}'. Class definitions are automatically in strict mode.": {
"category": "Error",
"code": 1210
},
"Identifier expected. '{0}' is a reserved word in strict mode.": {
"category": "Error",
"code": 1212
},
"Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode.": {
"category": "Error",
"code": 1213
},
"Identifier expected. '{0}' is a reserved word in strict mode. Modules are automatically in strict mode.": {
"category": "Error",
"code": 1214
},
"An import declaration can only be used in a namespace or module.": {
"category": "Error",
"code": 1232
},
"An export declaration can only be used in a module.": {
"category": "Error",
"code": 1233
},
"The 'abstract' modifier can only appear on a class, method, or property declaration.": {
"category": "Error",
"code": 1242
},
"'{0}' modifier cannot be used with '{1}' modifier.": {
"category": "Error",
"code": 1243
},
"Abstract methods can only appear within an abstract class.": {
"category": "Error",
"code": 1244
},
"A class member cannot have the '{0}' keyword.": {
"category": "Error",
"code": 1248
},
"A decorator can only decorate a method implementation, not an overload.": {
"category": "Error",
"code": 1249
},
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.": {
"category": "Error",
"code": 1250
},
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Class definitions are automatically in strict mode.": {
"category": "Error",
"code": 1251
},
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Modules are automatically in strict mode.": {
"category": "Error",
"code": 1252
},
"A definite assignment assertion '!' is not permitted in this context.": {
"category": "Error",
"code": 1255
},
"Identifier expected. '{0}' is a reserved word at the top-level of a module.": {
"category": "Error",
"code": 1262
},
"Declarations with initializers cannot also have definite assignment assertions.": {
"category": "Error",
"code": 1263
},
"Declarations with definite assignment assertions must also have type annotations.": {
"category": "Error",
"code": 1264
},
"await expressions are only allowed within async functions and at the top levels of modules.": {
"category": "Error",
"code": 1308
},
"Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern.": {
"category": "Error",
"code": 1312
},
"A parameter property cannot be declared using a rest parameter.": {
"category": "Error",
"code": 1317
},
"A default export can only be used in an ECMAScript-style module.": {
"category": "Error",
"code": 1319
},
"use strict directive cannot be used with non-simple parameter list.": {
"category": "Error",
"code": 1347
},
"Identifier expected. '{0}' is a reserved word that cannot be used here.": {
"category": "Error",
"code": 1359
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
},
"The 'super' can only be referenced in a derived class.": {
"category": "Error",
"code": 2335
},
"The 'super' cannot be referenced in constructor arguments.": {
"category": "Error",
"code": 2336
},
"Super calls are not permitted outside constructors or in nested functions inside constructors.": {
"category": "Error",
"code": 2337
},
"The 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": {
"category": "Error",
"code": 2338
},
"The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.": {
"category": "Error",
"code": 2358
},
"The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.": {
"category": "Error",
"code": 2359
},
"The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.": {
"category": "Error",
"code": 2360
},
"The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.": {
"category": "Error",
"code": 2361
},
"The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
"category": "Error",
"code": 2362
},
"The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
"category": "Error",
"code": 2363
},
"The left-hand side of an assignment expression must be a variable or a property access.": {
"category": "Error",
"code": 2364
},
"Multiple constructor implementations are not allowed.": {
"category": "Error",
"code": 2392
},
"Declaration name conflicts with built-in global identifier '{0}'.": {
"category": "Error",
"code": 2397
},
"The left-hand side of a 'for...in' statement cannot use a type annotation.": {
"category": "Error",
"code": 2404
},
"The 'super' cannot be referenced in a computed property name.": {
"category": "Error",
"code": 2466
},
"A rest element must be last in a destructuring pattern.": {
"category": "Error",
"code": 2462
},
"The 'let' is not allowed to be used as a name in 'let' or 'const' declarations.": {
"category": "Error",
"code": 2480
},
"The left-hand side of a 'for...of' statement cannot use a type annotation.": {
"category": "Error",
"code": 2483
},
"The left-hand side of a 'for...of' statement must be a variable or a property access.": {
"category": "Error",
"code": 2487
},
"The left-hand side of a 'for...in' statement cannot be a destructuring pattern.": {
"category": "Error",
"code": 2491
},
"A rest element cannot contain a binding pattern.": {
"category": "Error",
"code": 2501
},
"The 'super' can only be referenced in members of derived classes or object literal expressions.": {
"category": "Error",
"code": 2660
},
"Cannot export '{0}'. Only local declarations can be exported from a module.": {
"category": "Error",
"code": 2661
},
"Left side of comma operator is unused and has no side effects.": {
"category": "Error",
"code": 2695,
"reportsUnnecessary": true
},
"The target of an object rest assignment must be a variable or a property access.": {
"category": "Error",
"code": 2701
},
"The target of an object rest assignment may not be an optional property access.": {
"category": "Error",
"code": 2778
},
"The left-hand side of an assignment expression may not be an optional property access.": {
"category": "Error",
"code": 2779
},
"The left-hand side of a 'for...of' statement may not be an optional property access.": {
"category": "Error",
"code": 2781
},
"'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?": {
"category": "Error",
"code": 17012
},
"Meta-property '{0}' is only allowed in the body of a function declaration, function expression, or constructor.": {
"category": "Error",
"code": 17013
},
"An accessibility modifier cannot be used with a private identifier.": {
"category": "Error",
"code": 18010
},
"Private identifiers are not allowed outside class bodies.": {
"category": "Error",
"code": 18016
},
"'{0}' modifier cannot be used with a private identifier.": {
"category": "Error",
"code": 18019
},
"In strict mode code, functions can only be declared at top level or inside a block.": {
"category": "Error",
"code": 19000
},
"Class Declaration can only be declared at top level or inside a block.": {
"category": "Error",
"code": 19001
},
"Incorrect regular expression": {
"category": "Error",
"code": 19002
},
"Invalid regular expression: '{0}': Invalid escape": {
"category": "Error",
"code": 19003
},
"\\8 and \\9 are not allowed in strict mode": {
"category": "Error",
"code": 19004
},
"const and let declarations not allowed in statement positions": {
"category": "Error",
"code": 19005
},
"Getter must not have any formal parameters": {
"category": "Error",
"code": 19006
},
"Class declaration not allowed in statement position": {
"category": "Error",
"code": 19007
},
"Lexical declaration 'let' not allowed in statement position": {
"category": "Error",
"code": 19008
},
"Lexical declaration 'const' not allowed in statement position": {
"category": "Error",
"code": 19009
}
}
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env ruby
# 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.
require 'optparse'
require 'yaml'
require 'json'
require 'erb'
module Gen
def self.on_require(data); end
end
require_relative ('diagnostic')
def create_sandbox
# nothing but Ruby core libs and 'required' files
binding
end
def check_option(optparser, options, key)
return if options[key]
puts "Missing option: --#{key}"
puts optparser
exit false
end
options = OpenStruct.new
optparser = OptionParser.new do |opts|
opts.banner = 'Usage: gen.rb [options]'
opts.on('-t', '--template FILE', 'Template for file generation (required)')
opts.on('-d', '--datafile FILE', 'Source data in JSON format (required)')
opts.on('-o', '--output FILE', 'Output file (required)')
opts.on('-r', '--require foo,bar,baz', Array, 'List of files to be required for generation')
opts.on('-h', '--help', 'Prints this help') do
puts opts
exit
end
end
optparser.parse!(into: options)
check_option(optparser, options, :datafile)
check_option(optparser, options, :template)
check_option(optparser, options, :output)
template_file = File.read(options.template)
output_file = File.open(options.output, 'w')
data = YAML.load_file(options.datafile)
data = JSON.parse(data.to_json)
options&.require&.each { |r| require r }
Gen.on_require(data)
t = ERB.new(template_file, nil, '%-')
t.filename = options.template
output_file.write(t.result(create_sandbox))
output_file.close
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# 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.
set -e
PANDA_ROOT="../submodules/panda"
ISA="scripts/diagnosticMessages.json"
TEMPLATE="templates/diagnostic.ts.erb"
OUTPUT="src/diagnostic.ts"
ruby scripts/gen_diagnostic.rb --template $TEMPLATE --data $ISA --output $OUTPUT
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# 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.
set -e
PANDA_ROOT="../submodules/panda"
ISA="$PANDA_ROOT/isa/isa.yaml"
DEPS="$PANDA_ROOT/isa/isapi.rb,$PANDA_ROOT/libpandafile/pandafile_isapi.rb"
TEMPLATE="templates/irnodes.ts.erb"
OUTPUT="src/irnodes.ts"
ruby $PANDA_ROOT/isa/gen.rb --template $TEMPLATE --data $ISA --output $OUTPUT --require "$DEPS"
BUILTIN_DATA="$PANDA_ROOT/isa/builtins.yaml"
BUILTIN_REQS="$PANDA_ROOT/isa/builtinsapi.rb,$PANDA_ROOT/runtime/ecmascript/ecma_builtins.rb"
BUILTIN_TEMPLATE="templates/builtinsMap.ts.erb"
BUILTIN_OUTPUT="src/builtinsMap.ts"
ruby $PANDA_ROOT/isa/gen.rb --template $BUILTIN_TEMPLATE --data $BUILTIN_DATA --output $BUILTIN_OUTPUT --require "$BUILTIN_REQS"
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
# coding: utf-8
"""
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.
Description: Generate javascript byte code
"""
import os
import subprocess
import platform
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--src-js',
help='js source file')
parser.add_argument('--dst-file',
help='the converted target file')
parser.add_argument("--node",
help='path to nodejs exetuable')
parser.add_argument('--frontend-tool-path',
help='path to frontend conversion tool')
parser.add_argument("--node-modules",
help='path to node-modules exetuable')
parser.add_argument("--debug", action='store_true',
help='whether add debuginfo')
arguments = parser.parse_args()
return arguments
def set_env(input_arguments):
jsoner_format = ":"
if platform.system() == "Windows":
jsoner_format = ";"
os.environ["PATH"] = input_arguments.node + \
jsoner_format + os.environ["PATH"]
def run_command(cmd, execution_path):
print(" ".join(cmd) + " | execution_path: " + execution_path)
proc = subprocess.Popen(cmd, cwd=execution_path)
proc.wait()
def gen_abc_info(input_arguments):
set_env(input_arguments)
frontend_tool_path = input_arguments.frontend_tool_path
(path, name) = os.path.split(frontend_tool_path)
if not os.path.exists(os.path.join(path, "node_modules")):
if input_arguments.node_modules:
cmd = ['cp', "-rf", input_arguments.node_modules, path]
run_command(cmd, path)
else:
cmd = ['npm', 'install']
run_command(cmd, path)
cmd = [os.path.join(input_arguments.node, "node"),
'--expose-gc',
os.path.join(name, 'src/index.js'),
input_arguments.src_js,
'-o', input_arguments.dst_file,
'-t', '0']
if input_arguments.debug:
cmd.insert(3, '--debug')
run_command(cmd, path)
if __name__ == '__main__':
gen_abc_info(parse_args())
+171
View File
@@ -0,0 +1,171 @@
#!/usr/bin/env python3
#coding: utf-8
"""
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.
Description: Generate interface to get java plugin's js code and binary
"""
import os
import subprocess
import argparse
JAVA_FILE_SUFFIX = "JsCode"
JS_BIN_EXT = ".abc"
ARRAY_MAX = 8192 # size of 8K
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--node",
help="path to nodejs exetuable")
parser.add_argument("--frontend-tool-path",
help="path to frontend conversion tool")
parser.add_argument("--node-modules",
help='path to node-modules exetuable')
parser.add_argument("--plugin-path",
help="plugin js file path")
parser.add_argument("--plugin-name",
help="name of js file, ex: BatteryPlugin.js")
parser.add_argument("--generated-file",
help="name of generated file")
parser.add_argument("--package-name",
help="name of generated file's package")
arguments = parser.parse_args()
return arguments
def split_array_by_n(array, max_len):
for i in range(0, len(array), max_len):
yield array[i: i + max_len]
def gen_bin_info(input_arguments):
file_name = input_arguments.plugin_name
file_path = input_arguments.plugin_path
js_file = os.path.join(file_path, file_name)
file_name_pre = os.path.splitext(file_name)[0]
generate_js_bytecode = os.path.join(
os.path.dirname(__file__), "generate_js_bytecode.py")
(out_dir, _) = os.path.split(input_arguments.generated_file)
dst_file = os.path.join(out_dir, f'{file_name_pre}{JS_BIN_EXT}')
args = [
'--src-js',
js_file,
'--dst-file',
dst_file,
'--node',
input_arguments.node,
'--frontend-tool-path',
input_arguments.frontend_tool_path,
'--node-modules',
input_arguments.node_modules,
]
proc = subprocess.Popen(['python3', generate_js_bytecode] + args)
return_code = proc.wait()
return return_code
def gen_java_method(input_arguments):
file_name = input_arguments.plugin_name
file_path = input_arguments.plugin_path
out_file = input_arguments.generated_file
file_name_pre = os.path.splitext(file_name)[0]
js_src_file = os.path.join(file_path, file_name)
(out_dir, _) = os.path.split(input_arguments.generated_file)
js_bin_file = os.path.join(out_dir, file_name_pre + JS_BIN_EXT)
with open(out_file, "w") as output:
output.write("/*%s * Generated from Java and JavaScript plugins by ts2abc.%s */%s%s"
% (os.linesep, os.linesep, os.linesep, os.linesep))
output.write("package %s;%s"
% (input_arguments.package_name, os.linesep))
output.write("%s" % os.linesep)
output.write("public class %s%s {%s"
% (file_name_pre, JAVA_FILE_SUFFIX, os.linesep))
# write method: getJsCode
with open(js_src_file, "r") as input_src:
output.write(" public static String getJsCode() {%s"
% os.linesep)
output.write(" return%s" % os.linesep)
lines = input_src.readlines()
for line in lines[:-1]:
line = line.strip(os.linesep)
line = line.replace("\"", "\\\"")
output.write(" \"%s\\n\" +%s" % (line, os.linesep))
last_line = lines[-1].replace("\"", "\\\"").strip(os.linesep)
output.write(" \"%s\";%s" % (last_line, os.linesep))
output.write(" }%s" % os.linesep)
output.write("%s" % os.linesep)
# write method: getJsBytecode
with open(js_bin_file, "rb") as input_bin:
# seperate bytecode list
buf = bytearray(os.path.getsize(js_bin_file))
input_bin.readinto(buf)
hex_str = [hex(i) for i in buf]
byte_str = ["(byte)" + i for i in hex_str]
seperate_array = split_array_by_n(byte_str, ARRAY_MAX)
# generate seperate methods for js bytecode with ARRAY_MAX
method_idx = 0
method_len_list = []
for array in seperate_array:
output.write(" private static byte[] getJsByteCode_%s() {%s"
% (method_idx, os.linesep))
output.write(" return new byte[] {")
output.write(", ".join(array))
output.write("};%s" % os.linesep)
output.write(" }%s" % os.linesep)
method_idx = method_idx + 1
method_len_list.append(len(array))
# generate a method collect all seperated arrays
cur_pos = 0
output.write(" public static byte[] getJsByteCode() {%s"
% os.linesep)
output.write(" byte[] allByteCode = new byte[%s];%s"
% (len(byte_str), os.linesep))
for idx, method_len in enumerate(method_len_list):
output.write(" System.arraycopy(getJsByteCode_%s(), "
"0, allByteCode, %s, %s);%s"
% (idx, cur_pos, method_len, os.linesep))
cur_pos = cur_pos + method_len
output.write(" return allByteCode;%s" % os.linesep)
output.write(" }%s" % os.linesep)
output.write("}")
def operate_file(input_arguments):
retcode = gen_bin_info(input_arguments)
if retcode != 0:
return
gen_java_method(input_arguments)
if __name__ == "__main__":
operate_file(parse_args())
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
# coding: utf-8
"""
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.
Description: Compile ark front-end code with tsc
"""
import os
import subprocess
import argparse
import platform
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--src-dir',
help='Source directory')
parser.add_argument('--dist-dir',
help='Destination directory')
parser.add_argument('--platform',
help='platform, as: linux, mac, win')
parser.add_argument('--node',
help='node path')
parser.add_argument("--node-modules",
help='path to node-modules exetuable')
arguments = parser.parse_args()
return arguments
def set_env(node_dir):
jsoner_format = ":"
if platform.system() == "Windows":
jsoner_format = ";"
os.environ["PATH"] = f'{node_dir}{jsoner_format}{os.environ["PATH"]}'
def run_command(cmd, execution_path=os.getcwd()):
print(" ".join(cmd) + " | execution_path: " + execution_path)
proc = subprocess.Popen(cmd, cwd=execution_path)
ret = proc.wait()
assert not ret, f'\n{" ".join(cmd)} failed'
def node_modules(options):
src_dir = options.src_dir
dist_dir = options.dist_dir
run_command(['cp', '-f', os.path.join(src_dir, "package.json"),
os.path.join(dist_dir, "package.json")])
run_command(['cp', '-f', os.path.join(src_dir, "package-lock.json"),
os.path.join(dist_dir, "package-lock.json")])
if options.node_modules:
run_command(['cp', '-rf', options.node_modules,
os.path.join(dist_dir, "node_modules")])
else:
run_command(['npm', 'install'], dist_dir)
def npm_run_build(options):
plat_form = options.platform
node_modules_dir = os.path.join(options.dist_dir, 'node_modules')
tsc = os.path.join(node_modules_dir, "typescript/bin/tsc")
if plat_form == "linux":
cmd = [tsc, '-b', 'src']
run_command(cmd, options.dist_dir)
elif plat_form == "win":
cmd = [tsc, '-b', 'src/tsconfig.win.json']
run_command(cmd, options.dist_dir)
elif plat_form == 'mac':
cmd = [tsc, '-b', 'src/tsconfig.mac.json']
run_command(cmd, options.dist_dir)
if __name__ == "__main__":
ARGS = parse_args()
set_env(ARGS.node)
node_modules(ARGS)
npm_run_build(ARGS)
+52
View File
@@ -0,0 +1,52 @@
/*
* 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.
*/
"use strict";
const path = require("path");
const fs = require("fs");
const spawn = require('child_process').spawn;
let isWin = !1;
let isMac = !1;
const arkDir = path.resolve(__dirname);
if (fs.existsSync(path.join(arkDir, 'build-win'))) {
isWin = !0;
} else if (fs.existsSync(path.join(arkDir, 'build-mac'))) {
isMac = !0;
} else if (!fs.existsSync(path.join(arkDir, 'build'))) {
throw Error('find build fail').message;
}
let js2abc;
if (isWin) {
js2abc = path.join(arkDir, 'build-win', 'bin', 'js2abc.exe');
} else if (isMac) {
js2abc = path.join(arkDir, 'build-mac', 'bin', 'js2abc');
} else {
js2abc = path.join(arkDir, 'build', 'bin', 'js2abc');
}
let args = process.argv.splice(2);
let proc = spawn(`${js2abc}`, args);
proc.stderr.on('data', (data) => {
throw Error(`${data}`).message;
});
proc.stdout.on('data', (data) => {
process.stdout.write(`${data}`);
});
+176
View File
@@ -0,0 +1,176 @@
/*
* 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.
*/
import * as ts from "typescript";
import { isBindingPattern } from "./base/util";
import * as jshelpers from "./jshelpers";
import { Recorder } from "./recorder";
import {
CatchParameter,
ClassDecl,
ConstDecl,
Decl,
FuncDecl,
InitStatus,
LetDecl,
ModDecl,
ModuleScope,
Scope,
VarDecl,
VariableScope
} from "./scope";
import { isGlobalIdentifier } from "./syntaxCheckHelper";
import { VarDeclarationKind } from "./variable";
function addInnerArgs(node: ts.Node, scope: VariableScope): void {
// the first argument for js function is func_obj
scope.addParameter("4funcObj", VarDeclarationKind.CONST, -1);
// the second argument for newTarget
if (node.kind == ts.SyntaxKind.ArrowFunction) {
scope.addParameter("0newTarget", VarDeclarationKind.CONST, -1);
scope.addParameter("0this", VarDeclarationKind.CONST, 0);
} else {
scope.addParameter("4newTarget", VarDeclarationKind.CONST, -1);
scope.addParameter("this", VarDeclarationKind.CONST, 0);
}
if (node.kind != ts.SyntaxKind.SourceFile) {
let funcNode = <ts.FunctionLikeDeclaration>node;
addParameters(funcNode, scope);
}
if (scope.getUseArgs()) {
if (ts.isArrowFunction(node)) {
let parentVariableScope = <VariableScope>scope.getParentVariableScope();
parentVariableScope.add("arguments", VarDeclarationKind.CONST, InitStatus.INITIALIZED);
parentVariableScope.setUseArgs(true);
scope.setUseArgs(false);
} else {
if (!scope.findLocal("arguments")) {
scope.add("arguments", VarDeclarationKind.CONST, InitStatus.INITIALIZED);
}
}
}
}
export function addVariableToScope(recorder: Recorder) {
let scopeMap = recorder.getScopeMap();
let hoistMap = recorder.getHoistMap();
scopeMap.forEach((scope, node) => {
let hoistDecls = [];
if (scope instanceof VariableScope) {
addInnerArgs(node, scope);
hoistDecls = <Decl[]>hoistMap.get(scope);
if (hoistDecls) {
hoistDecls.forEach(hoistDecl => {
if (hoistDecl instanceof VarDecl) {
scope.add(hoistDecl.name, VarDeclarationKind.VAR);
} else if (hoistDecl instanceof FuncDecl) {
scope.add(hoistDecl.name, VarDeclarationKind.FUNCTION);
} else {
throw new Error("Wrong type of declaration to be hoisted")
}
})
}
}
let decls = scope.getDecls();
let nearestVariableScope = <VariableScope>scope.getNearestVariableScope();
hoistDecls = <Decl[]>hoistMap.get(nearestVariableScope);
for (let j = 0; j < decls.length; j++) {
let decl = decls[j];
if (hoistDecls && hoistDecls.includes(decl)) {
continue;
}
if (decl instanceof LetDecl) {
scope.add(decl.name, VarDeclarationKind.LET, InitStatus.UNINITIALIZED);
} else if (decl instanceof ConstDecl) {
scope.add(decl.name, VarDeclarationKind.CONST, InitStatus.UNINITIALIZED);
} else if (decl instanceof FuncDecl) {
scope.add(decl.name, VarDeclarationKind.FUNCTION);
} else if (decl instanceof CatchParameter) {
scope.add(decl.name, VarDeclarationKind.LET);
} else if (decl instanceof ModDecl) {
if (!(scope instanceof ModuleScope)) {
throw new Error("ModuleVariable can't exist without ModuleScope");
}
scope.add(decl.name, VarDeclarationKind.MODULE);
} else if (decl instanceof ClassDecl) {
let classNode = decl.node;
if (ts.isClassDeclaration(classNode)) {
scope.add(decl.name, VarDeclarationKind.CLASS, InitStatus.UNINITIALIZED);
} else {
let classScope = <Scope>recorder.getScopeOfNode(classNode);
classScope.add(decl.name, VarDeclarationKind.CLASS, InitStatus.UNINITIALIZED);
}
} else {
/**
* Case 1: var declaration share a same name with function declaration, then
* function declaration will be hoisted and the var declaration will be left be.
* Case 2: "var undefined" in global scope is not added to hoistDecls,
* but it should be added to scope
*/
if (isGlobalIdentifier(decls[j].name)) {
scope.add(decls[j].name, VarDeclarationKind.VAR);
}
}
}
})
}
function addParameters(node: ts.FunctionLikeDeclaration, scope: VariableScope): void {
let patternParams: Array<ts.BindingPattern> = new Array<ts.BindingPattern>();
for (let i = 0; i < node.parameters.length; ++i) {
let param = node.parameters[i];
let name: string = '';
if (isBindingPattern(param.name)) {
patternParams.push(<ts.BindingPattern>param.name);
name = i.toString() + "pattern";
} else if (ts.isIdentifier(param.name)) {
name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>param.name);
}
scope.addParameter(name, VarDeclarationKind.VAR, i + 1);
}
for (let i = 0; i < patternParams.length; i++) {
addPatternParamterElements(patternParams[i], scope);
}
}
function addPatternParamterElements(pattern: ts.BindingPattern, scope: VariableScope) {
let name: string = '';
pattern.elements.forEach(bindingElement => {
if (ts.isOmittedExpression(bindingElement)) {
return;
}
bindingElement = <ts.BindingElement>bindingElement;
if (ts.isIdentifier(bindingElement.name)) {
name = jshelpers.getTextOfIdentifierOrLiteral(bindingElement.name);
scope.add(name, VarDeclarationKind.VAR);
} else if (isBindingPattern(bindingElement.name)) {
let innerPattern = <ts.BindingPattern>bindingElement.name;
addPatternParamterElements(innerPattern, scope);
}
});
}
+220
View File
@@ -0,0 +1,220 @@
/*
* 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.
*/
import {
BuiltinR2i,
Imm,
IRNode,
IRNodeKind,
Label,
OperandKind,
VReg
} from "./irnodes";
import { generateCatchTables } from "./statement/tryStatement";
import { PandaGen } from "./pandagen";
import { CmdOptions } from "./cmdOptions";
import { builtinsCodeMap } from "./builtinsMap";
export class IntrinsicInfo {
readonly intrinsicName: string;
readonly argsNum: number;
readonly returnType: string;
constructor(intrinsicName: string, argsNum: number, returnType: string) {
this.intrinsicName = intrinsicName;
this.argsNum = argsNum;
this.returnType = returnType;
}
}
export class AssemblyDumper {
private labels: Map<number, string> // Label.id : Label string name
private labelId: number;
private pg: PandaGen;
readonly labelPrefix = "LABEL_";
static intrinsicRec: Map<string, IntrinsicInfo> = new Map<string, IntrinsicInfo>();
private output: string;
constructor(pg: PandaGen) {
this.pg = pg;
this.labels = new Map<number, string>();
this.labelId = 0;
this.output = "";
}
static writeLanguageTag(out: any): void {
out.str += ".language ECMAScript\n";
out.str += "\n";
}
static writeIntrinsicDecl(out: any): void {
out.str += ".record Ecmascript.Intrinsics <external>\n";
AssemblyDumper.intrinsicRec.forEach((intrinsicInfo, mnemonic) => {
out.str += ".function " + intrinsicInfo!.returnType + " Ecmascript.Intrinsics." + mnemonic + "(";
let intrinsicArgNum = intrinsicInfo!.argsNum;
for (let i = 0; i < intrinsicArgNum; i++) {
out.str += "any a" + i.toString();
if (i != intrinsicArgNum - 1) {
out.str += ", ";
}
}
out.str += ") <external>\n";
})
}
writeFunctionHeader(): void {
let parametersCount = this.pg.getParametersCount();
this.output += ".function any " + this.pg.internalName + "("
for (let i = 0; i < parametersCount; ++i) {
this.output += "any a" + i.toString();
if (i !== parametersCount - 1) {
this.output += ", ";
}
}
this.output += ") {\n";
}
writeFunctionBody(): void {
let irNodes: IRNode[] = this.pg.getInsns();
let parametersCount = this.pg.getParametersCount();
/* the first parametersCount insns are mov.dyn insns for argument initialization,
we can directly dump them into text
*/
for (let i = 0; i < parametersCount; ++i) {
let node = irNodes[i];
this.output += "\t";
this.output += node.mnemonic + " v" + (<VReg>node.operands[0]).num + ", a" + ((<VReg>node.operands[0]).num) + "\n";
}
for (let i = parametersCount; i < irNodes.length; ++i) {
let node = irNodes[i];
if (node.kind === IRNodeKind.VREG || node.kind === IRNodeKind.IMM) {
continue;
}
if (node.kind === IRNodeKind.LABEL) {
this.writeLabel(<Label>node);
continue;
}
this.output += "\t"
this.output += node.mnemonic + " ";
let operands = node.operands;
let formats = node.formats;
for (let j = 0; j < operands.length; ++j) {
let format = formats[0];
let kind = format[j].kind;
let op = operands[j];
if (kind == OperandKind.Imm) {
let imm = <Imm>op;
this.output += imm.value.toString();
} else if (kind == OperandKind.Id) {
this.output += op;
} else if (kind == OperandKind.StringId) {
let escapedOp = op.toString().replace(/\\/g, "\\\\").replace(/\t/g, "\\t")
.replace(/\n/g, "\\n").replace(/\"/g, "\\\"")
this.output += "\"" + escapedOp + "\"";
} else if (kind == OperandKind.DstVReg
|| kind == OperandKind.SrcDstVReg
|| kind == OperandKind.SrcVReg) {
let v = <VReg>op;
if (v.num < 0) {
throw Error("invalid register, please check your insn!\nRegister was allocated at:\n" + v.getStackTrace() + "\n");
}
this.output += "v" + v.num.toString();
if (node instanceof BuiltinR2i) {
break; // we don't need to print all the registers, just the first one
}
} else if (kind == OperandKind.Label) {
this.output += this.getLabelName(<Label>op);
} else {
throw new Error("Unexpected OperandKind");
}
if (j < operands.length - 1) {
this.output += ", ";
}
}
if (CmdOptions.isVariantBytecode()) {
if (node.mnemonic.startsWith('builtin')) {
if (node.operands[0] instanceof Imm) {
let subcode = node.operands[0].value;
this.output += " # " + (builtinsCodeMap as any)[node.mnemonic][subcode];
} else {
throw new Error("can't go here" + node.toString());
}
}
}
this.output += "\n";
}
}
writeFunctionTail(): void {
this.output += "}\n";
}
writeFunctionCatchTable(): void {
let catchTables = generateCatchTables(this.pg.getCatchMap());
if (catchTables.length == 0) {
return;
}
this.output += "\n";
catchTables.forEach((catchTable) => {
let catchBeginLabel = catchTable.getCatchBeginLabel();
let labelPairs = catchTable.getLabelPairs();
labelPairs.forEach((labelPair) => {
this.output += ".catchall " + this.getLabelName(labelPair.getBeginLabel())
+ ", " + this.getLabelName(labelPair.getEndLabel())
+ ", " + this.getLabelName(catchBeginLabel)
+ "\n"
});
});
}
getLabelName(label: Label): string {
let labelName: string;
if (!this.labels.has(label.id)) {
labelName = this.labelPrefix + this.labelId++;
this.labels.set(label.id, labelName);
} else {
labelName = this.labels.get(label.id)!;
}
return labelName;
}
writeLabel(label: Label): void {
let labelName = this.getLabelName(label);
this.output += labelName + ":\n";
}
dump(): void {
this.writeFunctionHeader();
this.writeFunctionBody();
this.writeFunctionCatchTable();
this.writeFunctionTail();
console.log(this.output);
}
static dumpHeader(): void {
let out = { str: "" };
AssemblyDumper.writeLanguageTag(out);
if (!CmdOptions.isVariantBytecode()) {
AssemblyDumper.writeIntrinsicDecl(out);
}
console.log(out.str)
}
}
+35
View File
@@ -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.
*/
import * as ts from "typescript";
import { VarDeclarationKind } from "./variable";
export function getVarDeclarationKind(decl: ts.VariableDeclaration): VarDeclarationKind {
if (decl.parent.kind == ts.SyntaxKind.VariableDeclarationList) {
let declList = <ts.VariableDeclarationList>decl.parent;
if ((declList.flags & ts.NodeFlags.Let) != 0) {
return VarDeclarationKind.LET;
} else if ((declList.flags & ts.NodeFlags.Const) != 0) {
return VarDeclarationKind.CONST;
} else {
return VarDeclarationKind.VAR;
}
} else if (decl.parent.kind == ts.SyntaxKind.CatchClause) {
return VarDeclarationKind.LET;
} else {
throw new Error("VariableDeclaration inside " + ts.SyntaxKind[decl.parent] + " is not implemented");
}
}
+385
View File
@@ -0,0 +1,385 @@
/*
* 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.
*/
import {
Call0Dyn,
Call1Dyn,
Call2Dyn,
Call3Dyn,
CalliRangeDyn,
CalliThisRangeDyn,
CloseIterator,
CopyDataProperties,
CopyModule,
CreateArrayWithBuffer,
CreateEmptyArray,
CreateEmptyObject,
CreateObjectHavingMethod,
CreateObjectWithBuffer,
CreateObjectWithExcludedKeys,
SetObjectWithProto,
Debugger,
DefineClassWithBuffer,
DefineGetterSetterByValue,
DelObjProp,
FldaiDyn,
GetIterator,
GetIteratorNext,
GetNextPropName,
GetPropertiesIterator,
Imm,
ImportModule,
IRNode,
Jmp,
Label,
LdaDyn,
LdaiDyn,
LdaStr,
LdGlobalVar,
LdHomeObject,
LdLexEnv,
LdLexVar,
LdModvarByName,
LdObjByIndex,
LdObjByName,
LdObjByValue,
LdSuperByName,
LdSuperByValue,
MovDyn,
NewLexEnv,
NewObjDynRange,
PopLexEnv,
ResultType,
ReturnUndefined,
StaDyn,
StArraySpread,
StGlobalVar,
StLexVar,
StModuleVar,
StObjByIndex,
StObjByName,
StObjByValue,
StOwnByIndex,
StOwnByName,
StOwnByValue,
StSuperByName,
StSuperByValue,
SuperCall,
SuperCallSpread,
ThrowConstAssignment,
ThrowDyn,
ThrowDeleteSuperProperty,
ThrowIfNotObject,
ThrowIfSuperNotCorrectCall,
ThrowPatternNonCoercible,
ThrowThrowNotExists,
ThrowUndefinedIfHole,
TryLdGlobalByName,
TryLdGlobalByValue,
TryStGlobalByName,
TryStGlobalByValue,
VReg
} from "../irnodes";
export function loadAccumulatorInt(value: number): IRNode {
return new LdaiDyn(new Imm(ResultType.Int, value));
}
export function loadAccumulatorFloat(value: number): IRNode {
return new FldaiDyn(new Imm(ResultType.Float, value));
}
export function loadAccumulatorString(value: string): IRNode {
return new LdaStr(value);
}
export function loadAccumulator(vreg: VReg): IRNode {
return new LdaDyn(vreg);
}
export function storeAccumulator(vreg: VReg): IRNode {
return new StaDyn(vreg);
}
export function deleteObjProperty(obj: VReg, prop: VReg): IRNode {
return new DelObjProp(obj, prop);
}
export function moveVreg(vd: VReg, vs: VReg): IRNode {
return new MovDyn(vd, vs);
}
export function jumpTarget(target: Label): IRNode {
return new Jmp(target);
}
export function creatDebugger(): IRNode {
return new Debugger();
}
export function throwException(): IRNode {
return new ThrowDyn();
}
export function throwConstAssignment(name: VReg) {
return new ThrowConstAssignment(name);
}
export function throwUndefinedIfHole(hole: VReg, name: VReg) {
return new ThrowUndefinedIfHole(hole, name);
}
export function throwThrowNotExists() {
return new ThrowThrowNotExists();
}
export function throwDeleteSuperProperty() {
return new ThrowDeleteSuperProperty();
}
export function newLexicalEnv(numVars: number) {
return new NewLexEnv(new Imm(ResultType.Int, numVars));
}
export function loadLexicalEnv() {
return new LdLexEnv();
}
export function popLexicalEnv() {
return new PopLexEnv();
}
export function loadLexicalVar(level: number, slot: number) {
return new LdLexVar(new Imm(ResultType.Int, level), new Imm(ResultType.Int, slot));
}
export function storeLexicalVar(level: number, slot: number, value: VReg) {
return new StLexVar(new Imm(ResultType.Int, level), new Imm(ResultType.Int, slot), value);
}
export function tryLoadGlobalByName(key: string) {
return new TryLdGlobalByName(key);
}
export function tryStoreGlobalByName(key: string) {
return new TryStGlobalByName(key);
}
export function tryLoadGlobalByValue(key: VReg) {
return new TryLdGlobalByValue(key);
}
export function tryStoreGlobalByValue(prop: VReg): IRNode {
return new TryStGlobalByValue(prop);
}
export function loadGlobalVar(name: string) {
return new LdGlobalVar(name);
}
export function storeGlobalVar(name: string) {
return new StGlobalVar(name);
}
export function loadObjByName(obj: VReg, key: string) {
return new LdObjByName(key, obj);
}
export function storeObjByName(obj: VReg, key: string) {
return new StObjByName(key, obj);
}
export function loadObjByIndex(obj: VReg, index: VReg) {
return new LdObjByIndex(obj, index);
}
export function storeObjByIndex(obj: VReg, index: VReg) {
return new StObjByIndex(obj, index);
}
export function loadObjByValue(obj: VReg, prop: VReg): IRNode {
return new LdObjByValue(obj, prop);
}
export function storeObjByValue(obj: VReg, prop: VReg): IRNode {
return new StObjByValue(obj, prop);
}
export function storeOwnByName(obj: VReg, key: string): IRNode {
return new StOwnByName(key, obj);
}
export function storeOwnByIndex(obj: VReg, index: VReg) {
return new StOwnByIndex(obj, index);
}
export function storeOwnByValue(obj: VReg, value: VReg) {
return new StOwnByValue(obj, value);
}
export function throwIfSuperNotCorrectCall(num: number) {
return new ThrowIfSuperNotCorrectCall(new Imm(ResultType.Int, num));
}
export function call(args: VReg[], passThis: boolean) {
let length = args.length;
let insn: IRNode;
if (!passThis) {
switch (length) {
case 1:
insn = new Call0Dyn(args[0]);
break;
case 2:
insn = new Call1Dyn(args[0], args[1]);
break;
case 3:
insn = new Call2Dyn(args[0], args[1], args[2]);
break;
case 4:
insn = new Call3Dyn(args[0], args[1], args[2], args[3]);
break;
default:
insn = new CalliRangeDyn(new Imm(ResultType.Int, length - 1), args);
}
} else {
insn = new CalliThisRangeDyn(new Imm(ResultType.Int, length - 1), args);
}
return insn;
}
export function newObject(args: VReg[]) {
return new NewObjDynRange(new Imm(ResultType.Int, args.length), args);
}
export function getPropIterator() {
return new GetPropertiesIterator();
}
export function getNextPropName(iter: VReg) {
return new GetNextPropName(iter);
}
export function returnUndefined() {
return new ReturnUndefined();
}
export function createEmptyObject() {
return new CreateEmptyObject();
}
export function createObjectHavingMethod(idx: number) {
return new CreateObjectHavingMethod(new Imm(ResultType.Int, idx));
}
export function createObjectWithBuffer(idx: number) {
return new CreateObjectWithBuffer(new Imm(ResultType.Int, idx));
}
export function setObjectWithProto(proto: VReg, object: VReg) {
return new SetObjectWithProto(proto, object);
}
export function copyDataProperties(dstObj: VReg, srcObj: VReg) {
return new CopyDataProperties(dstObj, srcObj);
}
export function defineGetterSetterByValue(obj: VReg, name: VReg, getter: VReg, setter: VReg) {
return new DefineGetterSetterByValue(obj, name, getter, setter);
}
export function createEmptyArray() {
return new CreateEmptyArray();
}
export function createArrayWithBuffer(idx: number) {
return new CreateArrayWithBuffer(new Imm(ResultType.Int, idx));
}
export function storeArraySpread(array: VReg, index: VReg) {
return new StArraySpread(array, index);
}
export function defineClassWithBuffer(id: string, idx: number, env: VReg, base: VReg) {
return new DefineClassWithBuffer(id, new Imm(ResultType.Int, idx), env, base);
}
export function createObjectWithExcludedKeys(obj: VReg, args: VReg[]) {
return new CreateObjectWithExcludedKeys(new Imm(ResultType.Int, args.length - 1), obj, args);
}
export function throwObjectNonCoercible() {
return new ThrowPatternNonCoercible();
}
export function throwIfNotObject(v: VReg) {
return new ThrowIfNotObject(v);
}
export function getIterator() {
return new GetIterator();
}
export function getIteratorNext(iter: VReg, nextMethod: VReg) {
return new GetIteratorNext(iter, nextMethod);
}
export function closeIterator(iter: VReg) {
return new CloseIterator(iter);
}
export function superCall(num: number, start: VReg) {
return new SuperCall(new Imm(ResultType.Int, num), start);
}
export function superCallSpread(vs: VReg) {
return new SuperCallSpread(vs);
}
export function ldSuperByName(obj: VReg, key: string) {
return new LdSuperByName(key, obj);
}
export function stSuperByName(obj: VReg, key: string) {
return new StSuperByName(key, obj);
}
export function stSuperByValue(obj: VReg, prop: VReg) {
return new StSuperByValue(obj, prop);
}
export function ldSuperByValue(obj: VReg, prop: VReg): IRNode {
return new LdSuperByValue(obj, prop);
}
export function importModule(name: string) {
return new ImportModule(name);
}
export function loadModuleVarByName(name: string, module: VReg) {
return new LdModvarByName(name, module);
}
export function storeModuleVariable(name: string) {
return new StModuleVar(name);
}
export function copyModuleIntoCurrentModule(mod: VReg) {
return new CopyModule(mod);
}
export function loadHomeObject() {
return new LdHomeObject();
}
+165
View File
@@ -0,0 +1,165 @@
/*
* 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.
*/
import { PandaGen } from "src/pandagen";
import {
IRNode,
LdBigInt,
LdBoolean,
LdFalse,
LdFunction,
LdGlobal,
LdHole,
LdInfinity,
LdNaN,
LdNull,
LdNumber,
LdObject,
LdRegExp,
LdString,
LdSymbol,
LdTrue,
LdUndefined,
StaDyn
} from "../irnodes";
import { CacheList, getVregisterCache } from "./vregisterCache";
export function expandHole(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.HOLE);
return [
new LdHole(),
new StaDyn(vreg)
]
}
export function expandNaN(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.NaN);
return [
new LdNaN(),
new StaDyn(vreg)
];
}
export function expandInfinity(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Infinity);
return [
new LdInfinity(),
new StaDyn(vreg)
];
}
export function expandGlobal(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Global);
return [
new LdGlobal(),
new StaDyn(vreg)
];
}
export function expandUndefined(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.undefined);
return [
new LdUndefined(),
new StaDyn(vreg)
];
}
export function expandBoolean(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Boolean);
return [
new LdBoolean(),
new StaDyn(vreg)
];
}
export function expandNumber(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Number);
return [
new LdNumber(),
new StaDyn(vreg)
];
}
export function expandString(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.String);
return [
new LdString(),
new StaDyn(vreg)
];
}
export function expandBigInt(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.BigInt);
return [
new LdBigInt(),
new StaDyn(vreg)
];
}
export function expandSymbol(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Symbol);
return [
new LdSymbol(),
new StaDyn(vreg)
];
}
export function expandRegExp(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.RegExp);
return [
new LdRegExp(),
new StaDyn(vreg)
];
}
export function expandNull(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Null);
return [
new LdNull(),
new StaDyn(vreg)
];
}
export function expandObject(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Object);
return [
new LdObject(),
new StaDyn(vreg)
];
}
export function expandFunction(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.Function);
return [
new LdFunction(),
new StaDyn(vreg)
];
}
export function expandTrue(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.True);
return [
new LdTrue(),
new StaDyn(vreg)
];
}
export function expandFalse(pandaGen: PandaGen): IRNode[] {
let vreg = getVregisterCache(pandaGen, CacheList.False);
return [
new LdFalse(),
new StaDyn(vreg)
];
}
+82
View File
@@ -0,0 +1,82 @@
/*
* 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.
*/
import * as ts from "typescript";
import {
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
export class Iterator {
private iterRecord: { iterator: VReg, nextMethod: VReg };
private iterDone: VReg;
private iterValue: VReg;
private pandaGen: PandaGen;
private node: ts.Node;
constructor(iterRecord: {iterator: VReg, nextMethod: VReg}, iterDone: VReg, iterValue: VReg, pandaGen: PandaGen, node: ts.Node) {
this.iterRecord = iterRecord;
this.iterDone = iterDone;
this.iterValue = iterValue;
this.pandaGen = pandaGen;
this.node = node;
}
getIterator() {
let pandaGen = this.pandaGen;
let iterator = this.iterRecord.iterator;
// get iterator
pandaGen.getIterator(this.node);
pandaGen.storeAccumulator(this.node, iterator);
// get the next method
pandaGen.loadObjProperty(this.node, iterator, "next");
pandaGen.storeAccumulator(this.node, this.iterRecord.nextMethod);
}
/**
* iterResult = nextMethod.call(iterator);
* if (!isObject(iterResult)) {
* throw TypeError
* }
**/
callNext(iterResult: VReg) {
this.pandaGen.getIteratorNext(this.node, this.iterRecord.iterator, this.iterRecord.nextMethod);
this.pandaGen.storeAccumulator(this.node, iterResult);
}
iteratorComplete(iterResult: VReg) {
this.pandaGen.loadObjProperty(this.node, iterResult, "done");
this.pandaGen.storeAccumulator(this.node, this.iterDone);
}
iteratorValue(iterResult: VReg) {
this.pandaGen.loadObjProperty(this.node, iterResult, "value");
this.pandaGen.storeAccumulator(this.node, this.iterValue);
}
close() {
this.pandaGen.closeIterator(this.node, this.iterRecord.iterator);
}
getCurrentValue() {
return this.iterValue;
}
getCurrrentDone() {
return this.iterDone;
}
}
+65
View File
@@ -0,0 +1,65 @@
/*
* 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.
*/
import {
IRNode
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { VariableScope } from "../scope";
import {
loadLexicalEnv,
newLexicalEnv,
storeAccumulator
} from "./bcGenUtil";
import { CacheList, getVregisterCache } from "./vregisterCache";
function createLexEnv(pandaGen: PandaGen, scope: VariableScope): IRNode[] {
let lexEnvVars = scope.getNumLexEnv();
let insns: IRNode[] = [];
insns.push(
newLexicalEnv(lexEnvVars),
storeAccumulator(getVregisterCache(pandaGen, CacheList.LexEnv))
);
return insns;
}
function loadLexEnv(pandaGen: PandaGen): IRNode[] {
let insns: IRNode[] = [];
insns.push(
loadLexicalEnv(),
storeAccumulator(getVregisterCache(pandaGen, CacheList.LexEnv)),
);
return insns;
}
export function expandLexEnv(pandaGen: PandaGen): IRNode[] {
let scope = pandaGen.getScope()!.getNearestVariableScope();
let insns: IRNode[];
if (!scope) {
throw new Error("pandagen must have one variable scope");
}
if (scope.need2CreateLexEnv()) {
insns = createLexEnv(pandaGen, scope);
} else {
insns = loadLexEnv(pandaGen);
}
return insns;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* 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.
*/
export enum LiteralTag {
BOOLEAN = 1,
INTEGER = 2,
DOUBLE = 4,
STRING = 5,
METHOD = 6,
GENERATOR = 7,
ACCESSOR = 8,
NULLVALUE = 9
}
export class Literal {
private tag: LiteralTag;
private value: any;
constructor(tag: LiteralTag, value: any) {
this.tag = tag;
this.value = value;
}
getTag() {
return this.tag;
}
getValue() {
return this.value;
}
}
export class LiteralBuffer {
private literalBuffer: Literal[] = [];
constructor() { };
addLiterals(...literals: Array<Literal>) {
this.literalBuffer.push(...literals);
}
isEmpty() {
return this.literalBuffer.length == 0;
}
}
+176
View File
@@ -0,0 +1,176 @@
/*
* 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.
*/
import { PandaGen } from "src/pandagen";
import * as ts from "typescript";
import { Compiler } from "../compiler";
import { compileDestructuring } from "../compilerUtils";
import { DiagnosticCode, DiagnosticError } from "../diagnostic";
import { getObjAndProp } from "../expression/memberAccessExpression";
import { findInnerExprOfParenthesis } from "../expression/parenthesizedExpression";
import { VReg } from "../irnodes";
import * as jshelpers from "../jshelpers";
import { Scope } from "../scope";
import { VarDeclarationKind, Variable } from "../variable";
import { isBindingOrAssignmentPattern } from "./util";
enum ReferenceKind { MemberAccess, LocalOrGlobal, Destructuring };
export class LReference {
private node: ts.Node;
private compiler: Compiler;
private refKind: ReferenceKind;
private isDeclaration: boolean;
private obj: VReg | undefined = undefined;
private prop: VReg | undefined = undefined;
private propLiteral: string | number | undefined = undefined;
readonly variable: { scope: Scope | undefined, level: number, v: Variable | undefined } | undefined;
private destructuringTarget: ts.BindingOrAssignmentPattern | undefined;
constructor(
node: ts.Node,
compiler: Compiler,
isDeclaration: boolean,
refKind: ReferenceKind,
variable: { scope: Scope | undefined, level: number, v: Variable | undefined } | undefined) {
this.node = node;
this.compiler = compiler;
this.isDeclaration = isDeclaration;
this.refKind = refKind;
if (refKind == ReferenceKind.Destructuring) {
this.destructuringTarget = <ts.BindingOrAssignmentPattern>node;
} else if (refKind == ReferenceKind.LocalOrGlobal) {
this.variable = variable!;
} else if (refKind == ReferenceKind.MemberAccess) {
this.obj = compiler.getPandaGen().getTemp();
this.prop = compiler.getPandaGen().getTemp();
}
}
getValue() {
let pandaGen = this.compiler.getPandaGen();
switch (this.refKind) {
case ReferenceKind.MemberAccess:
let prop: VReg | number | string;
if (this.propLiteral === undefined) {
prop = <VReg>this.prop!;
} else {
prop = this.propLiteral;
}
pandaGen.loadObjProperty(this.node, <VReg>this.obj, prop);
return;
case ReferenceKind.LocalOrGlobal:
this.compiler.loadTarget(this.node, this.variable!);
return;
case ReferenceKind.Destructuring:
throw new Error("Destructuring target can't be loaded");
default:
throw new Error("Invalid LReference kind to GetValue")
}
}
setValue() {
let pandaGen = this.compiler.getPandaGen();
switch (this.refKind) {
case ReferenceKind.MemberAccess: {
let prop: VReg | number | string
if (this.propLiteral === undefined) {
prop = <VReg>this.prop!;
} else {
prop = this.propLiteral;
}
if (jshelpers.isSuperProperty(<ts.ElementAccessExpression | ts.PropertyAccessExpression>this.node)) {
let thisReg = pandaGen.getTemp();
this.compiler.getThis(this.node, thisReg);
pandaGen.storeSuperProperty(this.node, thisReg, prop);
pandaGen.freeTemps(thisReg);
} else {
pandaGen.storeObjProperty(this.node, <VReg>this.obj, prop);
}
pandaGen.freeTemps(...[<VReg>this.obj, <VReg>this.prop]);
return;
}
case ReferenceKind.LocalOrGlobal:
this.compiler.storeTarget(this.node, this.variable!, this.isDeclaration);
return;
case ReferenceKind.Destructuring:
compileDestructuring(<ts.BindingOrAssignmentPattern>this.destructuringTarget, pandaGen, this.compiler);
return;
default:
throw new Error("Invalid LReference kind to SetValue")
}
}
setObjectAndProperty(pandaGen: PandaGen, obj: VReg, prop: VReg | number | string) {
if (!jshelpers.isSuperProperty(this.node)) {
pandaGen.moveVreg(this.node, <VReg>this.obj, obj);
}
if (prop instanceof VReg) {
pandaGen.moveVreg(this.node, <VReg>this.prop, prop);
return;
}
this.propLiteral = <string | number>prop;
}
static generateLReference(compiler: Compiler, node: ts.Node, isDeclaration: boolean): LReference {
let pandaGen = compiler.getPandaGen();
let realNode: ts.Node = node;
if (ts.isParenthesizedExpression(node)) {
realNode = findInnerExprOfParenthesis(node);
}
if (ts.isIdentifier(realNode)) {
let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>realNode);
let variable = compiler.getCurrentScope().find(name);
if (!variable.v) {
variable.v = compiler.getCurrentScope().add(name, VarDeclarationKind.NONE);
}
return new LReference(realNode, compiler, isDeclaration, ReferenceKind.LocalOrGlobal, variable);
}
if (ts.isPropertyAccessExpression(realNode) || ts.isElementAccessExpression(realNode)) {
let lref = new LReference(realNode, compiler, false, ReferenceKind.MemberAccess, undefined);
let objReg = pandaGen.getTemp();
let propReg = pandaGen.getTemp();
let { obj: object, prop: property } = getObjAndProp(realNode, objReg, propReg, compiler);
lref.setObjectAndProperty(pandaGen, object, property);
pandaGen.freeTemps(objReg, propReg);
return lref;
}
if (ts.isVariableDeclarationList(realNode)) {
let decls = realNode.declarations;
if (decls.length != 1) {
throw new Error("Malformed variable declaration");
}
return LReference.generateLReference(compiler, decls[0].name, true);
}
if (isBindingOrAssignmentPattern(realNode)) {
return new LReference(realNode, compiler, isDeclaration, ReferenceKind.Destructuring, undefined);
}
throw new DiagnosticError(
node,
DiagnosticCode.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access
);
}
}
+275
View File
@@ -0,0 +1,275 @@
/*
* 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.
*/
import * as ts from "typescript";
import { isValidIndex } from "../expression/memberAccessExpression";
import * as jshelpers from "../jshelpers";
export enum PropertyKind {
Variable,
Constant,
Computed, // Property with computed value (execution time).
Prototype,
Accessor,
Spread
}
export class Property {
private propKind: PropertyKind;
private valueNode: ts.Node | undefined;
private setterNode: ts.SetAccessorDeclaration | undefined;
private getterNode: ts.GetAccessorDeclaration | undefined;
private compiled: boolean = false;
private redeclared: boolean = false;
private name: string | number | ts.ComputedPropertyName | undefined;
constructor(propKind: PropertyKind, name: string | number | ts.ComputedPropertyName | undefined) {
this.propKind = propKind;
if (typeof (name) != 'undefined') {
this.name = name;
}
}
setCompiled() {
this.compiled = true;
}
setRedeclared() {
this.redeclared = true;
}
isCompiled() {
return this.compiled;
}
isRedeclared() {
return this.redeclared;
}
getName() {
if (typeof (this.name) == 'undefined') {
throw new Error("this property doesn't have a name");
}
return this.name;
}
getKind() {
return this.propKind;
}
getValue() {
if (this.propKind == PropertyKind.Accessor) {
throw new Error("Accessor doesn't have valueNode")
}
return this.valueNode!;
}
getGetter() {
return this.getterNode;
}
getSetter() {
return this.setterNode;
}
setValue(valueNode: ts.Node) {
this.valueNode = valueNode;
this.getterNode = undefined;
this.setterNode = undefined;
}
setGetter(getter: ts.GetAccessorDeclaration) {
if (this.propKind != PropertyKind.Accessor) {
this.valueNode = undefined;
this.setterNode = undefined;
this.propKind = PropertyKind.Accessor;
}
this.getterNode = getter;
}
setSetter(setter: ts.SetAccessorDeclaration) {
if (this.propKind != PropertyKind.Accessor) {
this.valueNode = undefined;
this.getterNode = undefined;
this.propKind = PropertyKind.Accessor;
}
this.setterNode = setter;
}
setKind(propKind: PropertyKind) {
this.propKind = propKind;
}
}
export function generatePropertyFromExpr(expr: ts.ObjectLiteralExpression): Property[] {
let hasProto: boolean = false;
let properties: Property[] = [];
let namedPropertyMap: Map<string, number> = new Map<string, number>();
expr.properties.forEach(property => {
switch (property.kind) {
case ts.SyntaxKind.PropertyAssignment: {
if (property.name.kind == ts.SyntaxKind.ComputedPropertyName) {
defineProperty(property.name, property, PropertyKind.Computed, properties, namedPropertyMap);
break;
}
let propName: number | string = <number | string>getPropName(property.name);
if (propName == "__proto__") {
if (!hasProto) {
defineProperty(propName, property.initializer, PropertyKind.Prototype, properties, namedPropertyMap);
hasProto = true;
break;
} else {
throw new Error("__proto__ was set multiple times in the object definition.");
}
}
if (isConstantExpr(property.initializer)) {
defineProperty(propName, property.initializer, PropertyKind.Constant, properties, namedPropertyMap);
} else {
defineProperty(propName, property.initializer, PropertyKind.Variable, properties, namedPropertyMap);
}
break;
}
case ts.SyntaxKind.ShorthandPropertyAssignment: {
// ShorthandProperty's name always be Identifier
let propName = jshelpers.getTextOfIdentifierOrLiteral(property.name);
defineProperty(propName, property.name, PropertyKind.Variable, properties, namedPropertyMap);
break;
}
case ts.SyntaxKind.SpreadAssignment: {
defineProperty(undefined, property.expression, PropertyKind.Spread, properties, namedPropertyMap);
break;
}
case ts.SyntaxKind.MethodDeclaration: {
let propName = getPropName(property.name);
if (typeof (propName) == 'string' || typeof (propName) == 'number') {
defineProperty(propName, property, PropertyKind.Variable, properties, namedPropertyMap);
} else {
defineProperty(propName, property, PropertyKind.Computed, properties, namedPropertyMap);
}
break;
}
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor: {
let propName = getPropName(property.name);
if (typeof (propName) == 'string' || typeof (propName) == 'number') {
defineProperty(propName, property, PropertyKind.Accessor, properties, namedPropertyMap);
} else {
defineProperty(propName, property, PropertyKind.Computed, properties, namedPropertyMap);
}
break;
}
default:
throw new Error("Unreachable Kind");
}
});
return properties;
}
function defineProperty(
propName: string | number | ts.ComputedPropertyName | undefined,
propValue: ts.Node,
propKind: PropertyKind,
properties: Property[],
namedPropertyMap: Map<string, number>) {
if (propKind == PropertyKind.Computed || propKind == PropertyKind.Spread) {
let prop = new Property(propKind, <ts.ComputedPropertyName | undefined>propName);
prop.setValue(propValue);
properties.push(prop);
} else {
let prop = new Property(propKind, propName);
let name_str = propertyKeyAsString(<string | number>propName);
if (namedPropertyMap.has(name_str)) {
let prevProp = properties[namedPropertyMap.get(name_str)!];
if ((prevProp.getKind() == PropertyKind.Accessor || prevProp.getKind() == PropertyKind.Constant)
&& (propKind == PropertyKind.Accessor || propKind == PropertyKind.Constant)) {
if (propKind == PropertyKind.Accessor) {
if (ts.isGetAccessorDeclaration(propValue)) {
prevProp!.setGetter(propValue);
} else if (ts.isSetAccessorDeclaration(propValue)) {
prevProp!.setSetter(propValue);
}
} else {
prevProp!.setValue(propValue);
prevProp!.setKind(PropertyKind.Constant);
}
return;
}
prop.setRedeclared();
}
namedPropertyMap.set(name_str, properties.length);
if (propKind == PropertyKind.Accessor) {
if (ts.isGetAccessorDeclaration(propValue)) {
prop.setGetter(propValue);
} else if (ts.isSetAccessorDeclaration(propValue)) {
prop.setSetter(propValue);
}
} else {
prop.setValue(propValue);
}
properties.push(prop);
}
}
export function isConstantExpr(node: ts.Node): boolean {
switch (node.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NumericLiteral:
case ts.SyntaxKind.NullKeyword:
case ts.SyntaxKind.TrueKeyword:
case ts.SyntaxKind.FalseKeyword:
return true;
default:
return false;
}
}
export function propertyKeyAsString(propName: string | number) {
if (typeof (propName) == 'number') {
return propName.toString();
}
return propName;
}
export function getPropName(propertyName: ts.PropertyName) {
if (ts.isComputedPropertyName(propertyName)) {
return propertyName;
}
let propName: number | string = jshelpers.getTextOfIdentifierOrLiteral(propertyName);
if (propertyName.kind == ts.SyntaxKind.NumericLiteral) {
propName = Number.parseFloat(propName);
if (!isValidIndex(propName)) {
propName = propName.toString();
}
} else if (propertyName.kind == ts.SyntaxKind.StringLiteral) {
let temp = Number(propName);
if (!isNaN(Number.parseFloat(propName)) && !isNaN(temp) && isValidIndex(temp) && String(temp) == propName) {
propName = temp;
}
}
return propName;
}
+216
View File
@@ -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.
*/
import path = require("path");
import { LocalVariable, Variable } from "src/variable";
import * as ts from "typescript";
import * as jshelpers from "../jshelpers";
import { LOGD, LOGE } from "../log";
import { ModuleScope, Scope } from "../scope";
import { isFunctionLikeDeclaration } from "../syntaxCheckHelper";
export function containSpreadElement(args?: ts.NodeArray<ts.Expression>): boolean {
if (!args) {
return false;
}
for (let i = 0; i < args.length; i++) {
if (args[i].kind === ts.SyntaxKind.SpreadElement) {
return true;
}
}
return false;
}
export function hasExportKeywordModifier(node: ts.Node): boolean {
let hasExport: boolean = false;
if (node.modifiers) {
node.modifiers.forEach((mod) => {
if (mod.kind == ts.SyntaxKind.ExportKeyword) {
hasExport = true;
}
});
}
return hasExport;
}
export function hasDefaultKeywordModifier(node: ts.Node): boolean {
let hasDefault: boolean = false;
if (node.modifiers) {
node.modifiers.forEach((mod) => {
if (mod.kind == ts.SyntaxKind.DefaultKeyword) {
hasDefault = true;
}
});
}
return hasDefault;
}
export function setVariableExported(varName: string, scope: Scope) {
if (!(scope instanceof ModuleScope)) {
throw new Error("variable can't be exported out of module scope");
}
let variable: { scope: Scope | undefined, level: number, v: Variable | undefined } = scope.find(varName);
(<LocalVariable>variable.v!).setExport();
(<LocalVariable>variable.v!).setExportedName(varName);
}
export function execute(cmd: string, args: Array<string>) {
var spawn = require('child_process').spawn;
let child = spawn(cmd, [...args], {
stdio: ['pipe', 'inherit', 'inherit']
});
child.on('exit', (code: any) => {
if (code === 1) {
LOGD("fail to execute cmd: ", cmd);
return 0;
}
LOGD("execute cmd successfully: ", cmd);
return 1;
});
return 1;
}
export function addUnicodeEscape(text: string) {
let firstIdx = 0;
let secondIdx = 0;
let len = text.length;
let newText = "";
while (secondIdx != len) {
if (text[secondIdx] == '\\' && secondIdx + 1 != len && text[secondIdx + 1] == 'u') {
if (secondIdx != 0 && text[secondIdx - 1] == '\\') {
newText += text.substr(firstIdx, secondIdx - firstIdx) + "\\\\" + "\\u";
} else {
newText += text.substr(firstIdx, secondIdx - firstIdx) + "\\" + "\\u";
}
secondIdx += 2;
firstIdx = secondIdx;
} else {
secondIdx++;
}
}
if (secondIdx == len && firstIdx != secondIdx) {
newText += text.substr(firstIdx);
}
return newText;
}
export function isBindingPattern(node: ts.Node) {
return ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node);
}
export function isObjectBindingOrAssignmentPattern(node: ts.Node) {
return ts.isObjectLiteralExpression(node) || ts.isObjectBindingPattern(node);
}
export function isArrayBindingOrAssignmentPattern(node: ts.Node) {
return ts.isArrayLiteralExpression(node) || ts.isArrayBindingPattern(node);
}
export function isBindingOrAssignmentPattern(node: ts.Node) {
return isArrayBindingOrAssignmentPattern(node) || isObjectBindingOrAssignmentPattern(node);
}
export function isMemberExpression(node: ts.Node) {
if (ts.isPropertyAccessExpression(node)
|| ts.isElementAccessExpression(node)) {
return true;
}
return false;
}
export function isUndefinedIdentifier(node: ts.Node) {
if (!ts.isIdentifier(node)) {
return false;
}
if (jshelpers.getTextOfIdentifierOrLiteral(node) != "undefined") {
return false;
}
return true;
}
export function isAnonymousFunctionDefinition(node: ts.Node) {
if (!isFunctionLikeDeclaration(node)) {
return false;
}
if (node.name) {
return false;
} else {
return true;
}
}
export function escapeUnicode(data: string) {
let char = '\n';
let i = 0;
let j = 0;
let new_data = ""
while ((j = data.indexOf(char, i)) !== -1) {
let tmp = data.substring(i, j);
if (tmp.indexOf("\\u") != -1) {
tmp = addUnicodeEscape(tmp);
}
new_data = new_data.concat(tmp, "\n");
i = j + 1;
}
new_data = new_data.concat("}\n");
return new_data
}
export function initiateTs2abc(args: Array<string>) {
let js2abc = path.join(path.resolve(__dirname, '../../bin'), "js2abc");
args.unshift("--compile-by-pipe");
var spawn = require('child_process').spawn;
let child = spawn(js2abc, [...args], {
stdio: ['pipe', 'inherit', 'inherit', 'pipe']
});
return child;
}
export function terminateWritePipe(ts2abc: any) {
if (!ts2abc) {
LOGD("ts2abc is not a valid object");
}
ts2abc.stdio[3].end();
}
export function listenChildExit(child: any) {
if (!child) {
LOGD("child is not a valid object");
}
child.on('exit', (code: any) => {
if (code === 1) {
LOGD("fail to generate panda binary file");
}
LOGD("success to generate panda binary file");
});
}
+128
View File
@@ -0,0 +1,128 @@
/*
* 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.
*/
import {
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
import {
expandBigInt,
expandBoolean,
expandFalse,
expandFunction,
expandGlobal,
expandHole,
expandInfinity,
expandNaN,
expandNull,
expandNumber,
expandObject,
expandRegExp,
expandString,
expandSymbol,
expandTrue,
expandUndefined
} from "./builtIn";
import { expandLexEnv } from "./lexEnv";
export enum CacheList {
MIN,
NaN = MIN,
HOLE,
Infinity,
undefined,
Boolean,
Number,
String,
BigInt,
Symbol,
RegExp,
Null,
Object,
Function,
Global,
LexEnv, // Lex Env must come before True and False, because LexEnv depends on True and False
True,
False,
MAX,
}
let cacheExpandHandlers = new Map([
[CacheList.HOLE, expandHole],
[CacheList.NaN, expandNaN],
[CacheList.Infinity, expandInfinity],
[CacheList.undefined, expandUndefined],
[CacheList.Boolean, expandBoolean],
[CacheList.Number, expandNumber],
[CacheList.String, expandString],
[CacheList.BigInt, expandBigInt],
[CacheList.Symbol, expandSymbol],
[CacheList.RegExp, expandRegExp],
[CacheList.Null, expandNull],
[CacheList.Object, expandObject],
[CacheList.Function, expandFunction],
[CacheList.Global, expandGlobal],
[CacheList.LexEnv, expandLexEnv],
[CacheList.True, expandTrue],
[CacheList.False, expandFalse],
]);
class CacheItem {
constructor(handler: Function) {
this.flag = false;
this.vreg = undefined;
this.expander = handler;
}
private flag: boolean;
private vreg: VReg | undefined;
private expander: Function;
isNeeded() {
return this.flag;
}
getCache(): VReg {
if (!this.flag || !this.vreg) {
this.flag = true;
this.vreg = new VReg();
}
return this.vreg;
}
getExpander() {
return this.expander;
}
}
export class VregisterCache {
private cache: CacheItem[] = [];
constructor() {
for (let i = CacheList.MIN; i < CacheList.MAX; ++i) {
let handler = cacheExpandHandlers.get(i);
if (!handler) {
throw new Error("invalid expand handler");
}
this.cache[i] = new CacheItem(handler);
}
}
getCache(index: CacheList) {
if (index < CacheList.MIN || index > CacheList.MAX) {
throw new Error("invalid builtin index");
}
return this.cache[index];
}
}
export function getVregisterCache(pandaGen: PandaGen, index: CacheList) {
let cache = pandaGen.getVregisterCache();
let cacheItem = cache.getCache(index);
return cacheItem.getCache();
}
+189
View File
@@ -0,0 +1,189 @@
/*
* 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.
*/
// singleton to parse commandLine infos
import commandLineArgs from "command-line-args";
import commandLineUsage from "command-line-usage";
import * as ts from "typescript";
import { LOGE } from "./log";
import path = require("path");
import { execute } from "./base/util";
const ts2pandaOptions = [
{ name: 'variant-bytecode', alias: 'r', type: Boolean, defaultValue: true, description: "emit 2nd bytecode to pandafile."},
{ name: 'modules', alias: 'm', type: Boolean, defaultValue: false, description: "compile as module."},
{ name: 'debug-log', alias: 'l', type: Boolean, defaultValue: false, description: "show info debug log."},
{ name: 'dump-assembly', alias: 'a', type: Boolean, defaultValue: false, description: "dump assembly to file."},
{ name: 'debug', alias: 'd', type: Boolean, defaultValue: false, description: "compile with debug info."},
{ name: 'show-statistics', alias: 's', type: String, lazyMultiple: true, defaultValue: "", description: "show compile statistics(ast, histogram, hoisting, all)."},
{ name: 'output', alias: 'o', type: String, defaultValue: "", description: "set output file."},
{ name: 'timeout', alias: 't', type: Number, defaultValue: 0, description: "js to abc timeout threshold(unit: seconds)."},
{ name: 'opt-log-level', type: String, defaultValue: "error", description: "specifie optimizer log level. Possible values: ['debug', 'info', 'error', 'fatal']"},
{ name: 'opt-level', type: Number, defaultValue: 1, description: "Optimization level. Possible values: [0, 1, 2]. Default: 0\n 0: no optimizations\n \
1: basic bytecode optimizations, including valueNumber, lowering, constantResolver, regAccAllocator\n \
2: other bytecode optimizations, unimplemented yet"},
{ name: 'help', alias: 'h', type: Boolean, description: "Show usage guide."},
{ name: 'bc-version', alias: 'v', type: Boolean, defaultValue: false, description: "Print ark bytecode version"},
{ name: 'bc-min-version', type: Boolean, defaultValue: false, description: "Print ark bytecode minimum supported version"}
]
export class CmdOptions {
private static parsedResult: ts.ParsedCommandLine;
private static options: commandLineArgs.CommandLineOptions;
static isEnableDebugLog(): boolean {
if (!this.options) {
return false;
}
return this.options["debug-log"];
}
static isAssemblyMode(): boolean {
if (!this.options) {
return false;
}
return this.options["dump-assembly"];
}
static isDebugMode(): boolean {
if (!this.options) {
return false;
}
return this.options["debug"];
}
static isModules(): boolean {
if (!this.options) {
return false;
}
return this.options["modules"];
}
static isVariantBytecode(): boolean {
if (!this.options) {
return true;
}
return this.options["variant-bytecode"];
}
static getOptLevel(): number {
return this.options["opt-level"];
}
static getOptLogLevel(): string {
return this.options["opt-log-level"];
}
static showASTStatistics(): boolean {
if (!this.options) {
return false;
}
return this.options["show-statistics"].includes("ast") || this.options["show-statistics"].includes("all");
}
static showHistogramStatistics(): boolean {
if (!this.options) {
return false;
}
return this.options["show-statistics"].includes("all") || this.options["show-statistics"].includes("histogram");
}
static showHoistingStatistics(): boolean {
if (!this.options) {
return false;
}
return this.options["show-statistics"].includes("all") || this.options["show-statistics"].includes("hoisting");
}
static getInputFileName(): string {
let path = this.parsedResult.fileNames[0];
let inputFile = path.substring(0, path.lastIndexOf('.'));
return inputFile;
}
static getOutputBinName(): string {
let outputFile = this.options.output;
if (outputFile == "") {
outputFile = CmdOptions.getInputFileName() + ".abc";
}
return outputFile;
}
static getTimeOut(): Number {
if (!this.options) {
return 0;
}
return this.options["timeout"];
}
static showHelp(): void {
const usage = commandLineUsage([
{
header: "Ark JavaScript Compiler",
content: 'node --expose-gc index.js [options] file.js'
},
{
header: 'Options',
optionList: ts2pandaOptions
},
{
content: 'Project Ark'
}
])
LOGE(usage);
}
static isBcVersion(): boolean {
if (!this.options) {
return false;
}
return this.options["bc-version"];
}
static getVersion(isBcVersion : boolean = true) : void {
let js2abc = path.join(path.resolve(__dirname, '../bin'), "js2abc");
let version_arg = isBcVersion ? "--bc-version" : "--bc-min-version"
execute(`${js2abc}`, [version_arg]);
}
static isBcMinVersion(): boolean {
if (!this.options) {
return false;
}
return this.options["bc-min-version"];
}
static parseUserCmd(args: string[]): ts.ParsedCommandLine | undefined {
this.options = commandLineArgs(ts2pandaOptions, { partial: true });
if (this.options.help) {
this.showHelp();
return undefined;
}
if (this.isBcVersion() || this.isBcMinVersion()) {
this.getVersion(this.isBcVersion());
return undefined;
}
if (!this.options._unknown) {
LOGE("options at least one file is needed");
this.showHelp();
return undefined;
}
this.parsedResult = ts.parseCommandLine(this.options._unknown!);
return this.parsedResult;
}
}
File diff suppressed because it is too large Load Diff
+381
View File
@@ -0,0 +1,381 @@
/*
* 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.
*/
import * as ts from "typescript";
import { writeFileSync } from "fs";
import { addVariableToScope } from "./addVariable2Scope";
import { AssemblyDumper } from "./assemblyDumper";
import { isAnonymousFunctionDefinition, initiateTs2abc, terminateWritePipe, listenChildExit } from "./base/util";
import { CmdOptions } from "./cmdOptions";
import {
Compiler
} from "./compiler";
import { CompilerStatistics } from "./compilerStatistics";
import { DebugInfo } from "./debuginfo";
import { hoisting } from "./hoisting";
import { IntrinsicExpander } from "./intrinsicExpander";
import * as jshelpers from "./jshelpers";
import { LOGD } from "./log";
import { setExportBinding, setImport } from "./modules";
import { PandaGen } from "./pandagen";
import { Pass } from "./pass";
import { CacheExpander } from "./pass/cacheExpander";
import { Recorder } from "./recorder";
import { RegAlloc } from "./regAllocator";
import {
GlobalScope,
ModuleScope,
Scope,
VariableScope
} from "./scope";
import { checkDuplicateDeclaration, checkExportEntries } from "./syntaxChecker";
import { Ts2Panda } from "./ts2panda";
import { findOuterNodeOfParenthesis } from "./expression/parenthesizedExpression";
import { getClassNameForConstructor } from "./statement/classStatement";
export class PendingCompilationUnit {
constructor(
readonly decl: ts.FunctionLikeDeclaration,
readonly scope: Scope,
readonly internalName: string
) { }
}
/**
* The class which drives the compilation process.
* It handles all dependencies and run passes.
*/
export class CompilerDriver {
private fileName: string;
private passes: Pass[];
private compilationUnits: PandaGen[];
pendingCompilationUnits: PendingCompilationUnit[];
private functionId: number = 1; // 0 reserved for main
private funcIdMap: Map<ts.Node, number> = new Map<ts.Node, number>();
private statistics: CompilerStatistics;
private needDumpHeader: boolean = true;
private ts2abcProcess: any = undefined;
constructor(fileName: string) {
this.fileName = fileName;
// register passes here
this.passes = [
new CacheExpander(),
new IntrinsicExpander(),
new RegAlloc()
];
this.compilationUnits = [];
this.pendingCompilationUnits = [];
this.statistics = new CompilerStatistics();
}
initiateTs2abcChildProcess() {
this.ts2abcProcess = initiateTs2abc([this.fileName]);
}
getTs2abcProcess(): any {
if (this.ts2abcProcess === undefined) {
throw new Error("ts2abc hasn't been initiated")
}
return this.ts2abcProcess;
}
getStatistics() {
return this.statistics;
}
setCustomPasses(passes: Pass[]) {
this.passes = passes;
}
addCompilationUnit(decl: ts.FunctionLikeDeclaration, scope: Scope): string {
let internalName = this.getFuncInternalName(decl);
this.pendingCompilationUnits.push(
new PendingCompilationUnit(decl, scope, internalName)
);
return internalName;
}
getCompilationUnits() {
return this.compilationUnits;
}
kind2String(kind: ts.SyntaxKind) {
return ts.SyntaxKind[kind];
}
getASTStatistics(node: ts.Node, statics: number[]) {
node.forEachChild(childNode => {
statics[<number>childNode.kind] = statics[<number>childNode.kind] + 1;
this.getASTStatistics(childNode, statics);
})
}
// sort all function by post order
postOrderAnalysis(scope: GlobalScope): VariableScope[] {
let spArray: VariableScope[] = [];
let stack: VariableScope[] = [];
stack.push(scope);
while (stack.length > 0) {
let temp: VariableScope | undefined = stack.pop();
if (temp == undefined) {
break;
}
spArray.push(temp);
for (let childVariableScope of temp.getChildVariableScope()) {
stack.push(childVariableScope);
}
}
return spArray.reverse();
}
compile(node: ts.SourceFile): void {
if (CmdOptions.showASTStatistics()) {
let statics: number[] = new Array(ts.SyntaxKind.Count).fill(0);
this.getASTStatistics(node, statics);
statics.forEach((element, idx) => {
if (element > 0) {
LOGD(this.kind2String(idx) + " = " + element);
}
});
}
let recorder = this.compilePrologue(node);
// initiate ts2abc
if (!CmdOptions.isAssemblyMode()) {
this.initiateTs2abcChildProcess();
let ts2abcProc = this.getTs2abcProcess();
try {
Ts2Panda.dumpCmdOptions(ts2abcProc);
for (let i = 0; i < this.pendingCompilationUnits.length; i++) {
let unit: PendingCompilationUnit = this.pendingCompilationUnits[i];
this.compileImpl(unit.decl, unit.scope, unit.internalName, recorder);
}
Ts2Panda.dumpStringsArray(ts2abcProc);
Ts2Panda.dumpConstantPool(ts2abcProc);
terminateWritePipe(ts2abcProc);
if (CmdOptions.isEnableDebugLog()) {
let jsonFileName = this.fileName.substring(0, this.fileName.lastIndexOf(".")).concat(".json");
writeFileSync(jsonFileName, Ts2Panda.jsonString);
LOGD("Successfully generate ", `${jsonFileName}`);
}
Ts2Panda.clearDumpData();
} catch (err) {
terminateWritePipe(ts2abcProc);
ts2abcProc.kill();
throw err;
}
listenChildExit(ts2abcProc);
} else {
for (let i = 0; i < this.pendingCompilationUnits.length; i++) {
let unit: PendingCompilationUnit = this.pendingCompilationUnits[i];
this.compileImpl(unit.decl, unit.scope, unit.internalName, recorder);
}
}
PandaGen.clearLiteralArrayBuffer();
}
private compileImpl(node: ts.SourceFile | ts.FunctionLikeDeclaration, scope: Scope,
internalName: string, recorder: Recorder): void {
let pandaGen = new PandaGen(internalName, this.getParametersCount(node), scope);
// for debug info
DebugInfo.addDebugIns(scope, pandaGen, true);
let compiler = new Compiler(node, pandaGen, this, recorder);
if (CmdOptions.isModules() && ts.isSourceFile(node) && scope instanceof ModuleScope) {
setImport(recorder.getImportStmts(), scope, pandaGen, compiler);
setExportBinding(recorder.getExportStmts(), scope, pandaGen);
}
// because of para vreg, don't change hosting's position
hoisting(node, pandaGen, recorder, compiler);
compiler.compile();
this.passes.forEach((pass) => pass.run(pandaGen));
// for debug info
DebugInfo.addDebugIns(scope, pandaGen, false);
DebugInfo.setDebugInfo(pandaGen);
DebugInfo.setSourceFileDebugInfo(pandaGen, node);
if (CmdOptions.isAssemblyMode()) {
this.writeBinaryFile(pandaGen);
} else {
Ts2Panda.dumpPandaGen(pandaGen, this.getTs2abcProcess());
}
if (CmdOptions.showHistogramStatistics()) {
this.statistics.getInsHistogramStatistics(pandaGen);
}
}
compileUnitTest(node: ts.SourceFile): void {
let recorder = this.compilePrologue(node);
for (let i = 0; i < this.pendingCompilationUnits.length; i++) {
let unit: PendingCompilationUnit = this.pendingCompilationUnits[i];
this.compileUnitTestImpl(unit.decl, unit.scope, unit.internalName, recorder);
}
PandaGen.clearLiteralArrayBuffer();
}
private compileUnitTestImpl(node: ts.SourceFile | ts.FunctionLikeDeclaration, scope: Scope,
internalName: string, recorder: Recorder) {
let pandaGen = new PandaGen(internalName, this.getParametersCount(node), scope);
let compiler = new Compiler(node, pandaGen, this, recorder);
if (CmdOptions.isModules() && ts.isSourceFile(node) && scope instanceof ModuleScope) {
setImport(recorder.getImportStmts(), scope, pandaGen, compiler);
setExportBinding(recorder.getExportStmts(), scope, pandaGen);
}
hoisting(node, pandaGen, recorder, compiler);
compiler.compile();
this.passes.forEach((pass) => pass.run(pandaGen));
this.compilationUnits.push(pandaGen);
}
private compilePrologue(node: ts.SourceFile) {
let topLevelScope: GlobalScope | ModuleScope;
if (CmdOptions.isModules()) {
topLevelScope = new ModuleScope(node);
} else {
topLevelScope = new GlobalScope(node);
}
let recorder = new Recorder(node, topLevelScope, this);
recorder.record();
checkDuplicateDeclaration(recorder);
checkExportEntries(recorder);
addVariableToScope(recorder);
let postOrderVariableScopes = this.postOrderAnalysis(topLevelScope);
for (let variableScope of postOrderVariableScopes) {
this.addCompilationUnit(<ts.FunctionLikeDeclaration>variableScope.getBindingNode(), variableScope);
}
return recorder;
}
showStatistics(): void {
if (CmdOptions.showHistogramStatistics()) {
this.statistics.printHistogram(false);
}
if (CmdOptions.showHoistingStatistics()) {
this.statistics.printHoistStatistics();
}
}
getFuncId(node: ts.SourceFile | ts.FunctionLikeDeclaration | ts.ClassLikeDeclaration): number {
if (this.funcIdMap.has(node)) {
return this.funcIdMap.get(node)!;
}
if (ts.isSourceFile(node)) {
this.funcIdMap.set(node, 0);
return 0;
}
let idx = this.functionId++;
this.funcIdMap.set(node, idx);
return idx;
}
/**
* Internal name is used to indentify a function in panda file
* Runtime uses this name to bind code and a Function object
*/
getFuncInternalName(node: ts.SourceFile | ts.FunctionLikeDeclaration): string {
let name: string = '';
if (ts.isSourceFile(node)) {
name = "main";
} else if (ts.isConstructorDeclaration(node)) {
let classNode = node.parent;
return this.getInternalNameForCtor(classNode);
} else {
let funcNode = <ts.FunctionLikeDeclaration>node;
if (isAnonymousFunctionDefinition(funcNode)) {
let outerNode = findOuterNodeOfParenthesis(funcNode);
if (ts.isVariableDeclaration(outerNode)) {
let id = outerNode.name;
if (ts.isIdentifier(id)) {
name = jshelpers.getTextOfIdentifierOrLiteral(id);
}
} else if (ts.isBinaryExpression(outerNode)) {
if (outerNode.operatorToken.kind == ts.SyntaxKind.EqualsToken && ts.isIdentifier(outerNode.left)) {
name = jshelpers.getTextOfIdentifierOrLiteral(outerNode.left);
}
}
} else {
if (ts.isIdentifier(funcNode.name!)) {
name = jshelpers.getTextOfIdentifierOrLiteral(funcNode.name);
}
}
}
let internalName = "func_";
if (name == '') {
internalName += this.getFuncId(node);
} else {
internalName += name + '_' + this.getFuncId(node);
}
return internalName;
}
getInternalNameForCtor(node: ts.ClassLikeDeclaration) {
let name = getClassNameForConstructor(node);
return "func_" + name + "_" + this.getFuncId(node);
}
writeBinaryFile(pandaGen: PandaGen) {
if (this.needDumpHeader) {
AssemblyDumper.dumpHeader();
this.needDumpHeader = false;
}
new AssemblyDumper(pandaGen).dump();
}
private getParametersCount(node: ts.SourceFile | ts.FunctionLikeDeclaration): number {
// each function and global scope accepts three parameters - funcObj + newTarget + this.
// the runtime passes these to global scope when calls it
let parametersCount = 3;
if (node.kind == ts.SyntaxKind.SourceFile) {
return parametersCount;
}
let decl = <ts.FunctionLikeDeclaration>node;
parametersCount += decl.parameters.length;
return parametersCount;
}
}
+286
View File
@@ -0,0 +1,286 @@
/*
* 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.
*/
import { builtinsCodeMap } from "./builtinsMap";
import { CmdOptions } from "./cmdOptions";
import { getInstructionSize, Imm, IRNode, IRNodeKind } from "./irnodes";
import { LOGD } from "./log";
import { PandaGen } from "./pandagen";
export enum HoistingType {
GLOBAL_VAR = 0,
LOCAL_VAR,
GLOBAL_FUNCTION,
LOCAL_FUNCTION
}
class ItemValue {
private count: number = 1;
private instSize: number;
private relatedInsns: { name: string, num: number }[] = [];
private nodeMap: Map<string, number> = new Map<string, number>();
constructor(instSize: number, relatedInsns?: { name: string, num: number }) {
this.instSize = instSize;
if (relatedInsns) {
this.relatedInsns.push(relatedInsns);
}
}
add(num: number) {
this.count += num;
this.relatedInsns.forEach(relatedInsn => { relatedInsn.num += num });
}
set(num: number) {
this.count = num;
this.relatedInsns.forEach(relatedInsn => { relatedInsn.num = num });
}
getCount() {
return this.count;
}
getInstSize() {
return this.instSize;
}
getTotalSize() {
return this.count * this.instSize;
}
getRelatedInsns() {
return this.relatedInsns;
}
getNodeMap() {
return this.nodeMap;
}
updateNodeMap(nodeName: string) {
if (!this.nodeMap.has(nodeName)) {
this.nodeMap.set(nodeName, 1);
} else {
let old = this.nodeMap.get(nodeName);
this.nodeMap.set(nodeName, old! + 1);
}
}
unionNodeMap(nodeMap: Map<string, number>) {
nodeMap.forEach((value: number, key: string) => {
if (!this.nodeMap.has(key)) {
this.nodeMap.set(key, value);
} else {
let oldvalue = this.nodeMap.get(key);
oldvalue! += value;
this.nodeMap.set(key, oldvalue!);
}
});
}
getSavedSizeIfRemoved(Histogram: HistogramStatistics) {
let savedSize = this.getTotalSize();
this.relatedInsns.forEach(relatedInsn => {
let histogram = Histogram.getStatistics();
let item = histogram.get(relatedInsn.name);
if (item) {
savedSize += (relatedInsn.num) * item.getInstSize();
}
});
return savedSize;
}
static createItemValue(name: string, instSize: number): ItemValue {
let relatedInsns: { name: string, num: number };
if (name == "lda.str") {
relatedInsns = { name: "sta.dyn", num: 1 };
}
return new ItemValue(instSize, relatedInsns!);
}
}
class HistogramStatistics {
private insHistogram: Map<string, ItemValue> = new Map<string, ItemValue>();
private funcName: string;
constructor(funcName: string) {
this.funcName = funcName;
}
getInsName(ins: IRNode): string {
if (ins.kind == IRNodeKind.LABEL) {
return "Label"
}
if (CmdOptions.isVariantBytecode()) {
if (ins.mnemonic.startsWith("builtin")) {
let subCode = (<Imm>ins.operands[0]).value;
return (builtinsCodeMap as any)[ins.mnemonic][subCode];
}
} else {
if ((ins.kind == IRNodeKind.CALL) || (ins.kind == IRNodeKind.CALL_SHORT) || (ins.kind == IRNodeKind.CALL_RANGE)) {
let mnemonic = <string>ins.operands[0];
let part = mnemonic.split('.');
return part[2];
}
}
return ins.mnemonic;
}
unionStatistics(histogram: HistogramStatistics): void {
let histogramData = histogram.getStatistics();
histogramData.forEach((value: ItemValue, key: string) => {
if (!this.insHistogram.has(key)) {
this.insHistogram.set(key, value);
} else {
let old = this.insHistogram.get(key);
old!.add(value.getCount());
old!.unionNodeMap(value.getNodeMap());
this.insHistogram.set(key, old!);
}
});
}
catchStatistics(pg: PandaGen): void {
pg.getInsns().forEach(ins => {
let key = this.getInsName(ins);
let opSize = getInstructionSize(ins.kind);
let nodeName = ins.getNodeName();
if (key.length <= 1) {
LOGD("this IRNode had no key: " + ins.toString());
}
if (!this.insHistogram.has(key)) {
let item = ItemValue.createItemValue(key, opSize);
item.updateNodeMap(nodeName);
this.insHistogram.set(key, item);
} else {
let old = this.insHistogram.get(key);
old!.updateNodeMap(nodeName);
old!.add(1);
this.insHistogram.set(key, old!);
}
});
return;
}
getStatistics(): Map<string, ItemValue> {
return this.insHistogram;
}
getTotal() {
let totalInsnsNum: number = 0;
let totalSize: number = 0;
this.insHistogram.forEach((value, key) => {
totalInsnsNum += value.getCount();
totalSize += value.getTotalSize();
});
return [totalInsnsNum, totalSize];
}
print(): void {
let totalInsnsNum = this.getTotal()[0];
let totalSize = this.getTotal()[1];
LOGD("\n");
LOGD("Histogram:", "====== (" + this.funcName + ") ======");
LOGD("op code\t\t\tinsns number\tins size\ttotal size\tsize percentage");
this.insHistogram.forEach((value, key) => {
if (key.length < 8) { // 8 indicates insn name length
LOGD(key + "\t\t\t" + value.getCount() + "\t\t"+ value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
+ value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%"); // multiplying 100 is to calculate the percentage data
} else if (key.length < 16) { // 16 indicates insn name length
LOGD(key + "\t\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
+ value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
} else {
LOGD(key + "\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
+ value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
}
});
LOGD("total insns number : \t" + totalInsnsNum + "\t\t" + "total Size : \t" + totalSize);
LOGD("\n");
this.insHistogram.forEach((value, key) => {
if (value.getNodeMap().size > 1) {
LOGD("op code: " + key);
value.getNodeMap().forEach((num: number, node: string) => {
if (node.length < 8) {
LOGD("Node: \t" + node + "\t\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
} else if (node.length < 16) {
LOGD("Node: \t" + node + "\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
} else if (node.length < 24) {
LOGD("Node: \t" + node + "\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
} else {
LOGD("Node: \t" + node + "\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
}
});
LOGD("\n");
}
});
}
}
export class CompilerStatistics {
private histogramMap: Map<string, HistogramStatistics> = new Map<string, HistogramStatistics>();
private numOfHoistingCases: number[] = [0, 0, 0, 0];
private hoistingRelatedInsnNum: number = 0;
constructor() {
}
addHoistingRelatedInsnNum(num: number) {
this.hoistingRelatedInsnNum += num;
}
addNumOfHoistCases(type: HoistingType) {
this.numOfHoistingCases[type]++;
}
getInsHistogramStatistics(pg: PandaGen) {
let histogram = new HistogramStatistics(pg.internalName);
histogram.catchStatistics(pg);
this.histogramMap.set(pg.internalName, histogram);
}
printHistogram(verbose: boolean) {
let totalHistogram = new HistogramStatistics("Total");
this.histogramMap.forEach((histogram, funcName) => {
totalHistogram.unionStatistics(histogram);
if (verbose) {
histogram.print();
}
});
totalHistogram.print();
}
printHoistStatistics(): void {
LOGD("\n");
LOGD("HoistingRelated Histogram:", "======whole file=======");
LOGD("global var\tlocal var\tglobal function\tlocal function");
LOGD(this.numOfHoistingCases[0] + "\t\t" + this.numOfHoistingCases[1] + "\t\t" + this.numOfHoistingCases[2] + "\t\t" + this.numOfHoistingCases[3]);
LOGD("\n");
LOGD("Approximately hoisting related insns nums");
LOGD(this.hoistingRelatedInsnNum);
}
}
+413
View File
@@ -0,0 +1,413 @@
/*
* 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.
*/
import { PandaGen } from "src/pandagen";
import * as ts from "typescript";
import { LReference } from "./base/lreference";
import {
isArrayBindingOrAssignmentPattern,
isObjectBindingOrAssignmentPattern
} from "./base/util";
import {
CacheList,
getVregisterCache
} from "./base/vregisterCache";
import { Compiler } from "./compiler";
import {
Label,
VReg
} from "./irnodes";
import jshelpers from "./jshelpers";
import {
CatchTable,
LabelPair
} from "./statement/tryStatement";
import { Iterator } from "./base/iterator";
export function compileDestructuring(pattern: ts.BindingOrAssignmentPattern, pandaGen: PandaGen, compiler: Compiler) {
let rhs = pandaGen.getTemp();
pandaGen.storeAccumulator(pattern, rhs);
if (isArrayBindingOrAssignmentPattern(pattern)) {
compileArrayDestructuring(<ts.ArrayBindingOrAssignmentPattern>pattern, pandaGen, compiler);
}
if (isObjectBindingOrAssignmentPattern(pattern)) {
compileObjectDestructuring(<ts.ObjectBindingOrAssignmentPattern>pattern, pandaGen, compiler);
}
pandaGen.loadAccumulator(pattern, rhs);
pandaGen.freeTemps(rhs);
}
function compileArrayDestructuring(arr: ts.ArrayBindingOrAssignmentPattern, pandaGen: PandaGen, compiler: Compiler) {
let iter = pandaGen.getTemp();
let nextMethod = pandaGen.getTemp();
let iterDone = pandaGen.getTemp();
let iterValue = pandaGen.getTemp();
let nextResult = pandaGen.getTemp();
let exception = pandaGen.getTemp();
let isDeclaration = ts.isArrayBindingPattern(arr) ? true : false;
// get iterator
let iterator = new Iterator({iterator: iter, nextMethod: nextMethod}, iterDone, iterValue, pandaGen, arr);
iterator.getIterator();
// prepare try-catch for iterate over all the elements
let tryBeginLabel = new Label();
let tryEndLabel = new Label();
let catchBeginLabel = new Label();
let catchEndLabel = new Label();
let normalClose = new Label();
let endLabel = new Label();
new CatchTable(
pandaGen,
catchBeginLabel,
new LabelPair(tryBeginLabel, tryEndLabel)
);
// try start
pandaGen.label(arr, tryBeginLabel);
for (let i = 0; i < arr.elements.length; i++) {
let element = arr.elements[i];
iterator.callNext(nextResult);
// if a hole exist, just let the iterator step ahead
if (ts.isOmittedExpression(element)) {
continue;
}
// if its spread element
if ((!isDeclaration && ts.isSpreadElement(element)) ||
(isDeclaration && (<ts.BindingElement>element).dotDotDotToken)) {
emitRestElement(isDeclaration ? (<ts.BindingElement>element).name : (<ts.SpreadElement>element).expression,
iterator, nextResult, pandaGen, compiler, isDeclaration);
pandaGen.branch(element, endLabel);
break;
}
let hasInit = false;
let target: ts.Node = isDeclaration ? (<ts.BindingElement>element).name : <ts.Expression>element;
let init: ts.Expression | undefined = undefined;
// in case init is present
if (!isDeclaration && ts.isBinaryExpression(element)) {
if (element.operatorToken.kind != ts.SyntaxKind.EqualsToken) {
throw new Error("Invalid destructuring assignment target");
}
target = element.left;
init = element.right;
hasInit = true;
} else if (isDeclaration && (<ts.BindingElement>element).initializer) {
init = (<ts.BindingElement>element).initializer;
hasInit = true;
}
let lRef = LReference.generateLReference(compiler, target, isDeclaration ? true : false);
let getDefaultLabel = new Label();
let getUndefinedLabel = new Label();
let storeLabel = new Label();
iterator.iteratorComplete(nextResult);
pandaGen.condition(
element,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.True),
hasInit ? getDefaultLabel : getUndefinedLabel
);
// iterdone == false, get current itervalue
iterator.iteratorValue(nextResult);
if (hasInit) {
pandaGen.condition(
element,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.undefined),
getDefaultLabel
)
pandaGen.loadAccumulator(element, iterator.getCurrentValue());
pandaGen.branch(element, storeLabel);
pandaGen.label(element, getDefaultLabel);
compiler.compileExpression(<ts.Expression>init);
pandaGen.branch(element, storeLabel);
} else {
pandaGen.branch(element, storeLabel);
}
pandaGen.label(element, getUndefinedLabel);
pandaGen.loadAccumulator(element, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.label(element, storeLabel);
lRef.setValue();
}
// end of try
pandaGen.label(arr, tryEndLabel);
pandaGen.loadAccumulator(arr, iterator.getCurrrentDone());
pandaGen.condition(
arr,
ts.SyntaxKind.EqualsEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.True),
normalClose
);
// nothing need to be done
pandaGen.branch(arr, endLabel);
// if any exception ocurrs, store it, close iterator and rethrow exception
pandaGen.label(arr, catchBeginLabel);
pandaGen.storeAccumulator(arr, exception);
iterator.close();
pandaGen.loadAccumulator(arr, exception);
pandaGen.throw(arr);
pandaGen.label(arr, catchEndLabel);
// if iterDone is not true after normal completion, close iterator
pandaGen.label(arr, normalClose);
iterator.close();
pandaGen.label(arr, endLabel);
pandaGen.freeTemps(iter, nextMethod, iterDone, iterValue, nextResult, exception);
}
function emitRestElement(restElement: ts.BindingName | ts.Expression, iterator: Iterator, iterResult: VReg,
pandaGen: PandaGen, compiler: Compiler, isDeclaration: boolean) {
let arrayObj = pandaGen.getTemp();
let index = pandaGen.getTemp();
let nextLabel = new Label();
let doneLabel = new Label();
// create left reference for rest element
let target = restElement;
let lRef = LReference.generateLReference(compiler, target, isDeclaration);
// create an empty array first
pandaGen.createEmptyArray(restElement);
pandaGen.storeAccumulator(restElement, arrayObj);
// index = 0
pandaGen.loadAccumulatorInt(restElement, 0);
pandaGen.storeAccumulator(restElement, index);
pandaGen.label(restElement, nextLabel);
// if iterDone == true, done with the process of building array
iterator.iteratorComplete(iterResult);
pandaGen.condition(
restElement,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.True),
doneLabel
);
// get value from iter and store it to arrayObj
// getIterValue(iterRecord, iterValue, pandaGen, restElement);
iterator.iteratorValue(iterResult);
pandaGen.storeObjProperty(restElement, arrayObj, index);
// index++
pandaGen.loadAccumulatorInt(restElement, 1);
pandaGen.binary(restElement, ts.SyntaxKind.PlusToken, index);
pandaGen.storeAccumulator(restElement, index);
iterator.callNext(iterResult);
pandaGen.branch(restElement, nextLabel);
pandaGen.label(restElement, doneLabel);
pandaGen.loadAccumulator(restElement, arrayObj);
lRef.setValue();
pandaGen.freeTemps(arrayObj, index);
}
function compileObjectDestructuring(obj: ts.ObjectBindingOrAssignmentPattern, pandaGen: PandaGen, compiler: Compiler) {
let value = pandaGen.getTemp();
pandaGen.storeAccumulator(obj, value);
let isDeclaration: boolean = ts.isObjectLiteralExpression(obj) ? false : true;
let elements = isDeclaration ? (<ts.ObjectBindingPattern>obj).elements : (<ts.ObjectLiteralExpression>obj).properties;
let elementsLength = elements.length;
// check if value is coercible
if (elementsLength == 0 ||
(isDeclaration && isRestElement(<ts.BindingElement>elements[0])) ||
(!isDeclaration && ts.isSpreadAssignment(elements[0]))) {
let notNullish: Label = new Label();
let nullLish: Label = new Label();
pandaGen.loadAccumulator(obj, value);
pandaGen.condition(obj, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.Null), nullLish);
pandaGen.loadAccumulator(obj, value);
pandaGen.condition(obj, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), nullLish);
pandaGen.branch(obj, notNullish);
// value == null or undefined, throw error
pandaGen.label(obj, nullLish);
pandaGen.throwObjectNonCoercible(obj);
pandaGen.label(obj, notNullish);
}
// create before to store the properties
let properties: Array<VReg> = new Array<VReg>();
let excludedProp: Array<VReg> = new Array<VReg>();
for (let i = 0; i < elementsLength; i++) {
let tmp = pandaGen.getTemp();
properties.push(tmp);
}
for (let i = 0; i < elementsLength; i++) {
let element = elements[i];
// emit rest property
if ((isDeclaration && isRestElement(<ts.BindingElement>element)) ||
(!isDeclaration && ts.isSpreadAssignment(element))) {
emitRestProperty(<ts.BindingElement | ts.SpreadAssignment>element, excludedProp, value, pandaGen, compiler);
break;
}
excludedProp.push(properties[i]);
let loadedValue: VReg = pandaGen.getTemp();
let key: ts.Expression | ts.ComputedPropertyName;
let target: ts.Node = element;
let init: ts.Expression | undefined = undefined;
let hasInit: boolean = false;
if (isDeclaration) {
let bindingElement = <ts.BindingElement>element;
target = bindingElement.name;
if (bindingElement.propertyName) {
key = <ts.Expression>bindingElement.propertyName;
} else {
key = <ts.Identifier>bindingElement.name;
}
// obtain init if exists
if (bindingElement.initializer) {
hasInit = true;
init = bindingElement.initializer;
}
} else {
if (ts.isPropertyAssignment(element)) {
key = <ts.Expression>element.name;
let targetExpr = element.initializer;
if (ts.isBinaryExpression(targetExpr)) {
if (targetExpr.operatorToken.kind != ts.SyntaxKind.EqualsToken) {
throw new Error("Invalid destructuring target");
}
target = targetExpr.left;
init = targetExpr.right;
} else {
target = targetExpr;
}
} else if (ts.isShorthandPropertyAssignment(element)) {
key = element.name;
target = element.name;
init = element.objectAssignmentInitializer ? element.objectAssignmentInitializer : undefined;
} else {
throw new Error("Invalid destructuring target");
}
}
// compile key
if (ts.isComputedPropertyName(key)) {
compiler.compileExpression(key.expression);
} else {
if (ts.isIdentifier(key)) {
let keyName = jshelpers.getTextOfIdentifierOrLiteral(key);
pandaGen.loadAccumulatorString(key, keyName);
} else {
compiler.compileExpression(key);
}
}
pandaGen.storeAccumulator(key, properties[i]);
// create left reference
let lRef = LReference.generateLReference(compiler, target, isDeclaration);
// load obj property from rhs, return undefined if no corresponding property exists
pandaGen.loadObjProperty(element, value, properties[i]);
pandaGen.storeAccumulator(element, loadedValue);
let getDefaultLabel = new Label();
let storeLabel = new Label();
if (hasInit) {
pandaGen.condition(
element,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.undefined),
getDefaultLabel
);
// load the new value
pandaGen.loadAccumulator(element, loadedValue);
pandaGen.branch(element, storeLabel);
// use default value
pandaGen.label(element, getDefaultLabel);
compiler.compileExpression(<ts.Expression>init);
pandaGen.label(element, storeLabel);
}
lRef.setValue();
pandaGen.freeTemps(loadedValue);
}
pandaGen.freeTemps(value, ...properties);
}
function emitRestProperty(restProperty: ts.BindingElement | ts.SpreadAssignment, excludedProp: Array<VReg>,
obj: VReg, pandaGen: PandaGen, compiler: Compiler) {
let isDeclaration = ts.isBindingElement(restProperty) ? true : false;
let target = isDeclaration ? (<ts.BindingElement>restProperty).name : (<ts.SpreadAssignment>restProperty).expression;
let lRef = LReference.generateLReference(compiler, target, true);
let undefinedReg = pandaGen.getTemp();
if (excludedProp.length == 0) {
pandaGen.loadAccumulator(restProperty, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.storeAccumulator(restProperty, undefinedReg);
excludedProp.push(undefinedReg);
}
// Create a Object with the information of excluded properties
pandaGen.createObjectWithExcludedKeys(restProperty, obj, excludedProp);
lRef.setValue();
pandaGen.freeTemps(undefinedReg);
}
function isRestElement(node: ts.BindingElement) {
if (node.dotDotDotToken) {
return true;
}
return false;
}
+384
View File
@@ -0,0 +1,384 @@
/*
* 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.
*/
import * as ts from "typescript";
import { CmdOptions } from "./cmdOptions";
import {
CalliDynRange,
CallRange,
DebugInsPlaceHolder,
IRNode,
Label,
VReg
} from "./irnodes";
import * as jshelpers from "./jshelpers";
import { PandaGen } from "./pandagen";
import { Scope } from "./scope";
import {
Variable
} from "./variable";
export class DebugPosInfo {
private boundLeft: number | undefined = 0;
private boundRight: number | undefined = 0;
private lineNum: number = -1;
private columnNum: number = -1;
private wholeLine: string | undefined = "";
private nodeKind: NodeKind | undefined = NodeKind.FirstNodeOfFunction;
constructor() { }
public setDebugPosInfoNodeState(extendedNode: ts.Node | NodeKind): void {
if (DebugInfo.isNode(extendedNode)) {
this.nodeKind = NodeKind.Normal;
} else {
this.nodeKind = <NodeKind>extendedNode;
}
}
public getDebugPosInfoNodeState(): NodeKind | undefined {
return this.nodeKind;
}
public setBoundLeft(boundLeft: number): void {
this.boundLeft = boundLeft;
}
public getBoundLeft(): number | undefined {
return this.boundLeft;
}
public setBoundRight(boundRight: number): void {
this.boundRight = boundRight;
}
public getBoundRight(): number | undefined {
return this.boundRight;
}
public setSourecLineNum(lineNum: number): void {
this.lineNum = lineNum;
}
public getSourceLineNum(): number {
return this.lineNum;
}
public setSourecColumnNum(columnNum: number): void {
this.columnNum = columnNum;
}
public getSourceColumnNum(): number {
return this.columnNum;
}
public setWholeLine(wholeLine: string): void {
this.wholeLine = wholeLine;
}
public getWholeLine(): string | undefined {
return this.wholeLine;
}
public ClearMembersForReleaseBuild(): void {
this.ClearMembersForDebugBuild();
this.boundLeft = undefined;
this.boundRight = undefined;
}
public ClearMembersForDebugBuild(): void {
this.wholeLine = undefined;
this.nodeKind = undefined;
}
}
export class VariableDebugInfo {
private name = "";
private variable: Variable | undefined;
private signature = "";
private signatureType = "";
private reg: number = -1;
private start: number = -1;
private length: number = -1;
constructor(name: string, signature: string, signatureType: string,
reg: number, start: number = 0, length: number = 0) {
this.name = name;
this.signature = signature;
this.signatureType = signatureType;
this.reg = reg;
this.start = start;
this.length = length;
}
public setStart(start: number): void {
this.start = start;
}
public getStart(): number {
return this.start;
}
public setLength(length: number): void {
this.length = length;
}
}
export enum NodeKind {
Normal,
Invalid,
FirstNodeOfFunction,
}
export class DebugInfo {
private static scopeArray: Scope[] = [];
private static lastNode: ts.Node;
constructor() { }
public static isNode(extendedNode: ts.Node | NodeKind) {
if (extendedNode != NodeKind.Invalid &&
extendedNode != NodeKind.FirstNodeOfFunction &&
extendedNode != NodeKind.Normal) {
return true;
}
return false;
}
public static updateLastNode(lastNode: ts.Node | NodeKind) {
if (DebugInfo.isNode(lastNode)) {
DebugInfo.lastNode = <ts.Node>lastNode;
}
}
public static getLastNode() {
return DebugInfo.lastNode;
}
public static setPosInfoForUninitializeIns(posInfo: DebugPosInfo, pandaGen: PandaGen) {
let firstStmt = pandaGen.getFirstStmt();
if (firstStmt) {
let file = jshelpers.getSourceFileOfNode(firstStmt);
let loc = file.getLineAndCharacterOfPosition(firstStmt.getStart());
let wholeLineText = firstStmt.getText();
posInfo.setSourecLineNum(loc.line);
posInfo.setSourecColumnNum(loc.character);
posInfo.setWholeLine(wholeLineText);
}
}
public static addScope(scope: Scope) {
DebugInfo.scopeArray.push(scope);
}
public static getScopeArray() {
return DebugInfo.scopeArray;
}
public static clearScopeArray() {
DebugInfo.scopeArray = [];
}
public static setDebuginfoForIns(node: ts.Node | NodeKind, ...insns: IRNode[]): void {
DebugInfo.updateLastNode(node);
let lineNumber = -1;
let columnNumber = -1;
let wholeLineText = "";
if (DebugInfo.isNode(node)) {
let tsNode = <ts.Node>(node);
let file = jshelpers.getSourceFileOfNode(node);
if (!file) {
return;
}
let loc = file.getLineAndCharacterOfPosition(tsNode.getStart());
wholeLineText = tsNode.getText();
lineNumber = loc.line;
columnNumber = loc.character;
}
for (let i = 0; i < insns.length; i++) {
let pos = new DebugPosInfo();
pos.setSourecLineNum(lineNumber);
pos.setSourecColumnNum(columnNumber);
pos.setWholeLine(wholeLineText);
pos.setDebugPosInfoNodeState(node);
insns[i].debugPosInfo = pos;
}
}
private static matchFormat(irnode: IRNode): number {
let formatIndex = 0;
for (let i = 0; i < irnode.formats[0].length; i++) {
if (irnode.operands[i] instanceof VReg) {
for (let j = 0; j < irnode.formats.length; j++) {
if ((<VReg>irnode.operands[i]).num < (1 << irnode.formats[j][i].bitwidth)) {
formatIndex = j > formatIndex ? j : formatIndex;
continue;
}
}
}
}
return formatIndex;
}
private static getIRNodeWholeLength(irnode: IRNode): number {
if (irnode instanceof Label || irnode instanceof DebugInsPlaceHolder) {
return 0;
}
let length = 1;
if (!irnode.formats[0]) {
return 0;
}
let formatIndex = this.matchFormat(irnode);
let formats = irnode.formats[formatIndex];
// count operands length
for (let i = 0; i < formats.length; i++) {
if ((irnode instanceof CalliDynRange) || (irnode instanceof CallRange)) {
length += formats[0].bitwidth / 8; // 8 indicates that one byte is composed of 8 bits
length += formats[1].bitwidth / 8;
break;
}
length += (formats[i].bitwidth / 8);
}
return length;
}
private static setVariablesDebugInfoInternal(pandaGen: PandaGen, scope: Scope) {
let insns = pandaGen.getInsns();
// count variables offset
let startIdx = 0;
let startIns = scope.getScopeStartIns();
let endIns = scope.getScopeEndIns();
for (let i = 0; i < insns.length; i++) {
if (startIns == insns[i]) {
startIdx = i;
}
if (endIns == insns[i]) {
let name2variable = scope.getName2variable();
name2variable.forEach((value, key) => {
if (!value.hasAlreadyBinded()) {
return;
}
let variableInfo = new VariableDebugInfo(key, "any", "any", (value.getVreg().num));
variableInfo.setStart(startIdx);
variableInfo.setLength(i - startIdx + 1);
pandaGen.addDebugVariableInfo(variableInfo);
});
}
}
}
private static setPosDebugInfo(pandaGen: PandaGen) {
let insns = pandaGen.getInsns();
let offset = 0;
for (let i = 0; i < insns.length; i++) {
if (insns[i].debugPosInfo.getDebugPosInfoNodeState() == NodeKind.FirstNodeOfFunction) {
DebugInfo.setPosInfoForUninitializeIns(insns[i].debugPosInfo, pandaGen);
}
}
// count pos offset
for (let i = 0; i < insns.length; i++) {
let insLength = DebugInfo.getIRNodeWholeLength(insns[i]);
let insnsDebugPosInfo = insns[i].debugPosInfo;
if (insnsDebugPosInfo) {
insnsDebugPosInfo.setBoundLeft(offset);
insnsDebugPosInfo.setBoundRight(offset + insLength);
}
offset += insLength;
if (i > 0 && insns[i - 1] instanceof Label) {
insns[i - 1].debugPosInfo = insns[i].debugPosInfo;
}
}
}
private static removeDebugIns(pandaGen: PandaGen) {
let insns = pandaGen.getInsns();
for (let i = 0; i < insns.length; i++) {
if (insns[i] instanceof DebugInsPlaceHolder) {
insns.splice(i, 1);
i--;
}
}
}
private static setVariablesDebugInfo(pandaGen: PandaGen) {
let recordArray = DebugInfo.getScopeArray();
recordArray.forEach(scope => {
DebugInfo.setVariablesDebugInfoInternal(pandaGen, scope);
});
}
public static setDebugInfo(pandaGen: PandaGen) {
// set position debug info
DebugInfo.setPosDebugInfo(pandaGen);
if (CmdOptions.isDebugMode()) {
// set variable debug info
DebugInfo.setVariablesDebugInfo(pandaGen);
// delete ins placeholder
DebugInfo.removeDebugIns(pandaGen)
// clear scope array
DebugInfo.clearScopeArray();
return;
}
}
public static setSourceFileDebugInfo(pandaGen: PandaGen, node: ts.SourceFile | ts.FunctionLikeDeclaration) {
let sourceFile = jshelpers.getSourceFileOfNode(node);
pandaGen.setSourceFileDebugInfo(sourceFile.fileName);
if (CmdOptions.isDebugMode()) {
if (ts.isSourceFile(node)) {
pandaGen.setSourceCodeDebugInfo(node.text);
}
return;
}
}
public static copyDebugInfo(insn: IRNode, expansion: IRNode[]) {
let debugPosInfo = insn.debugPosInfo;
for (let j = 0; j < expansion.length; j++) {
expansion[j].debugPosInfo = debugPosInfo;
}
}
public static addDebugIns(scope: Scope, pandaGen: PandaGen, isStart: boolean) {
if (!CmdOptions.isDebugMode()) {
return;
}
let insns = pandaGen.getInsns();
let placeHolder = new DebugInsPlaceHolder();
insns.push(placeHolder);
if (isStart) {
scope.setScopeStartIns(placeHolder);
DebugInfo.addScope(scope);
} else {
scope.setScopeEndIns(placeHolder);
}
}
}
@@ -0,0 +1,182 @@
/*
* 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.
*/
import * as ts from "typescript";
import { Compiler } from "../compiler";
import * as jshelpers from "../jshelpers";
import { LiteralTag, Literal, LiteralBuffer } from "../base/literal";
import { isConstantExpr } from "../base/properties";
import { PandaGen } from "../pandagen";
import { isInteger } from "./numericLiteral";
import { VReg } from "../irnodes";
export function compileArrayLiteralExpression(compiler: Compiler, node: ts.ArrayLiteralExpression) {
let pandaGen = compiler.getPandaGen();
let arrayObj = pandaGen.getTemp();
createArrayFromElements(node, compiler, node.elements, arrayObj);
pandaGen.freeTemps(arrayObj);
}
export function createArrayFromElements(node: ts.Node, compiler: Compiler, elements: ts.NodeArray<ts.Expression>, arrayObj: VReg) {
let pandaGen = compiler.getPandaGen();
// empty Array
if (elements.length == 0) {
pandaGen.createEmptyArray(node);
pandaGen.storeAccumulator(node, arrayObj);
return;
}
let literalBuffer = new LiteralBuffer();
let indexReg = pandaGen.getTemp();
let arrayCreated: boolean = false;
let hasSpread: boolean = false;
for (let i = 0; i < elements.length; i++) {
let element = elements[i];
if (isConstantExpr(element)) {
let elem = parseConstantExpr(element);
if (!arrayCreated) {
literalBuffer.addLiterals(elem);
if (i == elements.length - 1) {
emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
pandaGen.storeAccumulator(element, arrayObj);
arrayCreated = true;
}
continue;
}
compiler.compileExpression(element);
if (hasSpread) {
storeElementIfSpreadExisted(pandaGen, element, arrayObj, indexReg);
} else {
pandaGen.storeOwnProperty(element, arrayObj, i);
}
continue;
}
if (ts.isSpreadElement(element)) {
if (!arrayCreated) {
emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
pandaGen.storeAccumulator(element, arrayObj);
arrayCreated = true;
}
if (hasSpread) {
storeSpreadElement(compiler, pandaGen, element, arrayObj, indexReg);
} else {
hasSpread = true;
pandaGen.loadAccumulatorInt(element, i);
pandaGen.storeAccumulator(element, indexReg);
storeSpreadElement(compiler, pandaGen, element, arrayObj, indexReg);
}
continue;
}
if (ts.isOmittedExpression(element)) {
if (!arrayCreated) {
emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
pandaGen.storeAccumulator(element, arrayObj);
arrayCreated = true;
}
if (i == elements.length - 1) {
// omittedExpression is the last element, we need set the length of the array
if (hasSpread) {
pandaGen.loadAccumulator(element, indexReg);
pandaGen.storeObjProperty(element, arrayObj, "length");
// no need to increment index since it's the last element
} else {
pandaGen.loadAccumulatorInt(element, elements.length);
pandaGen.storeObjProperty(element, arrayObj, "length");
}
}
continue;
}
// non-constant elements
if (!arrayCreated) {
emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
pandaGen.storeAccumulator(element, arrayObj);
arrayCreated = true;
}
compiler.compileExpression(element);
if (hasSpread) {
storeElementIfSpreadExisted(pandaGen, element, arrayObj, indexReg);
} else {
pandaGen.storeOwnProperty(element, arrayObj, i);
}
}
pandaGen.loadAccumulator(node, arrayObj);
pandaGen.freeTemps(indexReg);
}
function parseConstantExpr(element: ts.Expression): Literal {
let elem: Literal;
switch (element.kind) {
case ts.SyntaxKind.FalseKeyword:
elem = new Literal(LiteralTag.BOOLEAN, false);
break;
case ts.SyntaxKind.TrueKeyword:
elem = new Literal(LiteralTag.BOOLEAN, true);
break;
case ts.SyntaxKind.StringLiteral:
elem = new Literal(LiteralTag.STRING, jshelpers.getTextOfIdentifierOrLiteral(element));
break;
case ts.SyntaxKind.NumericLiteral: {
let value = Number.parseFloat(jshelpers.getTextOfIdentifierOrLiteral(element));
if (isInteger(value)) {
elem = new Literal(LiteralTag.INTEGER, value);
} else {
elem = new Literal(LiteralTag.DOUBLE, value);
}
break;
}
case ts.SyntaxKind.NullKeyword:
elem = new Literal(LiteralTag.NULLVALUE, null);
break;
default:
throw new Error("invalid constant expression");
}
return elem;
}
function emitCreateArrayWithBuffer(pandaGen: PandaGen, literalBuffer: LiteralBuffer, element: ts.Expression) {
if (literalBuffer.isEmpty()) {
pandaGen.createEmptyArray(element);
} else {
let literalArrayBuffer = PandaGen.getLiteralArrayBuffer();
let bufferIdx = literalArrayBuffer.length;
literalArrayBuffer.push(literalBuffer);
pandaGen.createArrayWithBuffer(element, bufferIdx);
}
}
function storeElementIfSpreadExisted(pandaGen: PandaGen, element: ts.Expression, arrayObj: VReg, indexReg: VReg) {
pandaGen.storeOwnProperty(element, arrayObj, indexReg);
pandaGen.unary(element, ts.SyntaxKind.PlusPlusToken, indexReg);
pandaGen.storeAccumulator(element, indexReg);
}
function storeSpreadElement(compiler: Compiler, pandaGen: PandaGen, element: ts.SpreadElement, arrayObj: VReg, indexReg: VReg) {
compiler.compileExpression(element.expression);
pandaGen.storeArraySpreadElement(element, arrayObj, indexReg);
pandaGen.storeAccumulator(element, indexReg);
}
+119
View File
@@ -0,0 +1,119 @@
/*
* 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.
*/
import * as ts from "typescript";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { Compiler } from "../compiler";
import { VReg } from "../irnodes";
import { compileSuperCall, compileSuperProperty } from "../statement/classStatement";
import { createArrayFromElements } from "./arrayLiteralExpression";
import { getObjAndProp } from "./memberAccessExpression";
import { isMemberExpression } from "../base/util";
export function compileCallExpression(expr: ts.CallExpression, compiler: Compiler, inTailPos?: boolean) {
let pandaGen = compiler.getPandaGen();
// import call should be supported further
if ((expr.expression.kind == ts.SyntaxKind.CallExpression) || (expr.expression.kind == ts.SyntaxKind.NewExpression)) {
let processed = compiler.compileFunctionReturnThis(<ts.NewExpression | ts.CallExpression>expr.expression);
if (processed) {
return;
}
}
if (expr.expression.kind == ts.SyntaxKind.SuperKeyword) {
let args: VReg[] = [];
let hasSpread = emitCallArguments(compiler, expr, args);
compileSuperCall(compiler, expr, args, hasSpread);
pandaGen.freeTemps(...args);
return;
}
let { arguments: args, passThis: passThis } = getHiddenParameters(expr.expression, compiler);
// compile arguments of function call
emitCall(expr, args, passThis, compiler);
pandaGen.freeTemps(...args);
}
export function getHiddenParameters(expr: ts.Expression, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let passThis = false;
let args: VReg[] = [];
let funcReg = pandaGen.getTemp();
if (isMemberExpression(expr)) {
passThis = true;
let thisReg = pandaGen.getTemp();
let propReg = pandaGen.getTemp();
let { obj: obj, prop: prop } = getObjAndProp(<ts.PropertyAccessExpression | ts.ElementAccessExpression>expr, thisReg, propReg, compiler);
if ((<ts.PropertyAccessExpression | ts.ElementAccessExpression>expr).expression.kind == ts.SyntaxKind.SuperKeyword) {
compileSuperProperty(compiler, expr, thisReg, prop);
} else {
pandaGen.loadObjProperty(expr, thisReg, prop);
}
pandaGen.storeAccumulator(expr, funcReg);
args.push(...[funcReg, thisReg]);
pandaGen.freeTemps(propReg);
} else {
compiler.compileExpression(expr);
pandaGen.storeAccumulator(expr, funcReg);
args.push(funcReg);
}
return { arguments: args, passThis: passThis };
}
function emitCallArguments(compiler: Compiler, expr: ts.CallExpression, args: VReg[]) {
let pandaGen = compiler.getPandaGen();
let hasSpread = false;
for (let i = 0; i < expr.arguments.length; i++) {
let argument = expr.arguments[i];
hasSpread = ts.isSpreadElement(argument) ? true : false;
if (hasSpread) {
break;
}
}
if (!hasSpread) {
expr.arguments.forEach((argExpr: ts.Expression) => {
let arg = pandaGen.getTemp();
compiler.compileExpression(argExpr);
pandaGen.storeAccumulator(argExpr, arg);
args.push(arg);
});
}
return hasSpread;
}
export function emitCall(expr: ts.CallExpression, args: VReg[], passThis: boolean, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let hasSpread = emitCallArguments(compiler, expr, args);
if (!hasSpread) {
pandaGen.call(expr, [...args], passThis);
return;
}
// spread argument exist
let callee = args[0];
let thisReg = passThis ? args[1] : getVregisterCache(pandaGen, CacheList.undefined);
let argArray = pandaGen.getTemp();
createArrayFromElements(expr, compiler, <ts.NodeArray<ts.Expression>>expr.arguments, argArray);
pandaGen.callSpread(expr, callee, thisReg, argArray);
pandaGen.freeTemps(argArray);
}
@@ -0,0 +1,103 @@
/*
* 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.
*/
import * as ts from "typescript";
import { Compiler } from "../compiler";
import { VReg } from "../irnodes";
import * as jshelpers from "../jshelpers";
import { compileSuperProperty } from "../statement/classStatement";
const MAX_LENGTH = 2 ** 32 - 1;
export function compileMemberAccessExpression(node: ts.ElementAccessExpression | ts.PropertyAccessExpression, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let objReg = pandaGen.getTemp();
let propReg = pandaGen.getTemp();
let { obj: obj, prop: property } = getObjAndProp(node, objReg, propReg, compiler)
if (jshelpers.isSuperProperty(node)) {
// make sure "this" is stored in lexical env if needed
let thisReg = pandaGen.getTemp();
compileSuperProperty(compiler, node, thisReg, property);
pandaGen.freeTemps(thisReg);
} else {
pandaGen.loadObjProperty(node, obj, property);
}
pandaGen.freeTemps(objReg, propReg);
}
export function getObjAndProp(node: ts.ElementAccessExpression | ts.PropertyAccessExpression, objReg: VReg, propReg: VReg, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let obj = objReg;
let prop: VReg | string | number = propReg;
// get obj first;
if (!jshelpers.isSuperProperty(node)) {
compiler.compileExpression(node.expression);
pandaGen.storeAccumulator(node.expression, objReg);
}
if (ts.isPropertyAccessExpression(node)) {
if (node.name.kind != ts.SyntaxKind.Identifier) {
throw new Error("Property name of type private Identifier is unimplemented");
}
prop = jshelpers.getTextOfIdentifierOrLiteral(node.name);
} else {
if (ts.isStringLiteral(node.argumentExpression)) {
prop = jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression);
// deal with case like a["1"]
let temp = Number(prop);
if (!isNaN(Number.parseFloat(prop)) && !isNaN(temp) && isValidIndex(temp) && String(temp) == prop) {
prop = temp;
}
} else if (ts.isNumericLiteral(node.argumentExpression)) {
prop = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression));
if (!isValidIndex(prop)) {
prop = prop.toString();
}
} else if (ts.isPrefixUnaryExpression(node.argumentExpression) && ts.isNumericLiteral(node.argumentExpression.operand) &&
(node.argumentExpression.operator == ts.SyntaxKind.MinusToken || node.argumentExpression.operator == ts.SyntaxKind.PlusToken)) {
let expr = node.argumentExpression;
let temp = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(expr.operand));
if (expr.operator == ts.SyntaxKind.MinusToken) {
prop = "-" + temp.toString();
} else {
if (!isValidIndex(temp)) {
prop = "+" + temp.toString();
} else {
prop = temp;
}
}
} else {
compiler.compileExpression(node.argumentExpression);
pandaGen.storeAccumulator(node.argumentExpression, propReg);
prop = propReg;
}
}
return { obj: obj, prop: prop };
}
export function isValidIndex(num: number) {
if ((num >= 0) && (num < MAX_LENGTH) && (Number.isInteger(num))) {
return true;
}
return false;
}
+34
View File
@@ -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.
*/
import * as ts from "typescript";
import { Compiler } from "../compiler";
import * as jshelpers from "../jshelpers";
export function compileMetaProperty(expr: ts.MetaProperty, compiler: Compiler) {
let curScope = compiler.getCurrentScope();
let id = jshelpers.getTextOfIdentifierOrLiteral(expr.name);
if (id == "target") {
let { scope, level, v } = curScope.find("4newTarget");
if (!v) {
throw new Error("fail to access new.target");
} else {
compiler.loadTarget(expr, { scope, level, v });
}
return;
}
// support meta.property further
}
+70
View File
@@ -0,0 +1,70 @@
/*
* 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.
*/
import * as ts from "typescript";
import { Compiler } from "../compiler";
import { VReg } from "../irnodes";
import { containSpreadElement } from "../base/util";
import { createArrayFromElements } from "./arrayLiteralExpression";
export function compileNewExpression(expr: ts.NewExpression, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let ctorReg = pandaGen.getTemp();
let newTargetReg = pandaGen.getTemp();
// get the ctor function
compiler.compileExpression(expr.expression);
pandaGen.storeAccumulator(expr, ctorReg);
// new.target will be the same as ctor
pandaGen.moveVreg(expr, newTargetReg, ctorReg);
if (containSpreadElement(expr.arguments)) {
let argRegs = pandaGen.getTemp();
createArrayFromElements(expr, compiler, <ts.NodeArray<ts.Expression>>expr.arguments, argRegs);
pandaGen.newObjSpread(expr, ctorReg, newTargetReg);
pandaGen.freeTemps(ctorReg, newTargetReg, argRegs);
return;
}
// prepare arguments for newobj.dyn.range instruction
let numArgs = 2; // for the ctor
if (expr.arguments) {
numArgs += expr.arguments.length;
}
let argRegs = new Array<VReg>(numArgs);
argRegs[0] = ctorReg;
argRegs[1] = newTargetReg;
let argIndex = 2;
if (expr.arguments) {
// store ctor arguments in registers
expr.arguments.forEach((argExpr: ts.Expression) => {
let argReg = pandaGen.getTemp();
compiler.compileExpression(argExpr);
pandaGen.storeAccumulator(expr, argReg);
argRegs[argIndex++] = argReg;
});
}
// generate the instruction to create new instance
pandaGen.newObject(expr, argRegs);
// free temp registers
pandaGen.freeTemps(...argRegs);
}
+53
View File
@@ -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.
*/
import * as ts from "typescript";
import {
CacheList,
getVregisterCache
} from "../base/vregisterCache";
import * as jshelpers from "../jshelpers";
import { PandaGen } from "../pandagen";
const MAX_INT = 2 ** 31 - 1;
export function isInteger(value: number): Boolean {
if (!Number.isSafeInteger(value)) {
return false;
}
if (value > MAX_INT) {
return false;
}
return true;
}
export function compileNumericLiteral(pandaGen: PandaGen, lit: ts.NumericLiteral) {
let text = jshelpers.getTextOfIdentifierOrLiteral(lit);
let value = Number.parseFloat(text);
// check whether value is a NaN
if (Number.isNaN(value)) {
pandaGen.loadAccumulator(lit, getVregisterCache(pandaGen, CacheList.NaN));
} else if (!Number.isFinite(value)) {
// check whether value is a Infinity
pandaGen.loadAccumulator(lit, getVregisterCache(pandaGen, CacheList.Infinity));
} else if (isInteger(value)) {
// check whether value is a SafeInteger
pandaGen.loadAccumulatorInt(lit, value);
} else {
pandaGen.loadAccumulatorFloat(lit, value);
}
}
@@ -0,0 +1,294 @@
/*
* 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.
*/
import * as ts from "typescript";
import { Compiler } from "src/compiler";
import * as jshelpers from "../jshelpers";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { isInteger } from "./numericLiteral";
import { PandaGen } from "../pandagen";
import { VReg } from "../irnodes";
import { PropertyKind, Property, generatePropertyFromExpr } from "../base/properties";
import { LiteralTag, Literal, LiteralBuffer } from "../base/literal";
export function compileObjectLiteralExpression(compiler: Compiler, expr: ts.ObjectLiteralExpression) {
let pandaGen = compiler.getPandaGen();
// traverse the properties entries and store the useful information
let properties: Property[] = generatePropertyFromExpr(expr);
let objReg = pandaGen.getTemp();
let hasMethod: boolean = false;
// empty object literal expression
if (properties.length == 0) {
pandaGen.createEmptyObject(expr);
pandaGen.storeAccumulator(expr, objReg);
pandaGen.freeTemps(objReg);
return;
}
let literalBuffer = new LiteralBuffer();
hasMethod = compileProperties(compiler, properties, literalBuffer);
createObject(expr, pandaGen, objReg, literalBuffer, hasMethod, compiler);
// for now there may left some Variable/Accessor to set the true value
setUncompiledProperties(compiler, pandaGen, properties, objReg);
pandaGen.loadAccumulator(expr, objReg);
pandaGen.freeTemps(objReg);
}
function compileProperties(compiler: Compiler, properties: Property[], literalBuffer: LiteralBuffer): boolean {
let hasMethod: boolean = false;
for (let prop of properties) {
if (prop.getKind() == PropertyKind.Spread || prop.getKind() == PropertyKind.Computed) {
break;
}
if (prop.getKind() == PropertyKind.Prototype || prop.isRedeclared()) {
continue;
}
let nameLiteral = new Literal(LiteralTag.STRING, String(prop.getName()));
if (prop.getKind() == PropertyKind.Constant) {
let valLiteral: Literal = createConstantLiteral(prop);
literalBuffer.addLiterals(nameLiteral, valLiteral!);
prop.setCompiled(); // need to be careful
}
if (prop.getKind() == PropertyKind.Variable) {
let compilerDriver = compiler.getCompilerDriver();
let valueNode = prop.getValue();
let valLiteral: Literal;
if (ts.isMethodDeclaration(valueNode)) {
if (valueNode.asteriskToken) {
valLiteral = new Literal(LiteralTag.GENERATOR, compilerDriver.getFuncInternalName(valueNode));
} else {
valLiteral = new Literal(LiteralTag.METHOD, compilerDriver.getFuncInternalName(valueNode));
}
prop.setCompiled();
hasMethod = true;
} else {
valLiteral = new Literal(LiteralTag.NULLVALUE, null);
}
literalBuffer.addLiterals(nameLiteral, valLiteral);
}
if (prop.getKind() == PropertyKind.Accessor) {
let valLiteral = new Literal(LiteralTag.ACCESSOR, null);
literalBuffer.addLiterals(nameLiteral, valLiteral);
}
}
return hasMethod;
}
function createObject(expr: ts.ObjectLiteralExpression, pandaGen: PandaGen, objReg: VReg,
literalBuffer: LiteralBuffer, hasMethod: boolean, compiler: Compiler) {
if (literalBuffer.isEmpty()) {
pandaGen.createEmptyObject(expr);
} else {
let literalArrayBuffer = PandaGen.getLiteralArrayBuffer();
let bufferIdx = literalArrayBuffer.length;
literalArrayBuffer.push(literalBuffer);
if (hasMethod) {
let env = compiler.getCurrentEnv();
pandaGen.createObjectHavingMethod(expr, bufferIdx, env);
} else {
pandaGen.createObjectWithBuffer(expr, bufferIdx);
}
}
pandaGen.storeAccumulator(expr, objReg);
}
function createConstantLiteral(prop: Property): Literal {
let valLiteral: Literal;
if (prop.getValue().kind == ts.SyntaxKind.StringLiteral) {
valLiteral = new Literal(LiteralTag.STRING, jshelpers.getTextOfIdentifierOrLiteral(prop.getValue()));
} else if (prop.getValue().kind == ts.SyntaxKind.NumericLiteral) {
let value = Number.parseFloat(jshelpers.getTextOfIdentifierOrLiteral(prop.getValue()));
if (isInteger(value)) {
valLiteral = new Literal(LiteralTag.INTEGER, value);
} else {
valLiteral = new Literal(LiteralTag.DOUBLE, value);
}
} else if (prop.getValue().kind == ts.SyntaxKind.TrueKeyword || prop.getValue().kind == ts.SyntaxKind.FalseKeyword) {
if (prop.getValue().kind == ts.SyntaxKind.TrueKeyword) {
valLiteral = new Literal(LiteralTag.BOOLEAN, true);
} else {
valLiteral = new Literal(LiteralTag.BOOLEAN, false);
}
} else if (prop.getValue().kind == ts.SyntaxKind.NullKeyword) {
valLiteral = new Literal(LiteralTag.NULLVALUE, null);
} else {
throw new Error("Unreachable Kind of Literal");
}
return valLiteral;
}
function compileAccessorProperty(pandaGen: PandaGen, compiler: Compiler, objReg: VReg, prop: Property) {
let getterReg = pandaGen.getTemp();
let setterReg = pandaGen.getTemp();
let propReg = pandaGen.getTemp();
let propName = String(prop.getName());
let accessor: ts.GetAccessorDeclaration | ts.SetAccessorDeclaration;
if (prop.getGetter() !== undefined) {
let getter = <ts.GetAccessorDeclaration>prop.getGetter();
createMethodOrAccessor(pandaGen, compiler, objReg, getter);
pandaGen.storeAccumulator(getter, getterReg);
accessor = getter;
}
if (prop.getSetter() !== undefined) {
let setter = <ts.SetAccessorDeclaration>prop.getSetter();
createMethodOrAccessor(pandaGen, compiler, objReg, setter);
pandaGen.storeAccumulator(setter, setterReg);
accessor = setter;
}
pandaGen.loadAccumulatorString(accessor!, propName);
pandaGen.storeAccumulator(accessor!, propReg);
if (prop.getGetter() !== undefined && prop.getSetter() !== undefined) {
pandaGen.defineGetterSetterByValue(accessor!, objReg, propReg, getterReg, setterReg, false);
} else if (ts.isGetAccessorDeclaration(accessor!)) {
pandaGen.defineGetterSetterByValue(accessor, objReg, propReg, getterReg, getVregisterCache(pandaGen, CacheList.undefined), false);
} else {
pandaGen.defineGetterSetterByValue(accessor!, objReg, propReg, getVregisterCache(pandaGen, CacheList.undefined), setterReg, false);
}
pandaGen.freeTemps(getterReg, setterReg, propReg);
}
function compileSpreadProperty(compiler: Compiler, prop: Property, objReg: VReg) {
let pandaGen = compiler.getPandaGen();
let srcObj = pandaGen.getTemp();
compiler.compileExpression(<ts.Expression>prop.getValue());
pandaGen.storeAccumulator(<ts.Expression>prop.getValue(), srcObj);
pandaGen.copyDataProperties(<ts.Expression>prop.getValue().parent, objReg, srcObj);
pandaGen.freeTemps(srcObj);
}
function compileComputedProperty(compiler: Compiler, prop: Property, objReg: VReg) {
// Computed can't know its key in compile time, create Object now.
let pandaGen = compiler.getPandaGen();
let keyReg = pandaGen.getTemp();
compiler.compileExpression((<ts.ComputedPropertyName>prop.getName()).expression);
pandaGen.storeAccumulator(prop.getValue(), keyReg);
switch (prop.getValue().kind) {
case ts.SyntaxKind.PropertyAssignment: {
compiler.compileExpression((<ts.PropertyAssignment>prop.getValue()).initializer);
pandaGen.storeOwnProperty(prop.getValue(), objReg, keyReg);
break;
}
case ts.SyntaxKind.MethodDeclaration: {
createMethodOrAccessor(pandaGen, compiler, objReg, <ts.MethodDeclaration>prop.getValue());
pandaGen.storeOwnProperty(prop.getValue(), objReg, keyReg);
break;
}
case ts.SyntaxKind.GetAccessor: {
let accessorReg = pandaGen.getTemp();
let getter = <ts.GetAccessorDeclaration>prop.getValue();
createMethodOrAccessor(pandaGen, compiler, objReg, getter);
pandaGen.storeAccumulator(getter, accessorReg);
pandaGen.defineGetterSetterByValue(getter, objReg, keyReg, accessorReg, getVregisterCache(pandaGen, CacheList.undefined), true);
pandaGen.freeTemps(accessorReg);
break;
}
case ts.SyntaxKind.SetAccessor: {
let accessorReg = pandaGen.getTemp();
let setter = <ts.SetAccessorDeclaration>prop.getValue();
createMethodOrAccessor(pandaGen, compiler, objReg, setter);
pandaGen.storeAccumulator(setter, accessorReg);
pandaGen.defineGetterSetterByValue(setter, objReg, keyReg, getVregisterCache(pandaGen, CacheList.undefined), accessorReg, true);
pandaGen.freeTemps(accessorReg);
break;
}
// no default
}
pandaGen.freeTemps(keyReg);
}
function compileProtoProperty(compiler: Compiler, prop: Property, objReg: VReg) {
let pandaGen = compiler.getPandaGen();
let protoReg = pandaGen.getTemp();
compiler.compileExpression(<ts.Expression>prop.getValue());
pandaGen.storeAccumulator(<ts.Expression>prop.getValue().parent, protoReg);
pandaGen.setObjectWithProto(<ts.Expression>prop.getValue().parent, protoReg, objReg);
pandaGen.freeTemps(protoReg);
}
function setUncompiledProperties(compiler: Compiler, pandaGen: PandaGen, properties: Property[], objReg: VReg) {
for (let prop of properties) {
if (!prop.isCompiled()) {
switch (prop.getKind()) {
case PropertyKind.Accessor: {
compileAccessorProperty(pandaGen, compiler, objReg, prop);
break;
}
case PropertyKind.Spread: {
compileSpreadProperty(compiler, prop, objReg);
break;
}
case PropertyKind.Computed: {
compileComputedProperty(compiler, prop, objReg);
break;
}
case PropertyKind.Constant:
case PropertyKind.Variable: {
if (ts.isMethodDeclaration(prop.getValue())) {
createMethodOrAccessor(pandaGen, compiler, objReg, <ts.MethodDeclaration>prop.getValue());
} else {
compiler.compileExpression(<ts.Expression | ts.Identifier>prop.getValue());
}
pandaGen.storeOwnProperty(prop.getValue().parent, objReg, <string | number>(prop.getName()));
break;
}
case PropertyKind.Prototype: {
compileProtoProperty(compiler, prop, objReg);
break;
}
default: {
throw new Error("Unreachable PropertyKind for NullValue setting");
}
}
}
}
}
export function createMethodOrAccessor(pandaGen: PandaGen, compiler: Compiler, objReg: VReg,
func: ts.MethodDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration | ts.ConstructorDeclaration) {
let internalName = compiler.getCompilerDriver().getFuncInternalName(func);
let env = compiler.getCurrentEnv();
if (ts.isMethodDeclaration(func) && func.asteriskToken) {
pandaGen.defineFunction(func, func, internalName, env);
} else {
pandaGen.defineMethod(func, internalName, objReg, env);
}
}
@@ -0,0 +1,31 @@
/*
* 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.
*/
import * as ts from "typescript";
export function findInnerExprOfParenthesis(expr: ts.ParenthesizedExpression): ts.Expression {
while (expr.expression.kind == ts.SyntaxKind.ParenthesizedExpression) {
expr = <ts.ParenthesizedExpression>expr.expression;
}
return expr.expression;
}
export function findOuterNodeOfParenthesis(expr: ts.Node): ts.Node {
let parent = expr.parent;
while (parent.kind == ts.SyntaxKind.ParenthesizedExpression) {
parent = parent.parent;
}
return parent;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* 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.
*/
import * as ts from "typescript";
import * as jshelpers from "../jshelpers";
import { PandaGen } from "../pandagen";
export function compileStringLiteral(pandaGen: PandaGen, lit: ts.StringLiteral) {
let text = jshelpers.getTextOfIdentifierOrLiteral(lit);
pandaGen.loadAccumulatorString(lit, text);
}
@@ -0,0 +1,114 @@
/*
* 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.
*/
import * as ts from "typescript";
import { PandaGen } from "../pandagen";
import { VReg } from "../irnodes";
function genRawString(pandaGen: PandaGen, expr: ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral) {
let text = ""
if (ts.isTemplateExpression(expr)) {
text = expr.head.rawText!;
} else {
text = expr.rawText!;
}
text = text.replace(/(\r?\n|\r)/gm, "\n");
pandaGen.loadAccumulatorString(expr, text);
}
function genCookedString(pandaGen: PandaGen, expr: ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral) {
let text = ""
if (ts.isTemplateExpression(expr)) {
text = expr.head.text;
} else {
text = expr.text;
}
if (text.indexOf("\\u{") != -1) {
text = eval("'" + text + "'");
text = unescape(text.replace(/\u/g, "%u"));
}
pandaGen.loadAccumulatorString(expr, text);
}
function genTemplateArrayArg(pandaGen: PandaGen, expr: ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral, rawArr: VReg, cookedArr: VReg) {
let spans = undefined;
if (ts.isTemplateExpression(expr)) {
spans = expr.templateSpans;
}
let elemIndex = 0;
let indexReg = pandaGen.getTemp();
let rawArrTmp = pandaGen.getTemp();
let cookedArrTmp = pandaGen.getTemp();
pandaGen.createEmptyArray(expr);
pandaGen.storeAccumulator(expr, rawArrTmp);
pandaGen.createEmptyArray(expr);
pandaGen.storeAccumulator(expr, cookedArrTmp);
pandaGen.loadAccumulatorInt(expr, elemIndex);
pandaGen.storeAccumulator(expr, indexReg);
genRawString(pandaGen, expr)
pandaGen.storeObjProperty(expr, rawArrTmp, indexReg);
genCookedString(pandaGen, expr)
pandaGen.storeObjProperty(expr, cookedArrTmp, indexReg);
++elemIndex;
if (spans && spans.length) {
spans.forEach((span: ts.TemplateSpan) => {
pandaGen.loadAccumulatorInt(span, elemIndex);
pandaGen.storeAccumulator(span, indexReg);
pandaGen.loadAccumulatorString(span, span.literal.rawText === undefined ? span.literal.text : span.literal.rawText);
pandaGen.storeObjProperty(span, rawArrTmp, indexReg);
pandaGen.loadAccumulatorString(span, span.literal.text);
pandaGen.storeObjProperty(span, cookedArrTmp, indexReg);
++elemIndex;
});
}
pandaGen.moveVreg(expr, rawArr, rawArrTmp);
pandaGen.moveVreg(expr, cookedArr, cookedArrTmp);
pandaGen.freeTemps(indexReg, rawArrTmp, cookedArrTmp);
}
export function getTemplateObject(pandaGen: PandaGen, expr: ts.TaggedTemplateExpression) {
let templateArgs = pandaGen.getTemp();
let indexReg = pandaGen.getTemp();
let rawArr = pandaGen.getTemp();
let cookedArr = pandaGen.getTemp();
genTemplateArrayArg(pandaGen, expr.template, rawArr, cookedArr);
pandaGen.createEmptyArray(expr);
pandaGen.storeAccumulator(expr, templateArgs);
let elemIndex = 0;
pandaGen.loadAccumulatorInt(expr, elemIndex);
pandaGen.storeAccumulator(expr, indexReg);
pandaGen.loadAccumulator(expr, rawArr);
pandaGen.storeObjProperty(expr, templateArgs, indexReg);
++elemIndex;
pandaGen.loadAccumulatorInt(expr, elemIndex);
pandaGen.storeAccumulator(expr, indexReg);
pandaGen.loadAccumulator(expr, cookedArr);
pandaGen.storeObjProperty(expr, templateArgs, indexReg);
pandaGen.getTemplateObject(expr, templateArgs);
pandaGen.freeTemps(templateArgs, indexReg, rawArr, cookedArr);
}
@@ -0,0 +1,54 @@
/*
* 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.
*/
import * as ts from "typescript";
import { GeneratorFunctionBuilder } from "../function/generatorFunctionBuilder";
import { DiagnosticCode, DiagnosticError } from "../diagnostic";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { Compiler } from "../compiler";
export function compileYieldExpression(compiler: Compiler, expr: ts.YieldExpression) {
if (!(compiler.getFuncBuilder() instanceof GeneratorFunctionBuilder)) {
throw new DiagnosticError(expr.parent, DiagnosticCode.A_yield_expression_is_only_allowed_in_a_generator_body);
}
expr.asteriskToken ? genYieldStarExpr(compiler, expr) : genYieldExpr(compiler, expr);
}
function genYieldExpr(compiler: Compiler, expr: ts.YieldExpression) {
let pandaGen = compiler.getPandaGen();
let funcBuilder = <GeneratorFunctionBuilder>compiler.getFuncBuilder();
if (expr.expression) {
let retValue = pandaGen.getTemp();
compiler.compileExpression(expr.expression);
pandaGen.storeAccumulator(expr, retValue);
funcBuilder.yield(expr, retValue);
pandaGen.freeTemps(retValue);
} else {
funcBuilder.yield(expr, getVregisterCache(pandaGen, CacheList.undefined));
}
}
function genYieldStarExpr(compiler: Compiler, expr: ts.YieldExpression) {
let funcBuilder = <GeneratorFunctionBuilder>compiler.getFuncBuilder();
if (!expr.expression) {
throw new Error("yield* must have an expression!");
}
compiler.compileExpression(expr.expression!);
funcBuilder.yieldStar(expr);
}
@@ -0,0 +1,122 @@
/*
* 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.
*/
import ts from "typescript";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { NodeKind } from "../debuginfo";
import {
Label,
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { CatchTable, LabelPair } from "../statement/tryStatement";
enum ResumeMode { Return = 0, Throw, Next };
/**
* async function foo() {
* await 'promise obj';
* }
*/
export class AsyncFunctionBuilder {
private pandaGen: PandaGen;
private beginLabel: Label;
private endLabel: Label;
private asyncObj: VReg;
private retVal: VReg;
constructor(pandaGen: PandaGen) {
this.pandaGen = pandaGen;
this.beginLabel = new Label();
this.endLabel = new Label();
this.asyncObj = pandaGen.getTemp();
this.retVal = pandaGen.getTemp();
}
prepare(node: ts.Node): void {
let pandaGen = this.pandaGen;
pandaGen.asyncFunctionEnter(node);
pandaGen.storeAccumulator(node, this.asyncObj);
pandaGen.label(node, this.beginLabel);
}
await(node: ts.Node, value: VReg): void {
let pandaGen = this.pandaGen;
let promise = this.pandaGen.getTemp();
pandaGen.asyncFunctionAwaitUncaught(node, this.asyncObj, value);
pandaGen.storeAccumulator(node, promise);
pandaGen.suspendGenerator(node, this.asyncObj, promise);
pandaGen.freeTemps(promise);
pandaGen.resumeGenerator(node, this.asyncObj);
pandaGen.storeAccumulator(node, this.retVal);
this.handleMode(node);
}
private handleMode(node: ts.Node) {
let pandaGen = this.pandaGen;
let modeType = pandaGen.getTemp();
pandaGen.getResumeMode(node, this.asyncObj);
pandaGen.storeAccumulator(node, modeType);
// .reject
pandaGen.loadAccumulatorInt(node, ResumeMode.Throw);
let notThrowLabel = new Label();
// jump to normal code
pandaGen.condition(node, ts.SyntaxKind.EqualsEqualsToken, modeType, notThrowLabel);
pandaGen.loadAccumulator(node, this.retVal);
pandaGen.throw(node);
pandaGen.freeTemps(modeType);
// .resolve
pandaGen.label(node, notThrowLabel);
pandaGen.loadAccumulator(node, this.retVal);
}
resolve(node: ts.Node | NodeKind, value: VReg) {
let pandaGen = this.pandaGen;
pandaGen.asyncFunctionResolve(node, this.asyncObj, getVregisterCache(pandaGen, CacheList.True), value);
}
cleanUp(node: ts.Node): void {
let pandaGen = this.pandaGen;
pandaGen.label(node, this.endLabel);
// catch
let exception = pandaGen.getTemp();
pandaGen.storeAccumulator(NodeKind.Invalid, exception);
pandaGen.asyncFunctionReject(NodeKind.Invalid, this.asyncObj, getVregisterCache(pandaGen, CacheList.True), exception);
pandaGen.return(NodeKind.Invalid);
pandaGen.freeTemps(exception);
pandaGen.freeTemps(this.asyncObj, this.retVal);
new CatchTable(pandaGen, this.endLabel, new LabelPair(this.beginLabel, this.endLabel));
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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.
*/
import * as ts from "typescript";
import { GeneratorFunctionBuilder } from "./generatorFunctionBuilder";
import { AsyncFunctionBuilder } from "./asyncFunctionBuilder";
export type FunctionBuilderType = AsyncFunctionBuilder | GeneratorFunctionBuilder | FunctionBuilder;
export class FunctionBuilder {
prepare(node: ts.Node): void {
}
cleanUp(node: ts.Node): void {
}
}
@@ -0,0 +1,259 @@
/*
* 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.
*/
import { Scope } from "src/scope";
import ts from "typescript";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { Compiler, ControlFlowChange } from "../compiler";
import {
Label,
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { Recorder } from "../recorder";
import { IteratorRecord, IteratorType, getIteratorRecord } from "../statement/forOfStatement";
enum ResumeMode { Return = 0, Throw, Next };
/**
* function *foo() {
* yield 'a'
* }
*/
export class GeneratorFunctionBuilder {
private pandaGen: PandaGen;
private compiler: Compiler;
private genObj: VReg;
private retVal: VReg;
constructor(pandaGen: PandaGen, compiler: Compiler) {
this.pandaGen = pandaGen;
this.compiler = compiler;
this.genObj = pandaGen.getTemp();
this.retVal = pandaGen.getTemp();
}
prepare(node: ts.Node, recorder: Recorder) {
let pandaGen = this.pandaGen;
let scope = <Scope>recorder.getScopeOfNode(node);
let funcObj = scope.getName2variable().get('4funcObj')!.getVreg();
pandaGen.createGeneratorObj(node, funcObj);
pandaGen.storeAccumulator(node, this.genObj);
pandaGen.suspendGenerator(node, this.genObj, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.resumeGenerator(node, this.genObj);
pandaGen.storeAccumulator(node, this.retVal);
this.handleMode(node);
}
yield(node: ts.Node, value: VReg) {
let pandaGen = this.pandaGen;
let iterRslt = pandaGen.getTemp();
pandaGen.createIterResultObjectDyn(node, value, getVregisterCache(pandaGen, CacheList.False));
pandaGen.storeAccumulator(node, iterRslt);
pandaGen.suspendGenerator(node, this.genObj, iterRslt);
pandaGen.freeTemps(iterRslt);
pandaGen.resumeGenerator(node, this.genObj);
pandaGen.storeAccumulator(node, this.retVal);
this.handleMode(node);
}
yieldStar(expr: ts.YieldExpression) {
let pandaGen = this.pandaGen;
let method = pandaGen.getTemp();
let object = pandaGen.getTemp();
let receivedValue = pandaGen.getTemp();
let modeType = pandaGen.getTemp();
let loopStartLabel = new Label();
let callreturnLabel = new Label();
let callthrowLabel = new Label();
let iteratorCompletionLabel = new Label();
let exitLabel_return = new Label();
let exitLabel_throw = new Label();
let exitLabel_value = new Label();
let exitLabel_TypeError = new Label();
// get innerIterator & iterator.[[Nextmethod]] (spec 4 & 5), support async in the future
let type: IteratorType = IteratorType.Normal;
let iterator: IteratorRecord = getIteratorRecord(pandaGen, expr, method, object, type);
// init receivedValue with Undefined (spec 6)
pandaGen.moveVreg(expr, receivedValue, getVregisterCache(pandaGen, CacheList.undefined));
// init modeType with Next (spec 6)
pandaGen.loadAccumulatorInt(expr, ResumeMode.Next);
pandaGen.storeAccumulator(expr, modeType);
// starts executeing iterator.[[method]] (spec 7)
pandaGen.label(expr, loopStartLabel);
pandaGen.loadAccumulatorInt(expr, ResumeMode.Next);
pandaGen.condition(expr, ts.SyntaxKind.EqualsEqualsToken, modeType, callreturnLabel);
// call next
pandaGen.call(expr, [iterator.getNextMethod(), iterator.getObject(), receivedValue], true);
pandaGen.branch(expr, iteratorCompletionLabel);
// call return
pandaGen.label(expr, callreturnLabel);
pandaGen.loadAccumulatorInt(expr, ResumeMode.Return);
pandaGen.condition(expr, ts.SyntaxKind.EqualsEqualsToken, modeType, callthrowLabel);
pandaGen.loadObjProperty(expr, iterator.getObject(), "return");
pandaGen.storeAccumulator(expr, method);
// whether iterator.[[return]] exists
pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), exitLabel_return);
pandaGen.call(expr, [method, iterator.getObject(), receivedValue], true);
pandaGen.branch(expr, iteratorCompletionLabel);
// no return method
pandaGen.label(expr, exitLabel_return);
// if there are finally blocks, should implement these at first.
this.compiler.compileFinallyBeforeCFC(
undefined,
ControlFlowChange.Break,
undefined
);
// spec 7.c.iii.2 Return Completion(received).
pandaGen.loadAccumulator(expr, receivedValue);
pandaGen.return(expr);
// call throw
pandaGen.label(expr, callthrowLabel);
pandaGen.loadObjProperty(expr, iterator.getObject(), "throw");
pandaGen.storeAccumulator(expr, method);
// whether iterator.[[throw]] exists
pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), exitLabel_throw);
pandaGen.call(expr, [method, iterator.getObject(), receivedValue], true);
pandaGen.branch(expr, iteratorCompletionLabel);
// NOTE: If iterator does not have a throw method, this throw is
// going to terminate the yield* loop. But first we need to give
// iterator a chance to clean up.
pandaGen.label(expr, exitLabel_throw);
pandaGen.loadObjProperty(expr, iterator.getObject(), "return");
pandaGen.storeAccumulator(expr, method);
// whether iterator.[[return]] exists
pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), exitLabel_TypeError);
// [[return]] exists
pandaGen.call(expr, [method, iterator.getObject()], true);
let innerResult = pandaGen.getTemp();
pandaGen.storeAccumulator(expr, innerResult);
pandaGen.throwIfNotObject(expr, innerResult);
pandaGen.freeTemps(innerResult);
pandaGen.label(expr, exitLabel_TypeError);
pandaGen.throwThrowNotExist(expr);
// iteratorCompletion
pandaGen.label(expr, iteratorCompletionLabel);
pandaGen.storeAccumulator(expr, this.retVal);
pandaGen.throwIfNotObject(expr, this.retVal);
pandaGen.loadObjProperty(expr, this.retVal, "done");
pandaGen.toBoolean(expr);
pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsToken, getVregisterCache(pandaGen, CacheList.True), exitLabel_value);
pandaGen.suspendGenerator(expr, this.genObj, this.retVal);
pandaGen.resumeGenerator(expr, this.genObj);
pandaGen.storeAccumulator(expr, receivedValue);
pandaGen.getResumeMode(expr, this.genObj);
pandaGen.storeAccumulator(expr, modeType);
pandaGen.branch(expr, loopStartLabel);
// spec 7.a.v.1/7.b.ii.6.a/7.c.viii Return ? IteratorValue(innerResult).
// Decide if we trigger a return or if the yield* expression should just
// produce a value.
let outputLabel = new Label();
pandaGen.label(expr, exitLabel_value);
pandaGen.loadObjProperty(expr, this.retVal, "value");
let outputResult = pandaGen.getTemp();
pandaGen.storeAccumulator(expr, outputResult);
pandaGen.loadAccumulatorInt(expr, ResumeMode.Return);
pandaGen.condition(expr, ts.SyntaxKind.EqualsEqualsToken, modeType, outputLabel);
this.compiler.compileFinallyBeforeCFC(
undefined,
ControlFlowChange.Break,
undefined
);
pandaGen.loadAccumulator(expr, outputResult);
pandaGen.return(expr);
pandaGen.label(expr, outputLabel);
pandaGen.loadAccumulator(expr, outputResult);
pandaGen.freeTemps(method, object, receivedValue, modeType, outputResult);
}
private handleMode(node: ts.Node) {
let pandaGen = this.pandaGen;
let modeType = pandaGen.getTemp();
pandaGen.getResumeMode(node, this.genObj);
pandaGen.storeAccumulator(node, modeType);
// .return(value)
pandaGen.loadAccumulatorInt(node, ResumeMode.Return);
let notRetLabel = new Label();
pandaGen.condition(node, ts.SyntaxKind.EqualsEqualsToken, modeType, notRetLabel);
// if there are finally blocks, should implement these at first.
this.compiler.compileFinallyBeforeCFC(
undefined,
ControlFlowChange.Break,
undefined
);
pandaGen.loadAccumulator(node, this.retVal);
pandaGen.return(node);
// .throw(value)
pandaGen.label(node, notRetLabel);
pandaGen.loadAccumulatorInt(node, ResumeMode.Throw);
let notThrowLabel = new Label();
pandaGen.condition(node, ts.SyntaxKind.EqualsEqualsToken, modeType, notThrowLabel);
pandaGen.loadAccumulator(node, this.retVal);
pandaGen.throw(node);
pandaGen.freeTemps(modeType);
// .next(value)
pandaGen.label(node, notThrowLabel);
pandaGen.loadAccumulator(node, this.retVal);
}
cleanUp() {
this.pandaGen.freeTemps(this.genObj, this.retVal);
}
}
+107
View File
@@ -0,0 +1,107 @@
/*
* 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.
*/
import * as ts from "typescript";
import { hasExportKeywordModifier, hasDefaultKeywordModifier } from "./base/util";
import { CacheList, getVregisterCache } from "./base/vregisterCache";
import { Compiler } from "./compiler";
import { NodeKind } from "./debuginfo";
import { PandaGen } from "./pandagen";
import { Recorder } from "./recorder";
import {
FuncDecl,
FunctionScope,
GlobalScope,
LocalScope,
ModuleScope,
Scope,
VarDecl,
VariableScope
} from "./scope";
import { LocalVariable } from "./variable";
export function hoisting(rootNode: ts.SourceFile | ts.FunctionLikeDeclaration, pandaGen: PandaGen, recorder: Recorder, compiler: Compiler) {
let variableScope = <VariableScope>recorder.getScopeOfNode(rootNode);
let hoistDecls = recorder.getHoistDeclsOfScope(variableScope);
hoistDecls ?.forEach((decl) => {
if (decl instanceof VarDecl) {
hoistVar(decl, variableScope, pandaGen);
} else if (decl instanceof FuncDecl) {
hoistFunction(decl, variableScope, pandaGen, compiler);
} else {
throw new Error("Wrong declaration type to be hoisted");
}
});
}
export function hoistVar(decl: VarDecl, scope: Scope, pandaGen: PandaGen) {
let name = decl.name;
if (scope instanceof GlobalScope) {
pandaGen.loadAccumulator(decl.node, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.storeGlobalVar(decl.node, name);
} else if (scope instanceof FunctionScope || scope instanceof ModuleScope) {
let v = scope.findLocal(name)!;
pandaGen.loadAccumulator(NodeKind.FirstNodeOfFunction, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.storeAccToLexEnv(NodeKind.FirstNodeOfFunction, scope, 0, v, true);
} else {
throw new Error("Wrong scope to hoist");
}
}
export function hoistFunction(decl: FuncDecl, scope: Scope, pandaGen: PandaGen, compiler: Compiler) {
let funcName = decl.name;
let funcIndex = decl.index;
let internalName = `func_${funcName}_${funcIndex}`;
let env = compiler.getCurrentEnv();
if (scope instanceof GlobalScope) {
pandaGen.defineFunction(NodeKind.FirstNodeOfFunction, <ts.FunctionDeclaration>decl.node, internalName, env);
pandaGen.storeGlobalVar(NodeKind.FirstNodeOfFunction, funcName);
} else if ((scope instanceof FunctionScope) || (scope instanceof LocalScope) || (scope instanceof ModuleScope)) {
let hasExport: boolean = hasExportKeywordModifier(decl.node);
let hasDefault: boolean = hasDefaultKeywordModifier(decl.node);
let v = scope.findLocal(funcName)!;
if (hasExport && scope instanceof ModuleScope) {
(<LocalVariable>v).setExport();
if (hasDefault) {
(<LocalVariable>v).setExportedName("default");
} else {
(<LocalVariable>v).setExportedName(v.getName());
}
}
pandaGen.defineFunction(NodeKind.FirstNodeOfFunction, <ts.FunctionDeclaration>decl.node, internalName, env);
pandaGen.storeAccToLexEnv(NodeKind.FirstNodeOfFunction, scope, 0, v, true);
} else {
throw new Error("Wrong scope to hoist");
}
}
// this function is called when hoisting function inside blocks
export function hoistFunctionInBlock(scope: Scope, pandaGen: PandaGen, strictMode: boolean, compiler: Compiler) {
let decls = scope.getDecls();
let funcToHoist = new Array<FuncDecl>();
for (let i = 0; i < decls.length; i++) {
if (decls[i] instanceof FuncDecl) {
funcToHoist.push(<FuncDecl>decls[i]);
}
}
if (strictMode) {
funcToHoist.forEach(func => {
hoistFunction(func, scope, pandaGen, compiler);
});
}
}
+119
View File
@@ -0,0 +1,119 @@
/*
* 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.
*/
import * as ts from "typescript";
import { CmdOptions } from "./cmdOptions";
import { CompilerDriver } from "./compilerDriver";
import * as diag from "./diagnostic";
import { LOGD, LOGE } from "./log";
import { Pass } from "./pass";
import { CacheExpander } from "./pass/cacheExpander";
import { ICPass } from "./pass/ICPass";
import { IntrinsicVariantExpander } from "./pass/intrinsicVariantExpander";
import { RegAlloc } from "./regAllocator";
import { setGlobalStrict } from "./strictMode";
import jshelpers = require("./jshelpers");
function main(fileNames: string[], options: ts.CompilerOptions) {
let program = ts.createProgram(fileNames, options);
let emitResult = program.emit(
undefined,
undefined,
undefined,
undefined,
{
before: [
(ctx: ts.TransformationContext) => {
return (node: ts.SourceFile) => {
let outputBinName = CmdOptions.getOutputBinName();
let fileName = node.fileName.substring(0, node.fileName.lastIndexOf('.'));
if (fileName != CmdOptions.getInputFileName()) {
outputBinName = fileName + ".abc";
}
let compilerDriver = new CompilerDriver(outputBinName);
setGlobalStrict(jshelpers.isEffectiveStrictModeSourceFile(node, options));
if (CmdOptions.isVariantBytecode()) {
LOGD("variant bytecode dump");
let passes: Pass[] = [
new CacheExpander(),
new ICPass(),
new IntrinsicVariantExpander(),
new RegAlloc()
];
compilerDriver.setCustomPasses(passes);
}
compilerDriver.compile(node);
compilerDriver.showStatistics();
return node;
}
}
]
}
);
let allDiagnostics = ts
.getPreEmitDiagnostics(program)
.concat(emitResult.diagnostics);
allDiagnostics.forEach(diagnostic => {
diag.printDiagnostic(diagnostic);
});
}
namespace Compiler {
export namespace Options {
export let Default: ts.CompilerOptions = {
outDir: "../tmp/build",
allowJs: true,
noEmitOnError: true,
noImplicitAny: true,
target: ts.ScriptTarget.ES2015,
module: ts.ModuleKind.CommonJS,
strictNullChecks: true,
skipLibCheck: true
};
}
}
function run(args: string[], options?: ts.CompilerOptions): void {
let parsed = CmdOptions.parseUserCmd(args);
if (!parsed) {
return;
}
if (options) {
if (!((parsed.options.project) || (parsed.options.build))) {
parsed.options = options;
}
}
try {
main(parsed.fileNames, parsed.options);
} catch (err) {
if (err instanceof diag.DiagnosticError) {
let diagnostic = diag.getDiagnostic(err.code);
if (diagnostic != undefined) {
let diagnosticLog = diag.createDiagnostic(err.file, err.irnode, diagnostic, ...err.args);
diag.printDiagnostic(diagnosticLog);
}
} else if (err instanceof SyntaxError) {
LOGE(err.name, err.message);
} else {
throw err;
}
}
}
run(process.argv.slice(2), Compiler.Options.Default);
global.gc();
+192
View File
@@ -0,0 +1,192 @@
/*
* 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.
*/
import { AssemblyDumper, IntrinsicInfo } from "./assemblyDumper";
import { DebugInfo } from "./debuginfo";
import {
Call,
CallRange,
CallShort,
FldaiDyn,
Imm,
Intrinsic,
IRNode,
LdaiDyn,
LdaStr,
OperandKind,
ResultDst,
ResultType,
StaDyn,
VReg
} from "./irnodes";
import { PandaGen } from "./pandagen";
import { Pass } from "./pass";
export class IntrinsicExpanderInternal {
private temps: VReg[] = [];
getTemp(): VReg {
if (this.temps.length > 0) {
return this.temps.pop()!;
} else {
return new VReg();
}
}
freeTemps(temps: VReg[]) {
this.temps = this.temps.concat(temps);
}
// this method records the intrinsic usage during the whole source code
// it can help dumper to write the intrinsic function declaration in the front of bytecode
intrinsicDeclRec(ins: Intrinsic) {
let intrinsicName = ins.mnemonic;
let argsNum = ins.operands.length;
let resultType: string = "";
if (ins.resultIn() == ResultDst.None) {
resultType = "void";
} else if (ins.resultIn() == ResultDst.Acc) {
resultType = "any";
} else {
throw new Error("resultType of" + ins.resultIn() + "is not implement");
}
let intrinsicInfo = new IntrinsicInfo(intrinsicName, argsNum, resultType);
AssemblyDumper.intrinsicRec.set(ins.mnemonic, intrinsicInfo);
}
// Transforms a synthetic "intrinsic instruction" into an intrinsic function call.
// Returns an array of instructions forming intrinsic call and
// an array of temporary registers used for expansion.
expandInstruction(ins: Intrinsic): [IRNode[], VReg[]] {
let operands = ins.operands;
let formats = ins.formats;
let expansion: IRNode[] = [];
let callArgs: VReg[] = [];
let tempVregs: VReg[] = [];
let intrinsicName = "Ecmascript.Intrinsics." + ins.mnemonic;
// Walk the rest of the arguments.
for (let i = 0; i < operands.length; ++i) {
let format = formats[0];
let kind: OperandKind;
kind = format[i].kind;
let operand = operands[i];
if (kind === OperandKind.SrcVReg) {
callArgs.push(<VReg>operand);
continue;
}
// Imm has to be put into a vreg to be passed to intrinsic.
// for defineFuncDyn
if (kind === OperandKind.Imm) {
let tempImm: VReg = this.getTemp();
let imm = <Imm>operand;
let type = imm.resultType();
if (type == ResultType.Int || type == ResultType.Long) {
expansion.push(new LdaiDyn(imm));
} else if (type == ResultType.Float) {
expansion.push(new FldaiDyn(imm));
} else {
throw new Error("Unexpected result type for an Imm");
}
expansion.push(new StaDyn(tempImm));
callArgs.push(tempImm);
tempVregs.push(tempImm);
continue;
}
// Put id into vreg as a string object.
if (kind === OperandKind.Id) {
let tempId: VReg = this.getTemp();
expansion.push(new LdaStr(<string>operand));
expansion.push(new StaDyn(tempId));
callArgs.push(tempId);
tempVregs.push(tempId);
continue;
}
// For simplicity, intrinsics shall not have destinations other than accumulator.
// Also, no labels are allowed as operands.
if (kind === OperandKind.DstVReg
|| kind === OperandKind.SrcDstVReg
|| ins.resultIn() === ResultDst.VReg) {
throw new Error("Intrinsic " + ins.mnemonic + " has unexpected operand kinds");
} else {
throw new Error("Unknown operand kind for intrinsic " + ins.mnemonic);
}
}
// Call the intrinsic.
switch (callArgs.length) {
case 0:
expansion.push(new CallShort(intrinsicName));
break;
case 1:
expansion.push(new CallShort(intrinsicName, callArgs[0]));
break;
case 2:
expansion.push(new CallShort(intrinsicName, callArgs[0], callArgs[1]));
break;
case 3:
expansion.push(new Call(intrinsicName, callArgs[0], callArgs[1], callArgs[2]));
break;
case 4:
expansion.push(new Call(intrinsicName, callArgs[0], callArgs[1], callArgs[2], callArgs[3]));
break;
default:
expansion.push(new CallRange(intrinsicName, callArgs));
}
return [expansion, tempVregs];
}
run(pg: PandaGen): void {
let insns: IRNode[] = pg.getInsns();
let origTemps: VReg[] = pg.getTemps();
for (let i = 0; i < insns.length; ++i) {
let ins: IRNode = insns[i];
if (ins instanceof Intrinsic) {
// record the intrinsic
if (!AssemblyDumper.intrinsicRec.has(ins.mnemonic)) {
this.intrinsicDeclRec(ins);
}
let [expansion, temps] = this.expandInstruction(ins);
// for debuginfo
DebugInfo.copyDebugInfo(insns[i], expansion);
insns.splice(i, 1, ...expansion);
// Since we put something into the original array, its length changed.
// Skip what we've just added.
let step = expansion.length - 1;
i += step;
this.freeTemps(temps);
}
}
// We need extra registers in the function.
origTemps.push(...this.temps);
}
}
export class IntrinsicExpander implements Pass {
run(pg: PandaGen): void {
let intrinsicExpanderInternal = new IntrinsicExpanderInternal();
intrinsicExpanderInternal.run(pg);
}
}
+74
View File
@@ -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.
*/
export function getSymbol(node: ts.Node): ts.Symbol;
export function tsStringToString(str: ts.__String): string;
export function getTextOfIdentifierOrLiteral(node: ts.Node): string;
export function isJsFile(file: ts.SourceFile): boolean;
export function createEmptyNodeArray<T extends ts.Node>(): ts.NodeArray<T>;
export function getFlowNode(stmt: ts.Statement): ts.Node;
export function bindSourceFile(sourceFile: ts.SourceFile, options: ts.CompilerOptions);
export function createDiagnosticForNode(node: ts.Node, message: ts.DiagnosticMessage, ...args: (string | number | undefined)[]): ts.DiagnosticWithLocation;
export function createCompilerDiagnostic(message: ts.DiagnosticMessage, ...args: (string | number | undefined)[]): ts.Diagnostic;
export function createCompilerDiagnostic(message: ts.DiagnosticMessage, ...args: (string | number | undefined)[]): ts.Diagnostic;
export function createFileDiagnostic(file: ts.SourceFile, start: number, length: number, message: ts.DiagnosticMessage, ...args: (string | number | undefined)[]): ts.DiagnosticWithLocation;
export function isEffectiveStrictModeSourceFile(node: ts.SourceFile, compilerOptions: ts.CompilerOptions): boolean;
export function getErrorSpanForNode(sourceFile: ts.SourceFile, node: ts.Node): ts.TextSpan;
export function getSpanOfTokenAtPosition(sourceFile: ts.SourceFile, pos: number): ts.TextSpan;
export function getContainingClass(node: ts.Node): ts.ClassLikeDeclaration | undefined;
export function declarationNameToString(name: ts.DeclarationName | ts.QualifiedName | undefined);
export function getContainingFunction(node: ts.Node): ts.SignatureDeclaration | undefined;
export function isPrologueDirective(node: ts.Node): node is ts.PrologueDirective;
export function getSourceTextOfNodeFromSourceFile(sourceFile: ts.SourceFile, node: ts.Node, includeTrivia = false): string;
export function isAssignmentTarget(node: ts.Node): boolean;
export function getSourceFileOfNode(node: ts.Node): ts.SourceFile;
export function isIterationStatement(node: ts.Node, lookInLabeledStatements: boolean): node is ts.IterationStatement;
export function getTextOfNode(node: ts.Node, includeTrivia = false): string;
export function nodePosToString(node: ts.Node): string;
export function getContainingFunctionDeclaration(node: ts.Node): ts.FunctionLikeDeclaration | undefined;
export function tokenToString(t: ts.SyntaxKind): string | undefined;
export function getNewTargetContainer(node: ts.Node): ts.Node | undefined;
export function isVarConst(node: ts.VariableDeclaration | ts.VariableDeclarationList): boolean;
export function isLet(node: ts.Node): boolean;
export function nodeCanBeDecorated(node: ts.Node, parent?: ts.Node, grandparent?: ts.Node): boolean;
export function getAllAccessorDeclarations(declarations: readonly ts.Declaration[], accessor: ts.AccessorDeclaration): ts.AllAccessorDeclarations;
export function nodeIsPresent(node: ts.Node | undefined): boolean;
export function modifierToFlag(token: ts.SyntaxKind): ts.ModifierFlags;
export function hasSyntacticModifier(node: ts.Node, flags: ts.ModifierFlags): boolean;
export function isAmbientModule(node: ts.Node): node is ts.AmbientModuleDeclaration;
export function isKeyword(token: ts.SyntaxKind): boolean;
export function getThisContainer(node: ts.Node, includeArrowFunctions: boolean): ts.Node;
export function getEnclosingBlockScopeContainer(node: ts.Node): ts.Node;
export function findAncestor(node: ts.Node | undefined, callback: (element: ts.Node) => boolean | "quit"): ts.Node | undefined;
export function isBlockScope(node: ts.Node, parentNode: ts.Node): boolean;
export function isIdentifierName(node: ts.Identifier): boolean;
export function declarationNameToString(name: ts.DeclarationName | ts.QualifiedName | undefined): string;
export function isInTopLevelContext(node: ts.Node);
export function isExternalOrCommonJsModule(file: ts.SourceFile): boolean;
export function skipParentheses(node: ts.Node): ts.Node;
export function getImmediatelyInvokedFunctionExpression(func: ts.Node): ts.CallExpression | undefined;
export function hasQuestionToken(node: ts.Node);
export function getPropertyNameForPropertyNameNode(name: ts.PropertyName): ts.__String | undefined;
export function isFunctionBlock(node: ts.Node): boolean;
export function isFunctionLike(node: ts.Node): boolean;
export function getSuperContainer(node: ts.Node, stopOnFunctions: boolean): ts.Node;
export function getClassExtendsHeritageElement(node: ts.ClassLikeDeclaration | ts.InterfaceDeclaration);
export function hasStaticModifier(node: ts.Node): boolean;
export function skipOuterExpressions(node: ts.Node, kinds?: ts.OuterExpressionKinds): ts.Node;
export function isSuperCall(n: ts.Node);
export function isThisProperty(node: ts.Node): boolean;
export function isThisIdentifier(node: ts.Node | undefined): boolean;
export function getClassExtendsHeritageElement(node: ts.ClassLikeDeclaration | ts.InterfaceDeclaration);
export function isSuperProperty(node: ts.Node);
+314
View File
@@ -0,0 +1,314 @@
/*
* 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.
*/
const ts = require("typescript");
function getSymbol(node) {
return node.symbol;
}
function tsStringToString(str) {
return "" + str;
}
function getTextOfIdentifierOrLiteral(node) {
return ts.getTextOfIdentifierOrLiteral(node);
}
function isJsFile(file) {
return (file.scriptKind & ts.ScriptKind.JS) != 0;
}
function createEmptyNodeArray() {
return [];
}
function getFlowNode(stmt) {
return stmt.flowNode;
}
function bindSourceFile(sourceFile, options) {
ts.bindSourceFile(sourceFile, options);
}
function createDiagnosticForNode(node, message, ...args) {
return ts.createDiagnosticForNode(node, message, ...args);
}
function createCompilerDiagnostic(message, ...args) {
return ts.createCompilerDiagnostic(message, ...args);
}
function createFileDiagnostic(file, start, length, message, ...args) {
return ts.createFileDiagnostic(file, start, length, message, args);
}
function isEffectiveStrictModeSourceFile(node, compilerOptions) {
return ts.isEffectiveStrictModeSourceFile(node, compilerOptions);
}
function getErrorSpanForNode(sourceFile, node) {
return ts.getErrorSpanForNode(sourceFile, node);
}
function getSpanOfTokenAtPosition(sourceFile, pos) {
return ts.getSpanOfTokenAtPosition(sourceFile, pos);
}
function getContainingClass(node) {
return ts.getContainingClass(node);
}
function declarationNameToString(node) {
return ts.declarationNameToString(node);
}
function getContainingFunction(node) {
return ts.getContainingFunction(node);
}
function isPrologueDirective(node) {
return ts.isPrologueDirective(node);
}
function getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia) {
return ts.getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia);
}
function isAssignmentTarget(node) {
return ts.isAssignmentTarget(node);
}
function getSourceFileOfNode(node) {
return ts.getSourceFileOfNode(node);
}
function isIterationStatement(node, lookInLabeledStatements) {
return ts.isIterationStatement(node, lookInLabeledStatements);
}
function getTextOfNode(node, includeTrivia) {
return ts.getTextOfNode(node, includeTrivia);
}
function getContainingClass(node) {
return ts.getContainingClass(node);
}
function nodePosToString(node) {
return ts.nodePosToString(node);
}
function getContainingFunctionDeclaration(node) {
return ts.getContainingFunctionDeclaration(node);
}
function tokenToString(t) {
return ts.tokenToString(t);
}
function getNewTargetContainer(node) {
return ts.getNewTargetContainer(node);
}
function isVarConst(node) {
return ts.isVarConst(node);
}
function isLet(node) {
return ts.isLet(node);
}
function nodeCanBeDecorated(node) {
return ts.nodeCanBeDecorated(node);
}
function nodeIsPresent(node) {
return ts.nodeIsPresent(node);
}
function getAllAccessorDeclarations(declarations, accessor) {
return ts.getAllAccessorDeclarations(declarations, accessor);
}
function modifierToFlag(token) {
return ts.modifierToFlag(token);
}
function hasSyntacticModifier(node, flag) {
return ts.hasSyntacticModifier(node, flag);
}
function isAmbientModule(node) {
return ts.isAmbientModule(node);
}
function isKeyword(node) {
return ts.isKeyword(node);
}
function getThisContainer(node) {
return ts.getThisContainer(node);
}
function getEnclosingBlockScopeContainer(node) {
return ts.getEnclosingBlockScopeContainer(node);
}
function findAncestor(node, callback) {
return ts.findAncestor(node, callback);
}
function isBlockScope(node, parentNode) {
return ts.isBlockScope(node, parentNode);
}
function isIdentifierName(node) {
return ts.isIdentifierName(node);
}
function declarationNameToString(node) {
return ts.declarationNameToString(node);
}
function isInTopLevelContext(node) {
return ts.isInTopLevelContext(node);
}
function isExternalOrCommonJsModule(node) {
return ts.isExternalOrCommonJsModule(node);
}
function skipParentheses(node) {
return ts.skipParentheses(node);
}
function getImmediatelyInvokedFunctionExpression(node) {
return ts.getImmediatelyInvokedFunctionExpression(node);
}
function hasQuestionToken(node) {
return ts.hasQuestionToken(node);
}
function getPropertyNameForPropertyNameNode(name) {
return ts.getPropertyNameForPropertyNameNode(name);
}
function isFunctionBlock(node) {
return ts.isFunctionBlock(node);
}
function isFunctionLike(node) {
return ts.isFunctionLike(node);
}
function getSuperContainer(node, stopOnFunctions) {
return ts.getSuperContainer(node, stopOnFunctions);
}
function getClassExtendsHeritageElement(node) {
return ts.getClassExtendsHeritageElement(node);
}
function hasStaticModifier(node) {
return ts.hasStaticModifier(node);
}
function skipOuterExpressions(node, kinds) {
return ts.skipOuterExpressions(node, kinds);
}
function isSuperCall(node) {
return ts.isSuperCall(node);
}
function isThisIdentifier(node) {
return ts.isThisIdentifier(node);
}
function isThisProperty(node) {
return ts.isThisProperty(node);
}
function isSuperProperty(node) {
return ts.isSuperProperty(node);
}
function getClassExtendsHeritageElement(node) {
return ts.getClassExtendsHeritageElement(node);
}
module.exports = {
getSymbol: getSymbol,
tsStringToString: tsStringToString,
getTextOfIdentifierOrLiteral: getTextOfIdentifierOrLiteral,
isJsFile: isJsFile,
createEmptyNodeArray: createEmptyNodeArray,
getFlowNode: getFlowNode,
bindSourceFile: bindSourceFile,
createDiagnosticForNode: createDiagnosticForNode,
createCompilerDiagnostic: createCompilerDiagnostic,
createFileDiagnostic: createFileDiagnostic,
isEffectiveStrictModeSourceFile: isEffectiveStrictModeSourceFile,
getErrorSpanForNode: getErrorSpanForNode,
getSpanOfTokenAtPosition: getSpanOfTokenAtPosition,
getContainingClass: getContainingClass,
declarationNameToString: declarationNameToString,
getContainingFunction: getContainingFunction,
isPrologueDirective: isPrologueDirective,
getSourceTextOfNodeFromSourceFile: getSourceTextOfNodeFromSourceFile,
isAssignmentTarget: isAssignmentTarget,
getSourceFileOfNode: getSourceFileOfNode,
isIterationStatement: isIterationStatement,
getTextOfNode: getTextOfNode,
getContainingClass: getContainingClass,
nodePosToString: nodePosToString,
getContainingFunctionDeclaration: getContainingFunctionDeclaration,
tokenToString: tokenToString,
getNewTargetContainer: getNewTargetContainer,
isLet: isLet,
isVarConst: isVarConst,
nodeCanBeDecorated: nodeCanBeDecorated,
nodeIsPresent: nodeIsPresent,
getAllAccessorDeclarations: getAllAccessorDeclarations,
modifierToFlag: modifierToFlag,
hasSyntacticModifier: hasSyntacticModifier,
isAmbientModule: isAmbientModule,
isKeyword: isKeyword,
getThisContainer: getThisContainer,
getEnclosingBlockScopeContainer: getEnclosingBlockScopeContainer,
findAncestor: findAncestor,
isBlockScope: isBlockScope,
isIdentifierName: isIdentifierName,
declarationNameToString: declarationNameToString,
isInTopLevelContext: isInTopLevelContext,
isExternalOrCommonJsModule: isExternalOrCommonJsModule,
skipParentheses: skipParentheses,
getImmediatelyInvokedFunctionExpression: getImmediatelyInvokedFunctionExpression,
hasQuestionToken: hasQuestionToken,
getPropertyNameForPropertyNameNode: getPropertyNameForPropertyNameNode,
isFunctionBlock: isFunctionBlock,
isFunctionLike: isFunctionLike,
getSuperContainer: getSuperContainer,
getClassExtendsHeritageElement: getClassExtendsHeritageElement,
hasStaticModifier: hasStaticModifier,
skipOuterExpressions: skipOuterExpressions,
isSuperCall: isSuperCall,
isThisIdentifier: isThisIdentifier,
isThisProperty: isThisProperty,
isSuperProperty: isSuperProperty,
getClassExtendsHeritageElement: getClassExtendsHeritageElement,
};
+246
View File
@@ -0,0 +1,246 @@
/*
* 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.
*/
import ts from "typescript";
import {
loadAccumulator,
loadAccumulatorString,
loadLexicalVar,
storeAccumulator,
storeLexicalVar,
storeModuleVariable,
throwConstAssignment,
throwUndefinedIfHole
} from "./base/bcGenUtil";
import { CacheList, getVregisterCache } from "./base/vregisterCache";
import { Compiler } from "./compiler";
import { NodeKind } from "./debuginfo";
import {
IRNode,
VReg
} from "./irnodes";
import { PandaGen } from "./pandagen";
import { Scope } from "./scope";
import {
LocalVariable,
ModuleVariable,
Variable
} from "./variable";
import jshelpers from "./jshelpers";
abstract class VariableAccessBase {
variable: Variable;
scope: Scope;
level: number;
constructor(scope: Scope, level: number, variable: Variable) {
this.variable = variable;
this.scope = scope;
this.level = level;
}
isLexVar() {
return this.variable.isLexVar;
}
getEnvSlotOfVar(): number | undefined {
if (this.isLexVar()) {
return this.variable.idxLex;
}
return undefined;
}
abstract expand(pandaGen: PandaGen, compiler: Compiler): Array<IRNode>;
}
export class VariableAccessLoad extends VariableAccessBase {
constructor(scope: Scope, level: number, variable: Variable) {
super(scope, level, variable);
}
expand(pandaGen: PandaGen): Array<IRNode> {
if (this.isLexVar()) {
return this.loadLexEnvVar(pandaGen);
} else {
return this.loadLocalVar(pandaGen);
}
}
private loadLocalVar(pandaGen: PandaGen): Array<IRNode> {
let insns: Array<IRNode> = new Array<IRNode>();
let v = this.variable;
let bindVreg = pandaGen.getVregForVariable(v);
// check TDZ first
if (!(<LocalVariable>v).isInitialized()) {
let holeReg = pandaGen.getTemp();
insns.push(loadAccumulator(getVregisterCache(pandaGen, CacheList.HOLE)));
insns.push(storeAccumulator(holeReg));
checkTDZ(pandaGen, holeReg, v.getName(), insns);
pandaGen.freeTemps(holeReg);
return insns;
}
insns.push(loadAccumulator(bindVreg));
return insns;
}
private loadLexEnvVar(pandaGen: PandaGen): Array<IRNode> {
let insns: Array<IRNode> = new Array<IRNode>();
let v = this.variable;
let slot = v.idxLex;
insns.push(loadLexicalVar(this.level, slot));
// check TDZ
if (v.isLetOrConst()) {
let tempReg = pandaGen.getTemp();
insns.push(storeAccumulator(tempReg));
checkTDZ(pandaGen, tempReg, v.getName(), insns);
insns.push(loadAccumulator(tempReg));
pandaGen.freeTemps(tempReg);
}
return insns;
}
}
export class VariableAcessStore extends VariableAccessBase {
node: ts.Node | NodeKind;
isDeclaration: boolean;
constructor(scope: Scope, level: number, variable: Variable, isDeclaration: boolean, node: ts.Node | NodeKind) {
super(scope, level, variable);
this.isDeclaration = isDeclaration;
this.node = node;
}
expand(pandaGen: PandaGen): Array<IRNode> {
if (this.isLexVar()) {
return this.storeLexEnvVar(pandaGen);
} else {
return this.storeLocalVar(pandaGen);
}
}
private storeLocalVar(pandaGen: PandaGen): Array<IRNode> {
let insns: Array<IRNode> = new Array<IRNode>();
let v = <LocalVariable>this.variable;
let bindVreg = pandaGen.getVregForVariable(v);
if (!this.isDeclaration) {
// check TDZ first
if (!v.isInitialized()) {
let nameReg = pandaGen.getTemp();
let tempReg = pandaGen.getTemp();
let holeReg = pandaGen.getTemp();
insns.push(storeAccumulator(tempReg));
insns.push(loadAccumulator(getVregisterCache(pandaGen, CacheList.HOLE)));
insns.push(storeAccumulator(holeReg));
checkTDZ(pandaGen, holeReg, v.getName(), insns);
insns.push(loadAccumulator(tempReg));
pandaGen.freeTemps(nameReg, tempReg, holeReg);
}
// check const assignment
checkConstAssignment(pandaGen, v, insns, this.node);
}
insns.push(storeAccumulator(bindVreg));
if (v.isExportVar() && !(v instanceof ModuleVariable)) {
insns.push(storeModuleVariable(v.getExportedName()));
}
return insns;
}
private storeLexEnvVar(pandaGen: PandaGen): Array<IRNode> {
let insns: Array<IRNode> = new Array<IRNode>();
let v = <LocalVariable>this.variable;
// save the value first
let valueReg: VReg = pandaGen.getTemp();
insns.push(storeAccumulator(valueReg));
let slot = v.idxLex;
if (v.isLetOrConst() || v.isClass()) {
if (!this.isDeclaration) {
let holeReg = pandaGen.getTemp();
/**
* check TDZ first
* If acc == hole -> throw reference error
* else -> excute the next insn
*/
insns.push(loadLexicalVar(this.level, slot));
insns.push(storeAccumulator(holeReg));
checkTDZ(pandaGen, holeReg, v.getName(), insns);
// const assignment check need to be down after TDZ check
checkConstAssignment(pandaGen, v, insns, this.node);
pandaGen.freeTemps(holeReg);
}
}
insns.push(storeLexicalVar(this.level, slot, valueReg));
insns.push(loadAccumulator(valueReg));
if (v.isExportVar() && !(v instanceof ModuleVariable)) {
insns.push(storeModuleVariable(v.getExportedName()));
}
pandaGen.freeTemps(valueReg);
return insns;
}
}
function checkTDZ(pg: PandaGen, holeReg: VReg, name: string, expansion: IRNode[]) {
let nameReg = pg.getTemp();
expansion.push(loadAccumulatorString(name));
expansion.push(storeAccumulator(nameReg));
expansion.push(throwUndefinedIfHole(holeReg, nameReg));
pg.freeTemps(nameReg);
}
function checkConstAssignment(pg: PandaGen, v: Variable, expansion: IRNode[], node: ts.Node | NodeKind) {
let nameReg = pg.getTemp();
if (v.isConst()) {
expansion.push(loadAccumulatorString(v.getName()));
expansion.push(storeAccumulator(nameReg));
expansion.push(throwConstAssignment(nameReg));
}
if (v.isClass() && node != NodeKind.FirstNodeOfFunction &&
node != NodeKind.Invalid && node != NodeKind.Normal) {
let className = v.getName();
while (node) {
if (ts.isClassLike(node) && node.name &&
jshelpers.getTextOfIdentifierOrLiteral(node.name) == className) {
break;
}
node = node.parent;
}
// class name binding inside class is immutable
if (node) {
expansion.push(loadAccumulatorString(className));
expansion.push(storeAccumulator(nameReg));
expansion.push(throwConstAssignment(nameReg));
}
}
pg.freeTemps(nameReg);
}
+35
View File
@@ -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.
*/
// singleton to print debug logs
import { CmdOptions } from "./cmdOptions";
export function LOGD(tag: any, ...args: any[]) {
if (CmdOptions.isEnableDebugLog()) {
if (tag) {
console.log(tag + ": " + args);
} else {
console.log(args);
}
}
}
export function LOGE(tag: any, ...args: any[]) {
if (tag) {
console.error(tag + ": " + args);
} else {
console.error(args);
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* 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.
*/
import * as ts from "typescript";
import { PandaGen } from "./pandagen";
import jshelpers from "./jshelpers";
import { LocalVariable, ModuleVariable } from "./variable";
import { DiagnosticCode, DiagnosticError } from "./diagnostic";
import { ModuleScope } from "./scope";
import { Compiler } from "./compiler";
export class ModuleStmt {
private node: ts.Node
private moduleRequest: string;
private namespace: string = "";
private bingdingNameMap: Map<string, string> = new Map<string, string>();
private isCopy: boolean = true;
constructor(node: ts.Node, moduleRequest: string = "") {
this.node = node;
this.moduleRequest = moduleRequest;
}
getNode() {
return this.node;
}
getModuleRequest() {
return this.moduleRequest;
}
addLocalName(localName: string, importName: string) {
if (this.bingdingNameMap.has(localName)) {
throw new DiagnosticError(this.node, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(this.node), [localName]);
}
this.bingdingNameMap.set(localName, importName);
}
getBindingNameMap() {
return this.bingdingNameMap;
}
setNameSpace(namespace: string) {
this.namespace = namespace;
}
getNameSpace() {
return this.namespace;
}
setCopyFlag(isCopy: boolean) {
this.isCopy = isCopy;
}
getCopyFlag() {
return this.isCopy;
}
}
export function setImport(importStmts: Array<ModuleStmt>, moduleScope: ModuleScope, pandagen: PandaGen, compiler: Compiler) {
importStmts.forEach((importStmt) => {
pandagen.importModule(importStmt.getNode(), importStmt.getModuleRequest());
let moduleReg = pandagen.allocLocalVreg();
pandagen.storeAccumulator(importStmt.getNode(), moduleReg);
if (importStmt.getNameSpace()) {
let v = moduleScope.findLocal(importStmt.getNameSpace())!;
pandagen.storeAccToLexEnv(importStmt.getNode(), moduleScope, 0, v, true);
(<LocalVariable>v).initialize();
}
let bindingNameMap = importStmt.getBindingNameMap();
bindingNameMap.forEach((value: string, key: string) => {
let v = <ModuleVariable>moduleScope.findLocal(key)!;
v.bindModuleVreg(moduleReg);
v.setExoticName(value);
});
})
}
export function setExportBinding(exportStmts: Array<ModuleStmt>, moduleScope: ModuleScope, pandagen: PandaGen) {
exportStmts.forEach((exportStmt) => {
if (exportStmt.getModuleRequest()) {
pandagen.importModule(exportStmt.getNode(), exportStmt.getModuleRequest());
let moduleReg = pandagen.allocLocalVreg();
pandagen.storeAccumulator(exportStmt.getNode(), moduleReg);
if (!exportStmt.getCopyFlag()) {
if (exportStmt.getNameSpace()) {
pandagen.storeModuleVar(exportStmt.getNode(), exportStmt.getNameSpace());
}
let bindingNameMap = exportStmt.getBindingNameMap();
bindingNameMap.forEach((value: string, key: string) => {
pandagen.loadModuleVariable(exportStmt.getNode(), moduleReg, value);
pandagen.storeModuleVar(exportStmt.getNode(), key);
});
} else {
pandagen.copyModule(exportStmt.getNode(), moduleReg);
}
} else {
let bindingNameMap = exportStmt.getBindingNameMap();
bindingNameMap.forEach((value: string, key: string) => {
let v = moduleScope.findLocal(value);
if (typeof v == 'undefined') {
throw new DiagnosticError(exportStmt.getNode(), DiagnosticCode.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, jshelpers.getSourceFileOfNode(exportStmt.getNode()), [value]);
}
if (v instanceof ModuleVariable) {
pandagen.loadModuleVariable(exportStmt.getNode(), v.getModule(), v.getName());
pandagen.storeModuleVar(exportStmt.getNode(), key);
} else {
(<LocalVariable>v).setExport();
(<LocalVariable>v).setExportedName(key);
}
});
}
})
}
File diff suppressed because it is too large Load Diff
+180
View File
@@ -0,0 +1,180 @@
/*
* 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.
*/
import { DebugPosInfo, VariableDebugInfo } from "./debuginfo";
import { LiteralBuffer } from "./base/literal";
export class Metadata {
public attribute: string;
constructor(
attribute: string = ""
) {
this.attribute = attribute;
}
}
export class Signature {
public params: number;
public retType: string | undefined; // return type is always 'any', so we ignore it in json
constructor(params: number = 0, retType?: string | undefined) {
this.params = params;
this.retType = retType;
}
}
export class Ins {
public op: string;
public regs: Array<number> | undefined;
public ids: Array<string> | undefined;
public imms: Array<number> | undefined;
public label: string | undefined;
public debug_pos_info: DebugPosInfo | undefined;
constructor(
op: string,
regs: Array<number> | undefined = undefined,
ids: Array<string> | undefined = undefined,
imms: Array<number> | undefined = undefined,
label: string | undefined = undefined,
debug_pos_info: DebugPosInfo | undefined = undefined,
) {
this.op = op;
this.regs = regs;
this.ids = ids;
this.imms = imms;
this.label = label;
this.debug_pos_info = debug_pos_info;
}
}
export class Function {
public name: string;
public signature: Signature;
public regs_num: number;
public ins: Array<Ins>;
public labels: Array<string>;
public metadata: Metadata;
public catchTables: Array<CatchTable>;
public variables: Array<VariableDebugInfo> | undefined;
public sourceFile: string;
public sourceCode: string | undefined;
public icSize: number;
public parameterLength: number;
public funcName: string;
constructor(
name: string,
signature: Signature,
regs_num: number = 0,
ins: Array<Ins> = [],
labels: Array<string> = [],
variables: Array<VariableDebugInfo> | undefined = undefined,
sourceFile: string = "",
sourceCode: string | undefined = undefined,
icSize: number = 0,
parameterLength: number = 0,
funcName: string = ""
) {
this.name = name;
this.signature = signature;
this.ins = ins;
this.labels = labels;
this.regs_num = regs_num;
this.metadata = new Metadata();
this.catchTables = [];
this.variables = variables;
this.sourceFile = sourceFile;
this.sourceCode = sourceCode;
this.icSize = icSize;
this.parameterLength = parameterLength;
this.funcName = funcName;
}
}
export class Record {
public name: string;
public whole_line: string;
public bound_left: number;
public bound_right: number;
public line_number: number;
public metadata: Metadata;
constructor(
name: string,
whole_line: string,
bound_left: number,
bound_right: number,
line_number: number
) {
this.name = name;
this.whole_line = whole_line;
this.bound_left = bound_left;
this.bound_right = bound_right;
this.line_number = line_number;
this.metadata = new Metadata();
}
}
export class Program {
public functions: Array<Function>;
public records: Array<Record>;
public strings: Set<string>;
public strings_arr: Array<string>;
public literalArrays: Array<LiteralBuffer>;
public module_mode: boolean;
public debug_mode: boolean;
public log_enabled: boolean;
public opt_level: number;
public opt_log_level: string;
constructor() {
this.functions = [];
this.records = [];
this.strings = new Set();
this.strings_arr = [];
this.literalArrays = [];
this.module_mode = false;
this.debug_mode = false;
this.log_enabled = false;
this.opt_level = 1;
this.opt_log_level = "error";
}
finalize(): void {
this.strings_arr = Array.from(this.strings);
}
}
export class CatchTable {
public tryBeginLabel: string;
public tryEndLabel: string;
public catchBeginLabel: string;
constructor(
tryBeginLabel: string,
tryEndLabel: string,
catchBeginLabel: string
) {
this.tryBeginLabel = tryBeginLabel;
this.tryEndLabel = tryEndLabel;
this.catchBeginLabel = catchBeginLabel;
}
}
export interface Emmiter {
generate_program: (filename: string, program: Program) => string;
}
+20
View File
@@ -0,0 +1,20 @@
/*
* 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.
*/
import { PandaGen } from "./pandagen";
export interface Pass {
run(pandaGen: PandaGen): void;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* 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.
*/
import {
Intrinsic, IRNode
} from "../irnodes";
import { LOGE } from "../log";
import { PandaGen } from "../pandagen";
import { Pass } from "../pass";
class ICPassImpl {
constructor() { }
run(pg: PandaGen): void {
let insns: IRNode[] = pg.getInsns();
let icSize: number = 0;
for (let i = 0; i < insns.length; ++i) {
if (!(insns[i] instanceof Intrinsic)) {
continue;
}
let ins: Intrinsic = <Intrinsic>(insns[i]);
if (!ins.hasIC()) {
continue;
}
icSize = ins.updateICOffset(icSize);
}
if (icSize >= 0xFFFF) {
LOGE("ICPass: <" + pg.internalName + "> slot size overflow! total:" + icSize);
}
pg.setICSize(icSize);
}
}
export class ICPass implements Pass {
run(pg: PandaGen): void {
let icPass = new ICPassImpl();
icPass.run(pg);
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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.
*/
import {
CacheList
} from "../base/vregisterCache";
import {
IRNode
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { Pass } from "../pass";
export class CacheExpander implements Pass {
run(pandaGen: PandaGen): void {
let insns: IRNode[] = pandaGen.getInsns();
let cache = pandaGen.getVregisterCache();
for (let i = CacheList.MIN; i < CacheList.MAX; i++) {
let item = cache.getCache(i);
if (item.isNeeded()) {
let expander = item.getExpander();
let expansion = expander(pandaGen);
insns.splice(0, 0, ...expansion);
}
}
}
}
@@ -0,0 +1,173 @@
/*
* 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.
*/
import { AssemblyDumper, IntrinsicInfo } from "../assemblyDumper";
import { BuiltinExpander } from "../builtinsMap";
import { DebugInfo } from "../debuginfo";
import {
FldaiDyn,
Imm,
Intrinsic,
IRNode,
IRNodeKind,
LdaiDyn,
LdaStr,
OperandKind,
ResultDst,
ResultType,
StaDyn,
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { Pass } from "../pass";
class ExpanderInternal {
private temps: VReg[] = [];
getTemp(): VReg {
if (this.temps.length > 0) {
return this.temps.pop()!;
} else {
return new VReg();
}
}
freeTemps(temps: VReg[]) {
this.temps = this.temps.concat(temps);
}
// this method records the intrinsic usage during the whole source code
// it can help dumper to write the intrinsic function declaration in the front of bytecode
intrinsicDeclRec(ins: Intrinsic) {
let intrinsicName = ins.mnemonic;
let argsNum = ins.operands.length;
let resultType: string = "";
if (ins.resultIn() == ResultDst.None) {
resultType = "void";
} else if (ins.resultIn() == ResultDst.Acc) {
resultType = "any";
} else {
throw new Error("resultType of" + ins.resultIn() + "is not implement");
}
let intrinsicInfo = new IntrinsicInfo(intrinsicName, argsNum, resultType);
AssemblyDumper.intrinsicRec.set(ins.mnemonic, intrinsicInfo);
}
// Transforms a synthetic "intrinsic instruction" into an intrinsic function call.
// Returns an array of instructions forming intrinsic call and
// an array of temporary registers used for expansion.
expandInstruction(ins: Intrinsic): [IRNode[], VReg[]] {
let operands = ins.operands;
let formats = ins.formats;
let expansion: IRNode[] = [];
let callArgs: VReg[] = [];
let tempVregs: VReg[] = [];
let format = formats[0];
        if (ins.kind == IRNodeKind.DEFINE_GLOBAL_VAR) {
for (let i = 0; i < format.length; ++i) {
let kind: OperandKind;
kind = format[i].kind;
let operand = operands[i];
if (kind === OperandKind.SrcVReg) {
callArgs.push(<VReg>operand);
continue;
}
// Imm has to be put into a vreg to be passed to intrinsic.
// for defineFuncDyn
if (kind === OperandKind.Imm) {
let tempImm: VReg = this.getTemp();
let imm = <Imm>operand;
let type = imm.resultType();
if (type == ResultType.Int || type == ResultType.Long) {
expansion.push(new LdaiDyn(imm));
expansion.push(new StaDyn(tempImm));
} else if (type == ResultType.Float) {
expansion.push(new FldaiDyn(imm));
expansion.push(new StaDyn(tempImm));
} else {
throw new Error("Unexpected result type for an Imm");
}
callArgs.push(tempImm);
tempVregs.push(tempImm);
continue;
}
// Put id into vreg as a string object.
if (kind === OperandKind.Id) {
let tempId: VReg = this.getTemp();
expansion.push(new LdaStr(<string>operand));
expansion.push(new StaDyn(tempId));
callArgs.push(tempId);
tempVregs.push(tempId);
continue;
}
// For simplicity, intrinsics shall not have destinations other than accumulator.
// Also, no labels are allowed as operands.
if (kind === OperandKind.DstVReg
|| kind === OperandKind.SrcDstVReg
|| ins.resultIn() === ResultDst.VReg) {
throw new Error("Intrinsic " + ins.mnemonic + " has unexpected operand kinds");
} else {
throw new Error("Unknown operand kind for intrinsic " + ins.mnemonic);
}
}
expansion.push(BuiltinExpander.expand2Builtin(ins, callArgs));
} else {
expansion.push(BuiltinExpander.expand2Builtin(ins, ins.operands));
}
return [expansion, tempVregs];
}
run(pg: PandaGen): void {
let insns: IRNode[] = pg.getInsns();
let origTemps: VReg[] = pg.getTemps();
for (let i = 0; i < insns.length; ++i) {
let ins: IRNode = insns[i];
if (ins instanceof Intrinsic) {
// record the intrinsic
if (!AssemblyDumper.intrinsicRec.has(ins.mnemonic)) {
this.intrinsicDeclRec(ins);
}
let [expansion, temps] = this.expandInstruction(ins);
// for debuginfo
DebugInfo.copyDebugInfo(insns[i], expansion);
insns.splice(i, 1, ...expansion);
// Since we put something into the original array, its length changed.
// Skip what we've just added.
let step = expansion.length - 1;
i += step;
this.freeTemps(temps);
}
}
// We need extra registers in the function.
origTemps.push(...this.temps);
}
}
export class IntrinsicVariantExpander implements Pass {
run(pg: PandaGen): void {
let intrinsicExpanderInternal = new ExpanderInternal();
intrinsicExpanderInternal.run(pg);
}
}
+555
View File
@@ -0,0 +1,555 @@
/*
* 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.
*/
import ts from "typescript";
import * as astutils from "./astutils";
import { isAnonymousFunctionDefinition } from "./base/util";
import { CmdOptions } from "./cmdOptions";
import { CompilerDriver } from "./compilerDriver";
import { DiagnosticCode, DiagnosticError } from "./diagnostic";
import { findOuterNodeOfParenthesis } from "./expression/parenthesizedExpression";
import * as jshelpers from "./jshelpers";
import { LOGD } from "./log";
import { ModuleStmt } from "./modules";
import {
CatchParameter,
ClassDecl,
ConstDecl,
Decl,
FuncDecl,
FunctionParameter,
FunctionScope,
GlobalScope,
LetDecl,
LocalScope,
LoopScope,
ModDecl,
ModuleScope,
Scope,
VarDecl,
VariableScope
} from "./scope";
import {
AddCtor2Class,
isContainConstruct,
getClassNameForConstructor
} from "./statement/classStatement";
import { checkSyntaxError } from "./syntaxChecker";
import { isGlobalIdentifier } from "./syntaxCheckHelper";
import { VarDeclarationKind } from "./variable";
export class Recorder {
node: ts.Node;
scope: Scope;
compilerDriver: CompilerDriver;
private scopeMap: Map<ts.Node, Scope> = new Map<ts.Node, Scope>();
private hoistMap: Map<Scope, Decl[]> = new Map<Scope, Decl[]>();
private parametersMap: Map<ts.FunctionLikeDeclaration, FunctionParameter[]> = new Map<ts.FunctionLikeDeclaration, FunctionParameter[]>();
private ClassGroupOfNoCtor: Array<ts.ClassLikeDeclaration> = new Array<ts.ClassLikeDeclaration>();
private importStmts: Array<ModuleStmt> = [];
private exportStmts: Array<ModuleStmt> = [];
private defaultUsed: boolean = false;
constructor(node: ts.Node, scope: Scope, compilerDriver: CompilerDriver) {
this.node = node;
this.scope = scope;
this.compilerDriver = compilerDriver;
}
record() {
this.setScopeMap(this.node, this.scope);
this.recordInfo(this.node, this.scope);
return this.node;
}
getClassGroupOfNoCtor() {
return this.ClassGroupOfNoCtor;
}
private recordInfo(node: ts.Node, scope: Scope) {
node.forEachChild(childNode => {
checkSyntaxError(childNode);
switch (childNode.kind) {
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.ArrowFunction: {
this.compilerDriver.getFuncId(<ts.FunctionLikeDeclaration>childNode);
let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode);
this.recordFuncInfo(<ts.FunctionLikeDeclaration>childNode);
this.recordInfo(childNode, functionScope);
break;
}
case ts.SyntaxKind.FunctionDeclaration: {
this.compilerDriver.getFuncId(<ts.FunctionDeclaration>childNode);
let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode);
this.recordFuncDecl(<ts.FunctionDeclaration>childNode, scope);
this.recordInfo(childNode, functionScope);
break;
}
case ts.SyntaxKind.Block:
case ts.SyntaxKind.IfStatement:
case ts.SyntaxKind.SwitchStatement:
case ts.SyntaxKind.LabeledStatement:
case ts.SyntaxKind.ThrowStatement:
case ts.SyntaxKind.TryStatement:
case ts.SyntaxKind.CatchClause: {
let localScope = new LocalScope(scope);
this.setScopeMap(childNode, localScope);
this.recordInfo(childNode, localScope);
break;
}
case ts.SyntaxKind.DoStatement:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.ForOfStatement: {
let loopScope: LoopScope = new LoopScope(scope);;
this.setScopeMap(childNode, loopScope);
this.recordInfo(childNode, loopScope);
break;
}
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression: {
this.recordClassInfo(<ts.ClassLikeDeclaration>childNode, scope);
break;
}
case ts.SyntaxKind.Identifier: {
this.recordVariableDecl(<ts.Identifier>childNode, scope);
break;
}
case ts.SyntaxKind.ImportDeclaration: {
if (!CmdOptions.isModules()) {
throw new DiagnosticError(childNode, DiagnosticCode.An_import_declaration_can_only_be_used_in_a_namespace_or_module, jshelpers.getSourceFileOfNode(childNode));
}
if (!(scope instanceof ModuleScope)) {
throw new Error("SyntaxError: import statement cannot in other scope except ModuleScope");
}
this.recordImportInfo(<ts.ImportDeclaration>childNode, scope);
break;
}
case ts.SyntaxKind.ExportDeclaration: {
if (!CmdOptions.isModules()) {
throw new DiagnosticError(childNode, DiagnosticCode.An_export_declaration_can_only_be_used_in_a_module, jshelpers.getSourceFileOfNode(childNode));
}
if (!(scope instanceof ModuleScope)) {
throw new Error("SyntaxError: export statement cannot in other scope except ModuleScope");
}
this.recordExportInfo(<ts.ExportDeclaration>childNode);
break;
}
case ts.SyntaxKind.ExportAssignment: {
if (this.defaultUsed) {
throw new DiagnosticError(childNode, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(childNode), ["default"]);
}
this.defaultUsed = true;
this.recordInfo(childNode, scope);
break;
}
default:
this.recordInfo(childNode, scope);
}
});
}
private recordClassInfo(childNode: ts.ClassLikeDeclaration, scope: Scope) {
let localScope = new LocalScope(scope);
this.setScopeMap(childNode, localScope);
if (!isContainConstruct(childNode)) {
AddCtor2Class(this, childNode, localScope);
}
if (childNode.name) {
let name = jshelpers.getTextOfIdentifierOrLiteral(childNode.name);
let calssDecl = new ClassDecl(name, childNode, this.compilerDriver.getFuncId(childNode));
scope.setDecls(calssDecl);
}
this.recordInfo(childNode, localScope);
}
buildVariableScope(curScope: Scope, node: ts.FunctionLikeDeclaration) {
let functionScope = new FunctionScope(curScope, <ts.FunctionLikeDeclaration>node);
let parentVariableScope = <VariableScope>curScope.getNearestVariableScope();
functionScope.setParentVariableScope(parentVariableScope);
parentVariableScope.addChildVariableScope(functionScope);
this.setScopeMap(node, functionScope);
return functionScope;
}
private recordVariableDecl(id: ts.Identifier, scope: Scope) {
let name = jshelpers.getTextOfIdentifierOrLiteral(id);
let parent = this.getDeclarationNodeOfId(id);
if (parent) {
let declKind = astutils.getVarDeclarationKind(<ts.VariableDeclaration>parent);
// collect declaration information to corresponding scope
let decl = this.addVariableDeclToScope(scope, id, parent, name, declKind);
if (declKind == VarDeclarationKind.VAR) {
let variableScopeParent = <VariableScope>scope.getNearestVariableScope();
this.collectHoistDecls(id, variableScopeParent, decl);
}
} else {
let declScope = scope.findDeclPos(name);
if (declScope) {
let decl = <Decl>declScope.getDecl(name);
if ((decl instanceof LetDecl || decl instanceof ConstDecl)) {
let nearestRefVariableScope = <VariableScope>scope.getNearestVariableScope();
let nearestDefLexicalScope = <VariableScope | LoopScope>declScope.getNearestLexicalScope();
let tmp: Scope | undefined = nearestRefVariableScope.getNearestLexicalScope();
let needCreateLoopEnv: boolean = false;
if (nearestDefLexicalScope instanceof LoopScope) {
while(tmp) {
if (tmp == nearestDefLexicalScope) {
needCreateLoopEnv = true;
break;
}
tmp = tmp.getParent();
}
if (needCreateLoopEnv) {
nearestDefLexicalScope.pendingCreateEnv();
}
}
}
}
}
if (name == "arguments") {
let varialbeScope = scope.getNearestVariableScope();
varialbeScope ?.setUseArgs(true);
}
}
private addVariableDeclToScope(scope: Scope, node: ts.Node, parent: ts.Node, name: string, declKind: VarDeclarationKind): Decl {
let decl = new VarDecl(name, node);
switch (declKind) {
case VarDeclarationKind.VAR:
break;
case VarDeclarationKind.LET:
if (parent.parent.kind == ts.SyntaxKind.CatchClause) {
decl = new CatchParameter(name, node);
} else {
decl = new LetDecl(name, node);
}
break;
case VarDeclarationKind.CONST:
decl = new ConstDecl(name, node);
break;
default:
throw new Error("Wrong type of declaration");
}
scope.setDecls(decl);
return decl;
}
private getDeclarationNodeOfId(id: ts.Identifier): ts.VariableDeclaration | undefined {
let parent = id.parent;
if (ts.isVariableDeclaration(parent) &&
parent.name == id) {
return <ts.VariableDeclaration>parent;
} else if (ts.isBindingElement(parent) &&
parent.name == id) {
while (parent && !ts.isVariableDeclaration(parent)) {
parent = parent.parent;
}
return parent ? <ts.VariableDeclaration>parent : undefined;
} else {
return undefined;
}
}
private recordImportInfo(node: ts.ImportDeclaration, scope: ModuleScope) {
if (!ts.isStringLiteral(node.moduleSpecifier)) {
throw new Error("moduleSpecifier must be a stringLiteral");
}
let moduleRequest = jshelpers.getTextOfIdentifierOrLiteral(node.moduleSpecifier);
let importStmt = new ModuleStmt(node, moduleRequest);
if (node.importClause) {
let importClause: ts.ImportClause = node.importClause;
// import defaultExport from "a.js"
if (importClause.name) {
let name = jshelpers.getTextOfIdentifierOrLiteral(importClause.name);
scope.setDecls(new ModDecl(name, importClause.name));
importStmt.addLocalName(name, "default");
}
// import { ... } from "a.js"
// import * as a from "a.js"
// import defaultExport, * as a from "a.js"
if (importClause.namedBindings) {
let namedBindings = importClause.namedBindings;
// import * as a from "a.js"
if (ts.isNamespaceImport(namedBindings)) {
let nameSpace = jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceImport>namedBindings).name);
scope.setDecls(new ConstDecl(nameSpace, namedBindings));
importStmt.setNameSpace(nameSpace);
}
// import { ... } from "a.js"
if (ts.isNamedImports(namedBindings)) {
namedBindings.elements.forEach((element) => {
let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name);
let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name;
scope.setDecls(new ModDecl(name, element));
importStmt.addLocalName(name, exoticName);
});
}
}
}
this.importStmts.push(importStmt);
}
private recordExportInfo(node: ts.ExportDeclaration) {
let exportStmt: ModuleStmt;
if (node.moduleSpecifier) {
if (!ts.isStringLiteral(node.moduleSpecifier)) {
throw new Error("moduleSpecifier must be a stringLiteral");
}
exportStmt = new ModuleStmt(node, jshelpers.getTextOfIdentifierOrLiteral(node.moduleSpecifier));
} else {
exportStmt = new ModuleStmt(node);
}
if (node.exportClause) {
exportStmt.setCopyFlag(false);
let namedBindings: ts.NamedExportBindings = node.exportClause;
if (ts.isNamespaceExport(namedBindings)) {
exportStmt.setNameSpace(jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceExport>namedBindings).name));
}
if (ts.isNamedExports(namedBindings)) {
namedBindings.elements.forEach((element) => {
let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name);
if (name == 'default') {
if (this.defaultUsed) {
throw new DiagnosticError(node, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(node), [name]);
} else {
this.defaultUsed = true;
}
}
let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name;
exportStmt.addLocalName(name, exoticName);
});
}
}
this.exportStmts.push(exportStmt);
}
private recordFuncDecl(node: ts.FunctionDeclaration, scope: Scope) {
this.recordFuncInfo(node);
let funcId = <ts.Identifier>(node).name;
if (!funcId) {
// function declaration without name doesn't need to record hoisting.
return;
}
let funcName = jshelpers.getTextOfIdentifierOrLiteral(funcId);
let funcDecl = new FuncDecl(funcName, node, this.compilerDriver.getFuncId(node));
scope.setDecls(funcDecl);
let hoistScope = scope;
if (scope instanceof GlobalScope || scope instanceof ModuleScope) {
this.collectHoistDecls(node, <GlobalScope | ModuleScope>hoistScope, funcDecl);
} else if (scope instanceof LocalScope) {
hoistScope = <Scope>scope.getNearestVariableScope();
let expectHoistScope = this.getScopeOfNode(node.parent.parent);
if ((hoistScope == expectHoistScope) && (hoistScope instanceof FunctionScope)) {
this.collectHoistDecls(node, hoistScope, funcDecl);
}
} else {
LOGD("Function declaration", " in function is collected in its body block");
}
}
private recordFuncInfo(node: ts.FunctionLikeDeclaration) {
this.recordFunctionParameters(node);
this.recordFuncName(node);
}
recordFuncName(node: ts.FunctionLikeDeclaration) {
let name: string = '';
if (ts.isConstructorDeclaration(node)) {
let classNode = node.parent;
name = getClassNameForConstructor(classNode);
} else {
if (isAnonymousFunctionDefinition(node)) {
let outerNode = findOuterNodeOfParenthesis(node);
if (ts.isVariableDeclaration(outerNode)) {
let id = outerNode.name;
if (ts.isIdentifier(id)) {
name = jshelpers.getTextOfIdentifierOrLiteral(id);
}
} else if (ts.isBinaryExpression(outerNode)) {
if (outerNode.operatorToken.kind == ts.SyntaxKind.EqualsToken && ts.isIdentifier(outerNode.left)) {
name = jshelpers.getTextOfIdentifierOrLiteral(outerNode.left);
}
} else if (ts.isPropertyAssignment(outerNode)) {
let propName = outerNode.name;
if (ts.isIdentifier(propName) || ts.isStringLiteral(propName) || ts.isNumericLiteral(propName)) {
name = jshelpers.getTextOfIdentifierOrLiteral(propName);
if (name == "__proto__") {
name = '';
}
}
}
} else {
if (ts.isIdentifier(node.name!)) {
name = jshelpers.getTextOfIdentifierOrLiteral(node.name);
}
}
}
(<FunctionScope>this.getScopeOfNode(node)).setFuncName(name);
}
recordFunctionParameters(node: ts.FunctionLikeDeclaration) {
let parameters = node.parameters;
let funcParams: FunctionParameter[] = [];
let length = 0;
let lengthFlag = true;
if (parameters) {
parameters.forEach(parameter => {
// record function.length
if (parameter.initializer || this.isRestParameter(parameter)) {
lengthFlag = false;
}
if (lengthFlag) {
length++;
}
if (ts.isIdentifier(parameter.name)) {
let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>parameter.name);
funcParams.push(new FunctionParameter(name, parameter.name));
} else { // parameter is binding pattern
this.recordPatternParameter(<ts.BindingPattern>parameter.name, funcParams);
}
});
}
(<FunctionScope>this.getScopeOfNode(node)).setParameterLength(length);
this.setParametersMap(node, funcParams);
}
recordPatternParameter(pattern: ts.BindingPattern, funcParams: Array<FunctionParameter>) {
let name: string = '';
pattern.elements.forEach(bindingElement => {
if (ts.isOmittedExpression(bindingElement)) {
return;
}
bindingElement = <ts.BindingElement>bindingElement;
if (ts.isIdentifier(bindingElement.name)) {
name = jshelpers.getTextOfIdentifierOrLiteral(bindingElement.name);
funcParams.push(new FunctionParameter(name, bindingElement.name));
} else { // case of binding pattern
let innerPattern = <ts.BindingPattern>bindingElement.name;
this.recordPatternParameter(innerPattern, funcParams);
}
});
}
isRestParameter(parameter: ts.ParameterDeclaration) {
return parameter.dotDotDotToken ? true : false;
}
private collectHoistDecls(node: ts.Node, scope: VariableScope, decl: Decl) {
let declName = decl.name;
// if variable share a same name with the parameter of its contained function, it should not be hoisted
if (scope instanceof FunctionScope) {
let nearestFunc = jshelpers.getContainingFunction(node);
let functionParameters = this.getParametersOfFunction(nearestFunc);
if (functionParameters) {
for (let i = 0; i < functionParameters.length; i++) {
if (functionParameters[i].name == declName) {
return;
}
}
}
}
// Variable named of global identifier should not be hoisted.
if (isGlobalIdentifier(declName) && (scope instanceof GlobalScope)) {
return;
}
this.setHoistMap(scope, decl);
}
setScopeMap(node: ts.Node, scope: Scope) {
this.scopeMap.set(node, scope);
}
getScopeMap() {
return this.scopeMap;
}
getScopeOfNode(node: ts.Node) {
return this.scopeMap.get(node);
}
getImportStmts() {
return this.importStmts;
}
getExportStmts() {
return this.exportStmts;
}
setHoistMap(scope: VariableScope, decl: Decl) {
if (!this.hoistMap.has(scope)) {
this.hoistMap.set(scope, [decl]);
return;
}
let hoistDecls = <Decl[]>this.hoistMap.get(scope);
for (let i = 0; i < hoistDecls.length; i++) {
if (decl.name == hoistDecls[i].name) {
if (decl instanceof FuncDecl) {
hoistDecls[i] = decl;
}
return;
}
}
hoistDecls.push(decl);
}
getHoistMap() {
return this.hoistMap;
}
getHoistDeclsOfScope(scope: VariableScope) {
return this.hoistMap.get(scope);
}
setParametersMap(node: ts.FunctionLikeDeclaration, parameters: FunctionParameter[]) {
this.parametersMap.set(node, parameters);
}
getParametersOfFunction(node: ts.FunctionLikeDeclaration) {
return this.parametersMap.get(node);
}
}
+328
View File
@@ -0,0 +1,328 @@
/*
* 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.
*/
import { CacheList } from "./base/vregisterCache";
import { DebugInfo } from "./debuginfo";
import {
BuiltinR2i,
Format,
IRNode,
MovDyn,
OperandKind,
OperandType,
VReg,
Imm
} from "./irnodes";
import { PandaGen } from "./pandagen";
const MAX_VREGA = 16;
const MAX_VREGB = 256;
const MAX_VREGC = 65536;
class VRegWithFlag {
constructor(vreg: VReg) {
this.flag = false;
this.vreg = vreg;
}
vreg: VReg;
flag: boolean; // indicate whether it is used as a temporary register for spill
}
class RegAllocator {
private spills: VReg[] = [];
private vRegsId: number = 0;
private usedVreg: VRegWithFlag[] = [];
private tmpVreg: VRegWithFlag[] = [];
constructor() {
this.vRegsId = 0;
}
allocIndexForVreg(vreg: VReg) {
let num = this.getFreeVreg();
vreg.num = num;
this.usedVreg[num] = new VRegWithFlag(vreg);
}
findTmpVreg(level: number): VReg {
let iterCnts = Math.min(MAX_VREGB, this.usedVreg.length);
for (let i = 0; i < iterCnts; ++i) {
let value = this.usedVreg[i];
if (value === undefined || value.flag) {
continue;
}
if (level === MAX_VREGA && value.vreg.num >= MAX_VREGA) {
throw new Error("no available tmp vReg from A");
}
value.flag = true;
this.tmpVreg.push(value);
return value.vreg;
}
throw new Error("no available tmp vReg from B");
}
clearVregFlags(): void {
for (let v of this.tmpVreg) {
v.flag = false;
}
this.tmpVreg = [];
}
allocSpill(): VReg {
if (this.spills.length > 0) {
return this.spills.pop()!;
}
let v = new VReg();
this.allocIndexForVreg(v);
return v;
}
freeSpill(v: VReg): void {
this.spills.push(v);
}
getFreeVreg(): number {
if (this.vRegsId >= MAX_VREGC) {
throw new Error("vreg has been running out");
}
return this.vRegsId++;
}
/* check whether the operands is valid for the format,
return 0 if it is valid, otherwise return the total
number of vreg which does not meet the requirement
*/
getNumOfInvalidVregs(operands: OperandType[], format: Format): number {
let num = 0;
for (let j = 0; j < operands.length; ++j) {
if (operands[j] instanceof VReg) {
if ((<VReg>operands[j]).num >= (1 << format[j].bitwidth)) {
num++;
}
}
}
return num;
}
markVregNotAvailableAsTmp(vreg: VReg): void {
let num = vreg.num;
this.usedVreg[num].flag = true;
this.tmpVreg.push(this.usedVreg[num]);
}
doRealAdjustment(operands: OperandType[], format: Format, index: number, irNodes: IRNode[]): number {
let head: IRNode[] = [];
let tail: IRNode[] = [];
let spills: VReg[] = [];
// mark all vreg used in the current insn as not valid for tmp register
for (let i = 0; i < operands.length; ++i) {
if (operands[i] instanceof VReg) {
this.markVregNotAvailableAsTmp(<VReg>operands[i]);
}
}
for (let j = 0; j < operands.length; ++j) {
if (operands[j] instanceof VReg) {
let vOrigin = <VReg>operands[j];
if (vOrigin.num >= (1 << format[j].bitwidth)) {
let spill = this.allocSpill();
spills.push(spill);
let vTmp;
try {
vTmp = this.findTmpVreg(1 << format[j].bitwidth);
} catch {
throw Error("no available tmp vReg");
}
head.push(new MovDyn(spill, vTmp));
operands[j] = vTmp;
if (format[j].kind == OperandKind.SrcVReg) {
head.push(new MovDyn(vTmp, vOrigin));
} else if (format[j].kind == OperandKind.DstVReg) {
tail.push(new MovDyn(vOrigin, vTmp))
} else if (format[j].kind == OperandKind.SrcDstVReg) {
head.push(new MovDyn(vTmp, vOrigin));
tail.push(new MovDyn(vOrigin, vTmp))
} else {
// here we do nothing
}
tail.push(new MovDyn(vTmp, spill));
}
}
}
// for debuginfo
DebugInfo.copyDebugInfo(irNodes[index], head);
DebugInfo.copyDebugInfo(irNodes[index], tail);
irNodes.splice(index, 0, ...head);
irNodes.splice(index + head.length + 1, 0, ...tail);
for (let j = spills.length - 1; j >= 0; --j) {
this.freeSpill(spills[j]);
}
this.clearVregFlags();
return (head.length + tail.length);
}
checkDynRangeInstruction(irNodes: IRNode[], index: number): boolean {
let operands = irNodes[index].operands;
let level = 1 << irNodes[index].formats[0][2].bitwidth;
/*
1. "CalliDynRange 4, v255" is a valid insn, there is no need for all 4 registers numbers to be less than 255,
it is also similar for NewobjDyn
2. we do not need to mark any register to be invalid for tmp register, since no other register is used in calli.dyn.range
3. if v.num is bigger than 255, it means all register less than 255 has been already used, they should have been pushed
into usedVreg
*/
if ((<VReg>operands[2]).num >= level) {
// needs to be adjusted.
return false;
}
/* the first two operands are the imm */
let startNum = (<VReg>operands[2]).num;
let i = 3;
let implicitRegNums = (irNodes[index]).operands.length - 3;
let tempNums = implicitRegNums;
while (tempNums > 0) {
if ((++startNum) != (<VReg>operands[i++]).num) {
throw Error("Warning: VReg sequence of DynRange is not continuous. Please adjust it now.");
}
tempNums--;
}
/* If the parameters are consecutive, no adjustment is required. */
if (i == (implicitRegNums + 3)) {
return true;
}
// needs to be adjusted.
return false;
}
adjustDynRangeInstruction(irNodes: IRNode[], index: number): number {
let head: IRNode[] = [];
let tail: IRNode[] = [];
let spills: VReg[] = [];
let operands = irNodes[index].operands;
/* the first two operands are the imm */
let regNums = operands.length - 2;
let level = 1 << irNodes[index].formats[0][2].bitwidth;
let tmp = this.findTmpVreg(level);
for (let i = 0; i < regNums; i++) {
let spill = this.allocSpill();
spills.push(spill);
/* We need to make sure that the register input in the .range instruction is continuous(small to big). */
head.push(new MovDyn(spill, this.usedVreg[tmp.num + i].vreg));
head.push(new MovDyn(this.usedVreg[tmp.num + i].vreg, <VReg>operands[i + 2]));
operands[i + 2] = this.usedVreg[tmp.num + i].vreg;
tail.push(new MovDyn(this.usedVreg[tmp.num + i].vreg, spill));
}
// for debuginfo
DebugInfo.copyDebugInfo(irNodes[index], head);
DebugInfo.copyDebugInfo(irNodes[index], tail);
irNodes.splice(index, 0, ...head);
irNodes.splice(index + head.length + 1, 0, ...tail);
for (let i = spills.length - 1; i >= 0; --i) {
this.freeSpill(spills[i]);
}
this.clearVregFlags();
return (head.length + tail.length);
}
isRangeIns(ins: IRNode) {
if (ins instanceof BuiltinR2i) {
if (((<Imm>ins.operands[0]).value == 1) || ((<Imm>ins.operands[0]).value == 3) || ((<Imm>ins.operands[0]).value == 4)) {
return true;
}
}
return false;
}
adjustInstructionsIfNeeded(irNodes: IRNode[]): void {
for (let i = 0; i < irNodes.length; ++i) {
let operands = irNodes[i].operands;
let formats = irNodes[i].formats;
if (this.isRangeIns(irNodes[i])) {
if (this.checkDynRangeInstruction(irNodes, i)) {
continue;
}
i += this.adjustDynRangeInstruction(irNodes, i);
continue;
}
let min = operands.length;
let minFormat = formats[0];
for (let j = 0; j < formats.length; ++j) {
let num = this.getNumOfInvalidVregs(operands, formats[j]);
if (num < min) {
minFormat = formats[j];
min = num;
}
}
if (min > 0) {
i += this.doRealAdjustment(operands, minFormat, i, irNodes);
}
}
}
getTotalRegsNum(): number {
return this.vRegsId;
}
run(pandaGen: PandaGen): void {
let irNodes = pandaGen.getInsns();
let locals = pandaGen.getLocals();
let temps = pandaGen.getTemps();
let cache = pandaGen.getVregisterCache();
let parametersCount = pandaGen.getParametersCount();
// don't mess up allocation order
for (let i = 0; i < locals.length; ++i) {
this.allocIndexForVreg(locals[i]);
}
for (let i = 0; i < temps.length; ++i) {
this.allocIndexForVreg(temps[i]);
}
for (let i = CacheList.MIN; i < CacheList.MAX; ++i) {
let cacheItem = cache.getCache(i);
if (cacheItem.isNeeded()) {
this.allocIndexForVreg(cacheItem.getCache());
}
}
this.adjustInstructionsIfNeeded(irNodes);
for (let i = 0; i < parametersCount; ++i) {
let v = new VReg();
this.allocIndexForVreg(v);
irNodes.splice(0, 0, new MovDyn(locals[i], v));
}
}
}
export class RegAlloc {
run(pandaGen: PandaGen): void {
let regalloc = new RegAllocator();
regalloc.run(pandaGen);
pandaGen.setTotalRegsNum(regalloc.getTotalRegsNum());
}
}
+547
View File
@@ -0,0 +1,547 @@
/*
* 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.
*/
import * as ts from "typescript";
import { DebugInsPlaceHolder } from "./irnodes";
import { LOGD, LOGE } from "./log";
import {
GlobalVariable,
LocalVariable,
ModuleVariable,
VarDeclarationKind,
Variable
} from "./variable";
export enum InitStatus {
INITIALIZED, UNINITIALIZED
}
export abstract class Decl {
name: string;
node: ts.Node;
constructor(name: string, node: ts.Node) {
this.name = name;
this.node = node;
}
}
export class VarDecl extends Decl {
constructor(varName: string, node: ts.Node) {
super(varName, node);
}
}
export class LetDecl extends Decl {
constructor(letName: string, node: ts.Node) {
super(letName, node);
}
}
export class ConstDecl extends Decl {
constructor(constName: string, node: ts.Node) {
super(constName, node);
}
}
export class ModDecl extends Decl {
constructor(localName: string, node: ts.Node) {
super(localName, node);
}
}
export class FuncDecl extends Decl {
readonly index: number;
constructor(funcName: string, node: ts.Node, index: number) {
super(funcName, node);
this.index = index;
}
}
export class ClassDecl extends Decl {
readonly index: number;
constructor(className: string, node: ts.Node, index: number) {
super(className, node);
this.index = index;
}
}
export class CatchParameter extends Decl {
constructor(CpName: string, node: ts.Node) {
super(CpName, node);
}
}
export class FunctionParameter extends Decl {
constructor(FpName: string, node: ts.Node) {
super(FpName, node);
}
}
export abstract class Scope {
protected debugTag = "scope";
protected globals: Variable[] = [];
protected locals: Variable[] = [];
protected name2variable: Map<string, Variable> = new Map<string, Variable>();
protected decls: Decl[] = [];
protected parent: Scope | undefined = undefined;
// for debuginfo
protected startIns: DebugInsPlaceHolder = new DebugInsPlaceHolder();
protected endIns: DebugInsPlaceHolder = new DebugInsPlaceHolder();
constructor() { }
abstract add(name: string, declKind: VarDeclarationKind, status?: InitStatus): Variable | undefined;
getName2variable(): Map<string, Variable> {
return this.name2variable;
}
getScopeStartIns() {
return this.startIns;
}
setScopeStartIns(startIns: DebugInsPlaceHolder) {
this.startIns = startIns;
}
setScopeEndIns(endIns: DebugInsPlaceHolder) {
this.endIns = endIns;
}
getScopeEndIns() {
return this.endIns;
}
setParent(parentScope: Scope | undefined) {
this.parent = parentScope;
}
getParent(): Scope | undefined {
return this.parent;
}
getRootScope(): Scope {
let sp: Scope | undefined = this;
let pp = this.getParent();
while (pp != undefined) {
sp = pp;
pp = pp.getParent();
}
return sp;
}
getNearestVariableScope(): VariableScope | undefined {
let sp: Scope | undefined = this;
while (sp) {
if (sp instanceof VariableScope) {
return <VariableScope>sp;
}
sp = sp.parent;
}
return undefined;
}
getNearestLexicalScope(): VariableScope | LoopScope | undefined {
let curScope: Scope | undefined = this;
while (curScope) {
if (curScope instanceof VariableScope || curScope instanceof LoopScope) {
return <VariableScope | LoopScope>curScope;
}
curScope = curScope.parent;
}
return undefined;
}
getNthVariableScope(level: number): VariableScope | undefined {
let sp: Scope | undefined = this;
let tempLevel = level;
while (sp) {
if (sp instanceof VariableScope) {
if (tempLevel == 0) {
return <VariableScope>sp;
} else {
tempLevel--;
}
}
sp = sp.parent;
}
return undefined;
}
findLocal(name: string): Variable | undefined {
return this.name2variable.get(name);
}
find(name: string): { scope: Scope | undefined, level: number, v: Variable | undefined } {
let curLevel = 0;
let curScope: Scope | undefined = this;
while (curScope) {
let resolve = null;
let tmpLevel = curLevel; // to store current level, not impact by ++
if (curScope instanceof VariableScope || (curScope instanceof LoopScope && curScope.need2CreateLexEnv())) {
curLevel++;
}
resolve = curScope.findLocal(name);
if (resolve) {
LOGD(this.debugTag, "scope.find (" + name + ") :");
LOGD(undefined, resolve);
return { scope: curScope, level: tmpLevel, v: resolve };
}
curScope = curScope.getParent();
}
LOGD(this.debugTag, "scope.find (" + name + ") : undefined");
return { scope: undefined, level: 0, v: undefined };
}
findDeclPos(name: string): Scope | undefined {
let declPos: Scope | undefined = undefined;
let curScope: Scope | undefined = this;
while (curScope) {
if (curScope.hasDecl(name)) {
declPos = curScope;
break;
}
curScope = curScope.getParent();
}
return declPos;
}
abstract setLexVar(v: Variable, srcScope: Scope): void;
setDecls(decl: Decl) {
this.decls.push(decl);
}
hasDecl(name: string): boolean {
let decls = this.decls;
for (let i = 0; i < decls.length; i++) {
if (decls[i].name == name) {
return true;
}
}
return false;
}
getDecl(name: string): Decl | undefined {
let decls = this.decls;
for (let i = 0; i < decls.length; i++) {
if (decls[i].name == name) {
return decls[i];
}
}
return undefined;
}
getDecls() {
return this.decls;
}
}
export abstract class VariableScope extends Scope {
protected startLexIdx: number = 0;
protected needCreateLexEnv: boolean = false;
protected parameters: LocalVariable[] = [];
protected useArgs = false;
protected node: ts.Node | undefined = undefined;
protected parentVariableScope: VariableScope | null = null;
protected childVariableScope: VariableScope[] = [];
getBindingNode() {
return this.node;
}
setParentVariableScope(scope: VariableScope) {
this.parentVariableScope = scope;
}
getParentVariableScope() {
return this.parentVariableScope;
}
getChildVariableScope() {
return this.childVariableScope;
}
addChildVariableScope(scope: VariableScope) {
this.childVariableScope.push(scope);
}
addParameter(name: string, declKind: VarDeclarationKind, argIdx: number): Variable | undefined {
LOGD(this.debugTag, "VariableScope.addArg(" + name + "), kind(" + declKind + ")", "argIdx(" + argIdx + ")");
let v = this.add(name, declKind, InitStatus.INITIALIZED);
if (!(v instanceof LocalVariable)) {
throw new Error("Error: argument must be local variable!");
}
this.parameters.push(v);
return v;
}
addFuncName(funcName: string) {
let funcObj = this.name2variable.get('4funcObj');
this.name2variable.set(funcName, funcObj!);
}
need2CreateLexEnv(): boolean {
return this.needCreateLexEnv;
}
pendingCreateEnv() {
this.needCreateLexEnv = true;
}
getNumLexEnv(): number {
return this.startLexIdx;
}
getParametersCount(): number {
return this.parameters.length;
}
getParameters(): LocalVariable[] {
return this.parameters;
}
getLexVarIdx() {
this.needCreateLexEnv = true;
return this.startLexIdx++;
}
setLexVar(v: Variable, refScope: Scope) {
if (!v.isLexVar) {
v.setLexVar(this);
}
LOGD(this.debugTag, "VariableScope.setLexVar(" + v.idxLex + ")");
// set all chain to create env
let scope: Scope | undefined = refScope;
while (scope && scope != this) {
if (scope instanceof VariableScope || (scope instanceof LoopScope && scope.need2CreateLexEnv())) {
scope.pendingCreateEnv();
}
scope = scope.getParent();
}
}
setUseArgs(value: boolean) {
this.useArgs = value;
}
getUseArgs(): boolean {
return this.useArgs;
}
}
export class GlobalScope extends VariableScope {
constructor(node?: ts.SourceFile) {
super();
this.node = node ? node : undefined;
}
add(name: string, declKind: VarDeclarationKind, status?: InitStatus): Variable | undefined {
LOGD(this.debugTag, "globalscope.add (" + name + "), kind:" + declKind);
let v: Variable | undefined;
if (declKind == VarDeclarationKind.NONE || declKind == VarDeclarationKind.VAR || declKind == VarDeclarationKind.FUNCTION) {
v = new GlobalVariable(declKind, name);
this.globals.push(v);
} else {
v = new LocalVariable(declKind, name, status);
this.locals.push(v);
}
this.name2variable.set(name, v);
return v;
}
}
export class ModuleScope extends VariableScope {
constructor(node?: ts.SourceFile | ts.ModuleBlock) {
super();
this.node = node ? node : undefined;
}
add(name: string, declKind: VarDeclarationKind, status?: InitStatus): Variable | undefined {
LOGD(this.debugTag, "modulescope.add (" + name + "), kind:" + declKind);
let v: Variable | undefined;
if (declKind == VarDeclarationKind.NONE) {
v = new GlobalVariable(declKind, name);
this.globals.push(v);
} else if (declKind == VarDeclarationKind.VAR || declKind == VarDeclarationKind.FUNCTION) {
v = new LocalVariable(declKind, name);
this.locals.push(v);
} else if (declKind == VarDeclarationKind.MODULE) {
v = new ModuleVariable(VarDeclarationKind.CONST, name, InitStatus.INITIALIZED);
this.locals.push(v);
} else {
v = new LocalVariable(declKind, name, status);
this.locals.push(v);
}
this.name2variable.set(name, v);
return v;
}
}
export class FunctionScope extends VariableScope {
private parameterLength: number = 0;
private funcName: string = "";
constructor(parent?: Scope, node?: ts.FunctionLikeDeclaration) {
super();
this.parent = parent ? parent : undefined;
this.node = node ? node : undefined;
}
setParameterLength(length: number) {
this.parameterLength = length;
}
getParameterLength(): number {
return this.parameterLength;
}
setFuncName(name: string) {
this.funcName = name;
}
getFuncName() {
return this.funcName;
}
getParent(): Scope | undefined {
return this.parent;
}
add(name: string, declKind: VarDeclarationKind, status?: InitStatus): Variable | undefined {
let v: Variable | undefined;
LOGD(this.debugTag, "functionscope.add (" + name + "), kind:" + declKind);
if (declKind == VarDeclarationKind.NONE) {
// the variable declared without anything should be global
// See EcmaStandard: 13.3.2 Variable Statement
let globalScope = this.getRootScope();
if (globalScope instanceof GlobalScope || globalScope instanceof ModuleScope) {
v = globalScope.add(name, declKind);
} else {
v = undefined;
throw new Error("Error: global variable must be defined in global scope");
}
} else if (declKind == VarDeclarationKind.VAR || declKind == VarDeclarationKind.FUNCTION) {
v = new LocalVariable(declKind, name);
this.locals.push(v);
this.name2variable.set(name, v);
} else {
v = new LocalVariable(declKind, name, status);
this.locals.push(v);
this.name2variable.set(name, v);
}
return v;
}
}
export class LocalScope extends Scope {
constructor(parent: Scope) {
super();
this.parent = parent
}
setLexVar(v: Variable, srcScope: Scope) {
let variableScope = <VariableScope>this.getNearestLexicalScope();
variableScope.setLexVar(v, srcScope);
}
add(name: string, declKind: VarDeclarationKind, status?: InitStatus): Variable | undefined {
let v: Variable | undefined;
LOGD(this.debugTag, "localscope.add (" + name + "), kind:" + declKind);
if (declKind == VarDeclarationKind.NONE) {
let root = this.getRootScope();
if (root instanceof GlobalScope || root instanceof ModuleScope) {
return root.add(name, declKind, status);
} else {
LOGE(undefined, "Error: this scope'root is not globalscope, it is wrong");
return undefined;
}
} else if (declKind == VarDeclarationKind.VAR) {
/**
* the variable declared without anything should be accessible
* in all parent scopes so delegate creation to the parent
* See EcmaStandard: 13.3.2 Variable Statement
*/
let functionScope = this.getNearestVariableScope();
v = functionScope!.add(name, declKind);
} else {
v = new LocalVariable(declKind, name, status);
this.locals.push(v);
this.name2variable.set(name, v);
}
return v;
}
}
export class LoopScope extends LocalScope {
protected startLexIdx: number = 0;
protected needCreateLexEnv: boolean = false;
constructor(parent: Scope) {
super(parent);
}
setLexVar(v: Variable, refScope: Scope) {
if (!v.isLexVar) {
v.setLexVar(this);
}
LOGD(this.debugTag, "LoopScope.setLexVar(" + v.idxLex + ")");
let scope: Scope | undefined = refScope;
while (scope && scope != this) {
if (scope instanceof VariableScope || (scope instanceof LoopScope && scope.need2CreateLexEnv())) {
scope.pendingCreateEnv();
}
scope = scope.getParent();
}
}
need2CreateLexEnv(): boolean {
return this.needCreateLexEnv;
}
pendingCreateEnv() {
this.needCreateLexEnv = true;
}
getLexVarIdx() {
this.needCreateLexEnv = true;
return this.startLexIdx++;
}
getNumLexEnv(): number {
return this.startLexIdx;
}
}
+766
View File
@@ -0,0 +1,766 @@
/*
* 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.
*/
import * as ts from "typescript";
import { LReference } from "../base/lreference";
import { isUndefinedIdentifier } from "../base/util";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { Compiler } from "../compiler";
import { createArrayFromElements } from "../expression/arrayLiteralExpression";
import { createMethodOrAccessor } from "../expression/objectLiteralExpression";
import { Literal, LiteralBuffer, LiteralTag } from "../base/literal";
import { getPropName, isConstantExpr, Property, propertyKeyAsString, PropertyKind } from "../base/properties";
import { findOuterNodeOfParenthesis } from "../expression/parenthesizedExpression";
import {
VReg
} from "../irnodes";
import * as jshelpers from "../jshelpers";
import { PandaGen } from "../pandagen";
import { Recorder } from "../recorder";
import {
FunctionScope,
LocalScope,
Scope,
VariableScope
} from "../scope";
import { LocalVariable, Variable } from "../variable";
export function compileClassDeclaration(compiler: Compiler, stmt: ts.ClassLikeDeclaration) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let namedPropertyMap: Map<string, Property> = new Map<string, Property>();
let properties: Array<Property> = [];
let classFields: Array<ts.PropertyDeclaration> = [];
properties = generatePropertyFromExpr(stmt, classFields, namedPropertyMap);
let classReg = pandaGen.getTemp();
let baseVreg = compileHeritageClause(compiler, stmt);
let classBuffer = new LiteralBuffer();
let propertyIndex = 0;
let staticItemsNum = 0;
let hasConstructor = isContainConstruct(stmt);
for (; propertyIndex < properties.length; propertyIndex++) {
let prop = properties[propertyIndex];
let index = propertyIndex;
if (!hasConstructor) {
index = propertyIndex + 1;
}
let tmpVreg = pandaGen.getTemp();
if (prop.getKind() == PropertyKind.Constant) {
staticItemsNum++;
let nameLiteral = new Literal(LiteralTag.STRING, String(prop.getName()));
classBuffer.addLiterals(nameLiteral);
compiler.compileExpression(<ts.Expression>prop.getValue());
pandaGen.storeAccumulator(prop.getValue(), tmpVreg);
prop.setCompiled();
}
if (prop.getKind() == PropertyKind.Variable) {
if (prop.getValue().kind != ts.SyntaxKind.Constructor) {
if (jshelpers.hasStaticModifier(prop.getValue())) {
staticItemsNum++;
}
let nameLiteral = new Literal(LiteralTag.STRING, String(prop.getName()));
classBuffer.addLiterals(nameLiteral);
}
if (ts.isMethodDeclaration(prop.getValue())) {
let methodLiteral = new Literal(LiteralTag.METHOD, compiler.getCompilerDriver().getFuncInternalName(<ts.MethodDeclaration>prop.getValue()));
classBuffer.addLiterals(methodLiteral);
} else {
if (!ts.isConstructorDeclaration(prop.getValue())) {
let valLiteral = new Literal(LiteralTag.NULLVALUE, null);
classBuffer.addLiterals(valLiteral);
compiler.compileExpression(<ts.Expression | ts.Identifier>prop.getValue());
pandaGen.storeAccumulator(prop.getValue(), tmpVreg);
}
}
prop.setCompiled();
}
pandaGen.freeTemps(tmpVreg);
if (prop.getKind() == PropertyKind.Computed || prop.getKind() == PropertyKind.Accessor) {
break;
}
}
let notStaticItemsNum = propertyIndex - staticItemsNum;
let nameLiteral = new Literal(LiteralTag.INTEGER, hasConstructor ? notStaticItemsNum - 1 : notStaticItemsNum);
classBuffer.addLiterals(nameLiteral);
createClassLiteralBuf(compiler, classBuffer, stmt, [baseVreg, classReg]);
compileUnCompiledProperty(compiler, properties, classReg, hasConstructor);
pandaGen.loadAccumulator(stmt, classReg);
if (stmt.name) {
let className = jshelpers.getTextOfIdentifierOrLiteral(stmt.name);
let classScope = <Scope>compiler.getRecorder().getScopeOfNode(stmt);
let classInfo = classScope.find(className);
(<LocalVariable>classInfo.v).initialize();
pandaGen.storeAccToLexEnv(stmt, classInfo.scope!, classInfo.level, classInfo.v!, true);
}
pandaGen.freeTemps(classReg, baseVreg);
compiler.popScope();
}
export function AddCtor2Class(recorder: Recorder, classNode: ts.ClassLikeDeclaration, scope: Scope) {
let ctorNode;
let hasHeritage = classNode.heritageClauses && classNode.heritageClauses.length;
let statement: ts.Statement | undefined;
let superCallNode = ts.createSuper();
if (hasHeritage) {
let parameter = ts.createParameter(undefined, undefined, ts.createToken(ts.SyntaxKind.DotDotDotToken), "args");
ctorNode = ts.createConstructor(undefined, undefined, [parameter], undefined);
let callNode = ts.createCall(
superCallNode,
undefined,
[ts.createSpread(ts.createIdentifier("args"))]
);
superCallNode.parent = callNode;
superCallNode.pos = classNode.pos;
superCallNode.end = classNode.pos;
statement = ts.createExpressionStatement(callNode);
callNode.parent = statement;
callNode.pos = classNode.pos;
callNode.end = classNode.pos;
} else {
ctorNode = ts.createConstructor(undefined, undefined, [], undefined);
}
if (statement) {
ctorNode.body = ts.createBlock([statement]);
statement.parent = ctorNode;
statement.pos = classNode.pos;
statement.end = classNode.pos;
} else {
ctorNode.body = ts.createBlock([]);
}
ctorNode.parent = classNode;
ctorNode.pos = classNode.pos;
ctorNode.end = classNode.pos;
ctorNode.body!.parent = ctorNode;
let parentScope = <LocalScope>recorder.getScopeOfNode(classNode);
recorder.compilerDriver.getFuncId(classNode);
let funcScope = recorder.buildVariableScope(scope, ctorNode);
funcScope.setParent(parentScope);
let ctorBodyScope = new LocalScope(funcScope);
ctorBodyScope.setParent(funcScope);
recorder.setScopeMap(ctorNode, funcScope);
recorder.setScopeMap(ctorNode.body!, ctorBodyScope);
recorder.recordFuncName(ctorNode);
recorder.recordFunctionParameters(ctorNode);
}
function compileUnCompiledProperty(compiler: Compiler, properties: Property[], classReg: VReg, hasConstructor: boolean) {
let pandaGen = compiler.getPandaGen();
for (let propertyIndex = 0; propertyIndex < properties.length; propertyIndex++) {
let prop = properties[propertyIndex];
if (prop.isCompiled()) {
continue;
}
let index = propertyIndex;
if (!hasConstructor) {
index = propertyIndex + 1;
}
switch (prop.getKind()) {
case PropertyKind.Constant:
compiler.compileExpression(<ts.Expression>prop.getValue());
pandaGen.storeOwnProperty(prop.getValue().parent, classReg, <string | number>prop.getName());
break;
case PropertyKind.Variable:
compileUnCompiledVariable(compiler, prop, classReg);
break;
case PropertyKind.Computed:
let keyReg = pandaGen.getTemp();
compiler.compileExpression((<ts.ComputedPropertyName>prop.getName()).expression);
pandaGen.storeAccumulator(prop.getValue(), keyReg);
compileComputedProperty(compiler, prop, classReg, keyReg);
break;
case PropertyKind.Accessor:
setClassAccessor(pandaGen, compiler, classReg, prop);
break;
default:
throw new Error("Unreachable PropertyKind for NullValue setting");
}
}
}
function compileUnCompiledVariable(compiler: Compiler, prop: Property, classReg: VReg) {
let pandaGen = compiler.getPandaGen();
let proptoReg = pandaGen.getTemp();
let tmpReg = pandaGen.getTemp();
let flag = false;
if (ts.isMethodDeclaration(prop.getValue())) {
flag = createClassMethodOrAccessor(compiler, classReg, proptoReg, tmpReg, <ts.MethodDeclaration>prop.getValue());
} else {
compiler.compileExpression(<ts.Expression | ts.Identifier>prop.getValue());
flag = setPrototypeAttributes(compiler, prop.getValue().parent, classReg, proptoReg, tmpReg);
}
pandaGen.storeOwnProperty(prop.getValue().parent, flag ? proptoReg : classReg, <string>prop.getName());
pandaGen.freeTemps(proptoReg, tmpReg);
prop.setCompiled();
}
function createClassLiteralBuf(compiler: Compiler, classBuffer: LiteralBuffer,
stmt: ts.ClassLikeDeclaration, vregs: VReg[]) {
let pandaGen = compiler.getPandaGen();
let classLiteralBuf = PandaGen.getLiteralArrayBuffer();
let buffIdx = classLiteralBuf.length;
let internalName = compiler.getCompilerDriver().getInternalNameForCtor(stmt);
classLiteralBuf.push(classBuffer);
pandaGen.defineClassWithBuffer(stmt, internalName, buffIdx, vregs[0]);
pandaGen.storeAccumulator(stmt, vregs[1]);
}
export function compileConstructor(compiler: Compiler, node: ts.ConstructorDeclaration, unreachableFlag: boolean) {
let pandaGen = compiler.getPandaGen();
let members = node.parent.members;
for (let index = 0; index < members.length; index++) {
let decl = members[index];
if (ts.isPropertyDeclaration(decl) && !jshelpers.hasStaticModifier(decl)) {
let lref = LReference.generateLReference(compiler, decl.name, true);
if (decl.initializer) {
compiler.compileExpression(decl.initializer);
}
lref.setValue();
}
}
if (unreachableFlag) {
return;
}
let thisReg = pandaGen.getTemp();
compiler.getThis(node, thisReg);
pandaGen.loadAccumulator(node, thisReg);
checkValidUseSuperBeforeSuper(compiler, node);
pandaGen.return(node);
pandaGen.freeTemps(thisReg);
}
export function compileSuperCall(compiler: Compiler, node: ts.CallExpression, args: VReg[], hasSpread: boolean) {
let pandaGen = compiler.getPandaGen();
// make sure "this" is stored in lexical env if needed
let curScope = <Scope>compiler.getCurrentScope();
let { scope, level, v } = curScope.find("this");
if (scope && level >= 0) {
let tmpScope = curScope;
let needSetLexVar: boolean = false;
while (tmpScope != scope) {
if (tmpScope instanceof VariableScope) {
needSetLexVar = true;
}
tmpScope = <Scope>tmpScope.getParent();
}
if (needSetLexVar) {
scope.setLexVar(<Variable>v, curScope);
}
}
if (hasSpread) {
let argArray = pandaGen.getTemp();
createArrayFromElements(node, compiler, <ts.NodeArray<ts.Expression>>node.arguments, argArray);
loadCtorObj(node, compiler);
pandaGen.superCallSpread(node, argArray);
pandaGen.freeTemps(argArray);
} else {
let num = args.length;
let startReg = num ? args[0] : getVregisterCache(pandaGen, CacheList.undefined);
loadCtorObj(node, compiler);
pandaGen.superCall(node, num, startReg);
}
let tmpReg = pandaGen.getTemp();
pandaGen.storeAccumulator(node, tmpReg);
checkValidUseSuperBeforeSuper(compiler, node);
pandaGen.loadAccumulator(node, tmpReg);
pandaGen.freeTemps(tmpReg);
compiler.setThis(node);
}
function loadCtorObj(node: ts.CallExpression, compiler: Compiler) {
let recorder = compiler.getRecorder();
let pandaGen = compiler.getPandaGen();
let nearestFunc = jshelpers.getContainingFunction(node);
let nearestFuncScope = <FunctionScope>recorder.getScopeOfNode(nearestFunc);
if (ts.isConstructorDeclaration(nearestFunc)) {
let funcObj = <Variable>nearestFuncScope.findLocal("4funcObj");
pandaGen.loadAccumulator(node, pandaGen.getVregForVariable(funcObj));
} else {
let outerFunc = jshelpers.getContainingFunction(nearestFunc);
let outerFuncScope = <FunctionScope>recorder.getScopeOfNode(outerFunc);
outerFuncScope.pendingCreateEnv();
let level = 1;
while (!ts.isConstructorDeclaration(outerFunc)) {
outerFunc = jshelpers.getContainingFunction(outerFunc);
outerFuncScope.pendingCreateEnv();
level++;
}
let funcObj = <Variable>outerFuncScope.findLocal("4funcObj");
outerFuncScope.setLexVar(funcObj, outerFuncScope);
let slot = funcObj.idxLex;
pandaGen.loadLexicalVar(node, level, slot);
}
}
export function isContainConstruct(stmt: ts.ClassLikeDeclaration) {
let members = stmt.members;
for (let index = 0; index < members.length; index++) {
let member = members[index];
if (ts.isConstructorDeclaration(member)) {
return true
}
}
return false;
}
export function defineClassMember(
propName: string | number | ts.ComputedPropertyName | undefined,
propValue: ts.Node,
propKind: PropertyKind,
properties: Property[],
namedPropertyMap: Map<string, Property>) {
let staticFlag = false;
if (propKind == PropertyKind.Computed || propKind == PropertyKind.Spread) {
let prop = new Property(propKind, <ts.ComputedPropertyName | undefined>propName);
prop.setValue(propValue);
if (jshelpers.hasStaticModifier(propValue)) {
staticFlag = true;
properties.push(prop);
} else {
properties.unshift(prop);
}
} else {
let name_str = propertyKeyAsString(<string | number>propName);
if (!checkAndUpdateProperty(namedPropertyMap, name_str, propKind, propValue)) {
let prop = new Property(propKind, propName);
if (propKind == PropertyKind.Accessor) {
if (ts.isGetAccessorDeclaration(propValue)) {
prop.setGetter(propValue);
} else if (ts.isSetAccessorDeclaration(propValue)) {
prop.setSetter(propValue);
}
} else {
prop.setValue(propValue);
}
if (jshelpers.hasStaticModifier(propValue)) {
staticFlag = true;
properties.push(prop);
} else {
properties.unshift(prop);
}
namedPropertyMap.set(name_str, prop);
}
}
return staticFlag;
}
function compileHeritageClause(compiler: Compiler, node: ts.ClassLikeDeclaration) {
let pandaGen = compiler.getPandaGen();
let baseVreg = pandaGen.getTemp();
if (node.heritageClauses && node.heritageClauses.length) {
let heritageClause = node.heritageClauses[0];
if (heritageClause.types.length) {
let exp = heritageClause.types[0];
compiler.compileExpression(exp.expression);
pandaGen.storeAccumulator(exp.expression, baseVreg);
return baseVreg;
}
}
pandaGen.moveVreg(node, baseVreg, getVregisterCache(pandaGen, CacheList.HOLE));
return baseVreg;
}
export function getClassNameForConstructor(classNode: ts.ClassLikeDeclaration) {
let className = "";
if (!isAnonymousClass(classNode)) {
className = jshelpers.getTextOfIdentifierOrLiteral(classNode.name);
} else {
let outerNode = findOuterNodeOfParenthesis(classNode);
if (ts.isVariableDeclaration(outerNode)) {
let decl = outerNode.name;
if (ts.isIdentifier(decl)) {
className = jshelpers.getTextOfIdentifierOrLiteral(decl);
}
} else if (ts.isBinaryExpression(outerNode)) {
let leftExp = outerNode.left;
if (outerNode.operatorToken.kind == ts.SyntaxKind.EqualsToken && ts.isIdentifier(leftExp)) {
className = jshelpers.getTextOfIdentifierOrLiteral(leftExp);
}
} else if (ts.isPropertyAssignment(outerNode)) {
let propName = outerNode.name;
if (ts.isIdentifier(propName) || ts.isStringLiteral(propName) || ts.isNumericLiteral(propName)) {
className = jshelpers.getTextOfIdentifierOrLiteral(propName);
}
}
}
return className;
}
function isAnonymousClass(node: ts.ClassLikeDeclaration) {
return node.name ? false : true;
}
function generatePropertyFromExpr(node: ts.ClassLikeDeclaration, classFields: Array<ts.PropertyDeclaration>, namedPropertyMap: Map<string, Property>) {
let properties: Array<Property> = [];
let staticNum = 0;
let constructNode: any;
node.members.forEach(member => {
switch (member.kind) {
case ts.SyntaxKind.Constructor:
constructNode = member;
break;
case ts.SyntaxKind.PropertyDeclaration: {
if (!jshelpers.hasStaticModifier(member)) {
classFields.push(<ts.PropertyDeclaration>member);
break;
}
if (ts.isComputedPropertyName(member.name!)) {
if (defineClassMember(member.name, member, PropertyKind.Computed, properties, namedPropertyMap)) {
staticNum++;
}
} else {
let memberName: number | string = <number | string>getPropName(member.name!);
let initializer = (<ts.PropertyDeclaration>member).initializer;
if (initializer) {
if (isConstantExpr(initializer)) {
if (defineClassMember(memberName, initializer, PropertyKind.Constant, properties, namedPropertyMap)) {
staticNum++;
}
} else {
if (defineClassMember(memberName, initializer, PropertyKind.Variable, properties, namedPropertyMap)) {
staticNum++;
}
}
} else {
initializer = ts.createIdentifier("undefined");
if (defineClassMember(memberName, initializer, PropertyKind.Constant, properties, namedPropertyMap)) {
staticNum++;
}
}
}
break;
}
case ts.SyntaxKind.MethodDeclaration: {
let memberName = getPropName(member.name!);
if (typeof (memberName) == 'string' || typeof (memberName) == 'number') {
if (defineClassMember(memberName, member, PropertyKind.Variable, properties, namedPropertyMap)) {
staticNum++;
}
} else {
if (defineClassMember(memberName, member, PropertyKind.Computed, properties, namedPropertyMap)) {
staticNum++;
}
}
break;
}
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor: {
let accessorName = getPropName(member.name!);
if (typeof (accessorName) == 'string' || typeof (accessorName) == 'number') {
if (defineClassMember(accessorName, member, PropertyKind.Accessor, properties, namedPropertyMap)) {
staticNum++;
}
} else {
if (defineClassMember(accessorName, member, PropertyKind.Computed, properties, namedPropertyMap)) {
staticNum++;
}
}
break;
}
case ts.SyntaxKind.SemicolonClassElement:
break;
default:
throw new Error("Unreachable Kind");
}
});
/**
* If it is a non-static member, `unshift`; otherwise `push`
* Need to reverse the order of non-static members
*/
let staticItems = properties.slice(properties.length - staticNum)
properties = properties.slice(0, properties.length - staticNum);
properties = properties.reverse();
properties = properties.concat(staticItems);
if (constructNode) {
defineClassMember("constructor", constructNode, PropertyKind.Variable, properties, namedPropertyMap);
}
return properties;
}
function compileComputedProperty(compiler: Compiler, prop: Property, classReg: VReg, keyReg: VReg) {
let pandaGen = compiler.getPandaGen();
switch (prop.getValue().kind) {
case ts.SyntaxKind.PropertyDeclaration: {
let initializer = (<ts.PropertyDeclaration>prop.getValue()).initializer;
if (initializer) {
compiler.compileExpression(initializer);
pandaGen.storeOwnProperty(prop.getValue(), classReg, keyReg);
}
break;
}
case ts.SyntaxKind.MethodDeclaration: {
let protoReg = pandaGen.getTemp();
let tmpReg = pandaGen.getTemp();
let flag = createClassMethodOrAccessor(compiler, classReg, protoReg, tmpReg, <ts.MethodDeclaration>prop.getValue());
pandaGen.storeOwnProperty(prop.getValue(), flag ? protoReg : classReg, keyReg);
pandaGen.freeTemps(protoReg, tmpReg);
break;
}
case ts.SyntaxKind.GetAccessor: {
let accessorReg = pandaGen.getTemp();
let getProtoReg = pandaGen.getTemp();
let getter = <ts.GetAccessorDeclaration>prop.getValue();
let getFlag = createClassMethodOrAccessor(compiler, classReg, getProtoReg, accessorReg, getter);
pandaGen.defineGetterSetterByValue(getter, getFlag ? getProtoReg : classReg, keyReg, accessorReg, getVregisterCache(pandaGen, CacheList.undefined), true);
pandaGen.freeTemps(accessorReg, getProtoReg);
break;
}
case ts.SyntaxKind.SetAccessor: {
let accesReg = pandaGen.getTemp();
let setter = <ts.SetAccessorDeclaration>prop.getValue();
let setProtoReg = pandaGen.getTemp();
let setFlag = createClassMethodOrAccessor(compiler, classReg, setProtoReg, accesReg, setter);
pandaGen.defineGetterSetterByValue(setter, setFlag ? setProtoReg : classReg, keyReg, getVregisterCache(pandaGen, CacheList.undefined), accesReg, true);
pandaGen.freeTemps(accesReg, setProtoReg);
break;
}
default:
throw new Error("unrecognized computed property");
}
pandaGen.freeTemps(keyReg);
}
function setClassAccessor(pandaGen: PandaGen, compiler: Compiler, objReg: VReg, prop: Property) {
let getterReg = pandaGen.getTemp();
let setterReg = pandaGen.getTemp();
let propReg = pandaGen.getTemp();
let tmpVreg = pandaGen.getTemp();
let flag = false;
let accessor: ts.GetAccessorDeclaration | ts.SetAccessorDeclaration;
if (prop.getGetter() !== undefined) {
let getter = <ts.GetAccessorDeclaration>prop.getGetter();
accessor = getter;
flag = createClassMethodOrAccessor(compiler, objReg, tmpVreg, getterReg, getter);
}
if (prop.getSetter() !== undefined) {
let setter = <ts.SetAccessorDeclaration>prop.getSetter();
accessor = setter;
flag = createClassMethodOrAccessor(compiler, objReg, tmpVreg, setterReg, setter);
}
pandaGen.loadAccumulatorString(accessor!, String(prop.getName()));
pandaGen.storeAccumulator(accessor!, propReg);
if (prop.getGetter() !== undefined && prop.getSetter() !== undefined) {
pandaGen.defineGetterSetterByValue(accessor!, flag ? tmpVreg : objReg, propReg, getterReg, setterReg, false);
} else if (ts.isGetAccessorDeclaration(accessor!)) {
pandaGen.defineGetterSetterByValue(accessor, flag ? tmpVreg : objReg, propReg, getterReg, getVregisterCache(pandaGen, CacheList.undefined), false);
} else {
pandaGen.defineGetterSetterByValue(accessor!, flag ? tmpVreg : objReg, propReg, getVregisterCache(pandaGen, CacheList.undefined), setterReg, false);
}
pandaGen.freeTemps(getterReg, setterReg, propReg, tmpVreg);
}
function createClassMethodOrAccessor(compiler: Compiler, classReg: VReg, propReg: VReg, storeReg: VReg,
node: ts.MethodDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration | ts.ConstructorDeclaration) {
let pandaGen = compiler.getPandaGen();
if (jshelpers.hasStaticModifier(node)) {
createMethodOrAccessor(pandaGen, compiler, classReg, node);
pandaGen.storeAccumulator(node, storeReg);
return false;
}
pandaGen.storeAccumulator(node, storeReg);
pandaGen.loadObjProperty(node, classReg, "prototype");
pandaGen.storeAccumulator(node, propReg);
pandaGen.loadAccumulator(node, storeReg);
createMethodOrAccessor(pandaGen, compiler, propReg, node);
pandaGen.storeAccumulator(node, storeReg);
return true;
}
function scalarArrayEquals(node1: ts.Node | undefined, node2: ts.Node | undefined) {
if (node1 && node2) {
let val1Modifs = node1.modifiers;
let val2Modifs = node2.modifiers;
if (val1Modifs && val2Modifs) {
return val1Modifs.length == val2Modifs.length && val1Modifs.every(function(v, i) { return v === val2Modifs![i] });;
}
if (!val1Modifs && !val2Modifs) {
return true;
}
} else if (!node1 && !node2) {
return true;
}
return false;
}
export function setPrototypeAttributes(compiler: Compiler, node: ts.Node, classReg: VReg, propReg: VReg, storeReg: VReg) {
let pandaGen = compiler.getPandaGen();
pandaGen.storeAccumulator(node, storeReg);
if (jshelpers.hasStaticModifier(node)) {
return false;
}
pandaGen.loadObjProperty(node, classReg, "prototype");
pandaGen.storeAccumulator(node, propReg);
pandaGen.loadAccumulator(node, storeReg);
return true;
}
function checkAndUpdateProperty(namedPropertyMap: Map<string, Property>, name: string, propKind: PropertyKind, valueNode: ts.Node): boolean {
if (namedPropertyMap.has(name)) {
let prop = namedPropertyMap.get(name);
if (propKind == PropertyKind.Accessor) {
if (ts.isGetAccessorDeclaration(valueNode)) {
if (!scalarArrayEquals(prop!.getGetter(), valueNode)) {
return false;
}
prop!.setGetter(valueNode);
} else if (ts.isSetAccessorDeclaration(valueNode)) {
if (!scalarArrayEquals(prop!.getSetter(), valueNode)) {
return false;
}
prop!.setSetter(valueNode);
}
} else {
if (!scalarArrayEquals(prop!.getValue(), valueNode)) {
return false;
}
prop!.setValue(valueNode);
prop!.setKind(propKind);
}
return true;
}
return false;
}
export function shouldReturnThisForConstruct(stmt: ts.ReturnStatement): boolean {
let ctorNode = jshelpers.getContainingFunction(stmt);
let expr = stmt.expression;
if (!ctorNode || !ts.isConstructorDeclaration(ctorNode)) {
return false;
}
if (!expr) {
return true;
}
if (isUndefinedIdentifier(expr)) {
return true;
}
if (expr.kind == ts.SyntaxKind.ThisKeyword) {
return true;
}
return false;
}
export function compileSuperProperty(compiler: Compiler, expr: ts.Expression, thisReg: VReg, prop: VReg | string | number) {
// to make sure loading "this" correctly
let curScope = <Scope>compiler.getCurrentScope();
let { scope, level, v } = curScope.find("this");
if (scope && level >= 0) {
let needSetLexVar: boolean = false;
while (curScope != scope) {
if (curScope instanceof VariableScope) {
needSetLexVar = true;
break;
}
curScope = <Scope>curScope.getParent();
}
if (needSetLexVar) {
scope.setLexVar(<Variable>v, curScope);
}
}
checkValidUseSuperBeforeSuper(compiler, expr);
let pandaGen = compiler.getPandaGen();
compiler.getThis(expr, thisReg);
pandaGen.loadSuperProperty(expr, thisReg, prop);
}
export function checkValidUseSuperBeforeSuper(compiler: Compiler, node: ts.Node) {
let pandaGen = compiler.getPandaGen();
let ctorNode = jshelpers.findAncestor(node, ts.isConstructorDeclaration);
if (!ctorNode || !ts.isClassLike(ctorNode.parent) || !jshelpers.getClassExtendsHeritageElement(ctorNode.parent)) {
return;
}
let thisReg = pandaGen.getTemp();
compiler.getThis(node, thisReg);
pandaGen.loadAccumulator(node, thisReg);
pandaGen.freeTemps(thisReg);
if (jshelpers.isSuperProperty(node) ||
ts.isConstructorDeclaration(node) ||
node.kind == ts.SyntaxKind.ThisKeyword ||
node.kind == ts.SyntaxKind.ReturnStatement) {
pandaGen.throwIfSuperNotCorrectCall(ctorNode, 0);
}
if (jshelpers.isSuperCall(node)) {
pandaGen.throwIfSuperNotCorrectCall(ctorNode, 1);
}
}
+116
View File
@@ -0,0 +1,116 @@
/*
* 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.
*/
import * as ts from "typescript";
import { Compiler } from "src/compiler";
import {
CacheList,
getVregisterCache
} from "../base/vregisterCache";
import { LabelTarget } from "./labelTarget";
import { Label, VReg } from "../irnodes";
import { TryBuilderWithForOf } from "./tryStatement";
import { PandaGen } from "src/pandagen";
import { LoopScope } from "src/scope";
export enum IteratorType { Normal, Async }
export class IteratorRecord {
private type: IteratorType;
private object: VReg;
private nextMethod: VReg;
constructor(object: VReg, nextMethod: VReg, type: IteratorType = IteratorType.Normal) {
this.type = type;
this.object = object;
this.nextMethod = nextMethod;
}
getType() {
return this.type;
}
getObject() {
return this.object;
}
getNextMethod() {
return this.nextMethod;
}
}
export function compileForOfStatement(stmt: ts.ForOfStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let nextLabel = new Label();
let endLabel = new Label();
let doneReg = pandaGen.getTemp();
let method = pandaGen.getTemp();
let object = pandaGen.getTemp();
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let loopEnv = pandaGen.getTemp();
// for now Async is not handled.
let type: IteratorType = IteratorType.Normal;
compiler.compileExpression(stmt.expression);
let iterator: IteratorRecord = getIteratorRecord(pandaGen, stmt, method, object, type);
pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.False));
pandaGen.storeAccumulator(stmt, doneReg);
let labelTarget = new LabelTarget(endLabel, nextLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
let tryBuilderWithForOf = new TryBuilderWithForOf(compiler, pandaGen, stmt, doneReg, iterator, labelTarget, needCreateLoopEnv, needCreateLoopEnv ? loopEnv : undefined);
compiler.constructTry(stmt, tryBuilderWithForOf, nextLabel);
pandaGen.label(stmt, endLabel);
LabelTarget.popLabelTarget();
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
compiler.popEnv();
}
pandaGen.freeTemps(doneReg, method, object, loopEnv);
compiler.popScope();
}
export function getIteratorRecord(pandagen: PandaGen, node: ts.Node, nextMethod: VReg, object: VReg, type: IteratorType) {
getIterator(pandagen, node, type);
pandagen.storeAccumulator(node, object);
pandagen.loadObjProperty(node, object, "next");
pandagen.storeAccumulator(node, nextMethod);
return new IteratorRecord(object, nextMethod, type);
}
function getIterator(pandagen: PandaGen, node: ts.Node, type: IteratorType) {
if (type == IteratorType.Async) {
// support Async Iterator in the future
throw new Error("Async Iterator haven't been supported");
} else {
pandagen.getIterator(node);
}
}
+107
View File
@@ -0,0 +1,107 @@
/*
* 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.
*/
import * as ts from "typescript";
import * as jshelpers from "../jshelpers";
import { DiagnosticCode, DiagnosticError } from "../diagnostic";
import { TryStatement } from "./tryStatement";
import { Label } from "../irnodes";
export class LabelTarget {
private static name2LabelTarget: Map<string, LabelTarget> = new Map<string, LabelTarget>();
private static labelTargetStack: LabelTarget[] = [];
private breakTargetLabel: Label;
private continueTargetLabel: Label | undefined;
private tryStatement: TryStatement | undefined;
constructor(breakTargetLabel: Label, continueTargetLabel: Label | undefined) {
this.breakTargetLabel = breakTargetLabel;
this.continueTargetLabel = continueTargetLabel;
this.tryStatement = TryStatement.getCurrentTryStatement();
}
getBreakTargetLabel() {
return this.breakTargetLabel;
}
getContinueTargetLabel() {
return this.continueTargetLabel;
}
getTryStatement() {
return this.tryStatement;
}
private static isLabelTargetsEmpty(): boolean {
if (LabelTarget.labelTargetStack.length == 0) {
return true;
}
return false;
}
private static getCloseLabelTarget(): LabelTarget | undefined {
if (!LabelTarget.isLabelTargetsEmpty()) {
return LabelTarget.labelTargetStack[LabelTarget.labelTargetStack.length - 1];
}
return undefined;
}
// this API used for get uplevel continueLabel when compile switchStatement
static getCloseContinueTarget(): Label | undefined {
let labelTarget = LabelTarget.getCloseLabelTarget();
if (labelTarget) {
return labelTarget.continueTargetLabel;
}
return undefined;
}
static pushLabelTarget(labelTarget: LabelTarget) {
LabelTarget.labelTargetStack.push(labelTarget);
}
static popLabelTarget() {
LabelTarget.labelTargetStack.pop();
}
static updateName2LabelTarget(node: ts.Node, labelTarget: LabelTarget) {
while (node.kind == ts.SyntaxKind.LabeledStatement) {
let labeledStmt = <ts.LabeledStatement>node;
let labelName = jshelpers.getTextOfIdentifierOrLiteral(labeledStmt.label);
// make sure saved label is different
if (LabelTarget.name2LabelTarget.has(labelName)) {
throw new DiagnosticError(node, DiagnosticCode.Duplicate_label_0);
}
LabelTarget.name2LabelTarget.set(labelName, labelTarget);
node = node.parent;
}
}
static deleteName2LabelTarget(labelName: string) {
LabelTarget.name2LabelTarget.delete(labelName);
}
static getLabelTarget(stmt: ts.BreakOrContinueStatement): LabelTarget {
let labelTarget: LabelTarget;
if (stmt.label) {
let labelName = jshelpers.getTextOfIdentifierOrLiteral(stmt.label);
labelTarget = LabelTarget.name2LabelTarget.get(labelName)!;
} else {
labelTarget = LabelTarget.getCloseLabelTarget()!;
}
return labelTarget;
}
}
+319
View File
@@ -0,0 +1,319 @@
/*
* 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.
*/
/**
* The loopStatement implementation.
* This file implements compilation process of loop statements
* and uses Pandagen to generate bytecode.
*
*/
import { Variable } from "src/variable";
import * as ts from "typescript";
import { LReference } from "../base/lreference";
import {
CacheList,
getVregisterCache
} from "../base/vregisterCache";
import { Compiler } from "../compiler";
import { Label, VReg } from "../irnodes";
import { LoopScope, Scope } from "../scope";
import { LabelTarget } from "./labelTarget";
export function compileDoStatement(stmt: ts.DoStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let conditionLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, conditionLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let loopEnv = pandaGen.getTemp();
pandaGen.label(stmt, loopStartLabel);
if (needCreateLoopEnv) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
}
compiler.compileStatement(stmt.statement);
pandaGen.label(stmt, conditionLabel);
compiler.compileCondition(stmt.expression, loopEndLabel);
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
}
pandaGen.branch(stmt, loopStartLabel);
pandaGen.label(stmt, loopEndLabel);
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
compiler.popEnv();
}
LabelTarget.popLabelTarget();
pandaGen.freeTemps(loopEnv);
compiler.popScope();
}
export function compileWhileStatement(stmt: ts.WhileStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, new LabelTarget(loopEndLabel, loopStartLabel));
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let loopEnv = pandaGen.getTemp();
pandaGen.label(stmt, loopStartLabel);
compiler.compileCondition(stmt.expression, loopEndLabel);
if (needCreateLoopEnv) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
}
compiler.compileStatement(stmt.statement);
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
}
pandaGen.branch(stmt, loopStartLabel);
pandaGen.label(stmt, loopEndLabel);
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
compiler.popEnv()
}
LabelTarget.popLabelTarget();
pandaGen.freeTemps(loopEnv);
compiler.popScope();
}
export function compileForStatement(stmt: ts.ForStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
// determine if loopenv need to be created
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let loopEnv = pandaGen.getTemp();
let createEnvAtBegining: boolean = false;
if (needCreateLoopEnv) {
// determine the location where loopenv should be created
if (stmt.initializer && ts.isVariableDeclarationList(stmt.initializer)) {
loopScope.getName2variable().forEach(v => {
if (v.isLetOrConst() && v.isLexVar) {
createEnvAtBegining = true;
}
});
}
}
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let incLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, incLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
if (stmt.initializer && ts.isVariableDeclarationList(stmt.initializer) && createEnvAtBegining && needCreateLoopEnv) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
let declList = <ts.VariableDeclarationList>stmt.initializer;
declList.declarations.forEach(decl => compiler.compileVariableDeclaration(decl));
// loopCondition
pandaGen.label(stmt, loopStartLabel);
if (stmt.condition) {
compiler.compileCondition(stmt.condition, loopEndLabel);
}
// loopBody
compiler.compileStatement(stmt.statement);
// loopIncrementor
pandaGen.label(stmt, incLabel);
// load init from current env for the use of the next iteration
type variableInfo = { scope: Scope | undefined, level: number, v: Variable | undefined };
let variables: Map<variableInfo, VReg> = new Map<variableInfo, VReg>();
let tmpVregs: Array<VReg> = new Array<VReg>();
loopScope.getName2variable().forEach((v, name) => {
if (v.isLexVar && v.isLetOrConst()) {
let tmp = pandaGen.getTemp();
tmpVregs.push(tmp);
let varInfo = loopScope.find(name);
variables.set(varInfo, tmp);
compiler.loadTarget(stmt, varInfo);
pandaGen.storeAccumulator(stmt, tmp);
}
});
// pop the current loopenv and create a new loopenv before next iteration
pandaGen.popLexicalEnv(stmt);
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
variables.forEach((reg, varInfo) => {
let slot: number = (<Variable>varInfo.v).idxLex;
// emitStore is not used here to avoid dead-zone check within it, just use storeLexcialVar
pandaGen.storeLexicalVar(stmt, varInfo.level, slot, reg);
})
// must compile incrementor after store the previous value into the corresponding slot, otherwise will fall into a dead loop
if (stmt.incrementor) {
compiler.compileExpression(stmt.incrementor);
}
pandaGen.branch(stmt, loopStartLabel);
pandaGen.label(stmt, loopEndLabel);
pandaGen.popLexicalEnv(stmt);
compiler.popEnv();
pandaGen.freeTemps(...tmpVregs);
} else { // compile for in fast mode
if (stmt.initializer) {
if (ts.isVariableDeclarationList(stmt.initializer)) {
let declList = <ts.VariableDeclarationList>stmt.initializer;
declList.declarations.forEach((decl) => compiler.compileVariableDeclaration(decl));
} else {
compiler.compileExpression(stmt.initializer);
}
}
// loopCondition
pandaGen.label(stmt, loopStartLabel);
// createLoopEnv if needed
if (needCreateLoopEnv) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
}
if (stmt.condition) {
compiler.compileCondition(stmt.condition, loopEndLabel);
}
// loopBody
compiler.compileStatement(stmt.statement);
// loopIncrementor
pandaGen.label(stmt, incLabel);
if (stmt.incrementor) {
compiler.compileExpression(stmt.incrementor);
}
// pop the current loopenv before next iteration
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
}
pandaGen.branch(stmt, loopStartLabel);
pandaGen.label(stmt, loopEndLabel);
if (needCreateLoopEnv) {
pandaGen.popLexicalEnv(stmt);
compiler.popEnv();
}
}
LabelTarget.popLabelTarget();
pandaGen.freeTemps(loopEnv);
compiler.popScope();
}
export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
// init label info;
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
// determine the location where env should be created
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLexEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let createEnvAtBegining: boolean = false;
let loopEnv = pandaGen.getTemp();
if (needCreateLexEnv && ts.isVariableDeclarationList(stmt.initializer)) {
loopScope.getName2variable().forEach(v => {
if (v.isLetOrConst() && v.isLexVar) {
createEnvAtBegining = true;
}
});
}
let iterReg = pandaGen.getTemp();
let propName = pandaGen.getTemp();
// create enumerator
compiler.compileExpression(stmt.expression);
pandaGen.getPropIterator(stmt);
pandaGen.storeAccumulator(stmt, iterReg);
pandaGen.label(stmt, loopStartLabel);
if (needCreateLexEnv && createEnvAtBegining) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
}
// get next prop of enumerator
pandaGen.getNextPropName(stmt, iterReg);
pandaGen.storeAccumulator(stmt, propName);
pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), loopEndLabel);
let lref = LReference.generateLReference(compiler, stmt.initializer, false);
pandaGen.loadAccumulator(stmt, propName);
lref.setValue();
if (needCreateLexEnv && !createEnvAtBegining) {
pandaGen.createLexEnv(stmt, loopEnv, loopScope);
compiler.pushEnv(loopEnv);
}
compiler.compileStatement(stmt.statement);
if (needCreateLexEnv) {
pandaGen.popLexicalEnv(stmt);
}
pandaGen.branch(stmt, loopStartLabel);
pandaGen.label(stmt, loopEndLabel);
if (needCreateLexEnv) {
pandaGen.popLexicalEnv(stmt);
compiler.popEnv();
}
pandaGen.freeTemps(loopEnv, iterReg, propName);
LabelTarget.popLabelTarget();
compiler.popScope();
}
+146
View File
@@ -0,0 +1,146 @@
/*
* 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.
*/
import * as ts from "typescript";
import { CacheList, getVregisterCache } from "../base/vregisterCache";
import { Compiler, ControlFlowChange } from "../compiler";
import { AsyncFunctionBuilder } from "../function/asyncFunctionBuilder";
import { Label, VReg } from "../irnodes";
import * as jshelpers from "../jshelpers";
import { checkValidUseSuperBeforeSuper } from "./classStatement";
export function compileReturnStatement(stmt: ts.ReturnStatement, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let returnValue = pandaGen.getTemp();
if (isReturnInDerivedCtor(stmt)) {
compileReturnInDerivedCtor(stmt, returnValue, compiler);
} else {
compileNormalReturn(stmt, returnValue, compiler);
}
pandaGen.freeTemps(returnValue);
}
function compileReturnInDerivedCtor(stmt: ts.ReturnStatement, returnValue: VReg, compiler: Compiler) {
let pandaGen = compiler.getPandaGen();
let expr = stmt.expression;
let need2CheckSuper = pandaGen.getTemp();
if (!expr) {
pandaGen.moveVreg(stmt, need2CheckSuper, getVregisterCache(pandaGen, CacheList.True));
} else {
if (ts.isCallExpression(expr) && expr.expression.kind == ts.SyntaxKind.SuperKeyword) {
compileNormalReturn(stmt, returnValue, compiler);
pandaGen.freeTemps(need2CheckSuper);
return;
}
if (expr.kind == ts.SyntaxKind.ThisKeyword) {
pandaGen.moveVreg(stmt, need2CheckSuper, getVregisterCache(pandaGen, CacheList.True));
} else {
compiler.compileExpression(expr);
pandaGen.binary(stmt, ts.SyntaxKind.EqualsEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined));
pandaGen.storeAccumulator(stmt, need2CheckSuper);
}
}
let compile = new Label();
let notCompile = new Label();
pandaGen.loadAccumulator(stmt, need2CheckSuper);
pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.False), compile);
// load this
let thisReg = pandaGen.getTemp();
compiler.getThis(stmt, thisReg);
pandaGen.loadAccumulator(stmt, thisReg);
pandaGen.branch(stmt, notCompile);
// compile return expression
pandaGen.label(stmt, compile);
if (expr) {
compiler.compileExpression(expr);
} else {
pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.undefined));
}
pandaGen.label(stmt, notCompile);
pandaGen.storeAccumulator(stmt, returnValue);
compiler.compileFinallyBeforeCFC(
undefined,
ControlFlowChange.Break,
undefined
);
let returnLabel = new Label();
let normalLabel = new Label();
pandaGen.loadAccumulator(stmt, need2CheckSuper);
pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.False), normalLabel);
// check if super has been called
checkValidUseSuperBeforeSuper(compiler, stmt);
pandaGen.branch(stmt, returnLabel);
pandaGen.label(stmt, normalLabel);
// load returnValue to acc
pandaGen.loadAccumulator(stmt, returnValue);
pandaGen.label(stmt, returnLabel);
pandaGen.return(stmt);
pandaGen.freeTemps(need2CheckSuper, thisReg);
}
function compileNormalReturn(stmt: ts.ReturnStatement, returnValue: VReg, compiler: Compiler) {
let expr = stmt.expression;
let pandaGen = compiler.getPandaGen();
if (expr) {
compiler.compileExpression(expr);
} else {
pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.undefined));
}
pandaGen.storeAccumulator(stmt, returnValue);
compiler.compileFinallyBeforeCFC(
undefined,
ControlFlowChange.Break,
undefined
);
pandaGen.loadAccumulator(stmt, returnValue);
let funcBuilder = compiler.getFuncBuilder();
if (funcBuilder instanceof AsyncFunctionBuilder) {
let resovledVal = pandaGen.getTemp();
pandaGen.storeAccumulator(stmt, resovledVal);
funcBuilder.resolve(stmt, resovledVal);
pandaGen.freeTemps(resovledVal);
}
pandaGen.return(stmt);
}
function isReturnInDerivedCtor(stmt: ts.ReturnStatement) {
let ctorNode = jshelpers.findAncestor(stmt, ts.isConstructorDeclaration);
if (ctorNode && ctorNode.parent) {
let classNode = <ts.ClassLikeDeclaration>ctorNode.parent;
if (classNode.heritageClauses) {
return true;
}
}
return false;
}
+136
View File
@@ -0,0 +1,136 @@
/*
* 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.
*/
import * as ts from "typescript";
import {
Label,
VReg
} from "../irnodes";
import { PandaGen } from "../pandagen";
import { Compiler } from "../compiler";
import {
DiagnosticCode,
DiagnosticError
} from "../diagnostic"
import { LabelTarget } from "./labelTarget";
export class SwitchBase {
private stmt: ts.SwitchStatement;
private compiler: Compiler;
private pandaGen: PandaGen;
private caseLabels: Label[] = [];
private switchEndLabel: Label;
constructor(stmt: ts.SwitchStatement, compiler: Compiler, caseNums: number, switchEndLabel: Label) {
this.stmt = stmt;
this.compiler = compiler;
this.pandaGen = compiler.getPandaGen();
this.switchEndLabel = switchEndLabel;
for (let i = 0; i < caseNums; i++) {
let caseLabel = new Label();
this.caseLabels.push(caseLabel);
}
// switchStatements don't have continue target
// so we use the uplevel continue label as it's continue target.
let labelTarget = new LabelTarget(switchEndLabel, LabelTarget.getCloseContinueTarget());
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
}
setCasePosition(index: number) {
let caseTarget = this.stmt.caseBlock.clauses[index];
this.pandaGen.label(caseTarget, this.caseLabels[index]);
}
compileTagOfSwitch(tagReg: VReg) {
this.compiler.compileExpression(this.stmt.expression);
this.pandaGen.storeAccumulator(this.stmt.expression, tagReg);
}
compileCaseStatements(index: number) {
this.stmt.caseBlock.clauses[index].statements.forEach(statement => {
this.compiler.compileStatement(statement);
})
}
JumpIfCase(tag: VReg, index: number) {
let stmt = this.stmt;
let pandaGen = this.pandaGen;
let caseTarget = <ts.CaseClause>stmt.caseBlock.clauses[index];
this.compiler.compileExpression(caseTarget.expression);
pandaGen.condition(caseTarget, ts.SyntaxKind.ExclamationEqualsEqualsToken, tag, this.caseLabels[index]);
}
JumpToDefault(defaultIndex: number) {
let defaultTarget = <ts.DefaultClause>this.stmt.caseBlock.clauses[defaultIndex];
this.pandaGen.branch(defaultTarget, this.caseLabels[defaultIndex]);
}
checkDefaultNum(defaultCnt: number) {
if (defaultCnt > 1) {
throw new DiagnosticError(this.stmt, DiagnosticCode.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement);
}
}
break() {
this.pandaGen.branch(this.stmt, this.switchEndLabel);
}
end() {
this.pandaGen.label(this.stmt, this.switchEndLabel);
}
}
export function compileSwitchStatement(stmt: ts.SwitchStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let caseNums = stmt.caseBlock.clauses.length;
let switchEndLabel = new Label();
let switchBuilder = new SwitchBase(stmt, compiler, caseNums, switchEndLabel);
let tagReg = pandaGen.getTemp();
switchBuilder.compileTagOfSwitch(tagReg);
let caseTargets = stmt.caseBlock.clauses;
let defaultIndex = 0;
let defaultCnt = 0;
for (let i = 0; i < caseTargets.length; i++) {
let caseTarget = caseTargets[i];
if (ts.isDefaultClause(caseTarget)) {
defaultIndex = i;
defaultCnt++;
continue;
}
switchBuilder.JumpIfCase(tagReg, i);
}
switchBuilder.checkDefaultNum(defaultCnt);
if (defaultIndex > 0) {
switchBuilder.JumpToDefault(defaultIndex);
} else {
switchBuilder.break();
}
for (let i = 0; i < caseTargets.length; i++) {
switchBuilder.setCasePosition(i);
switchBuilder.compileCaseStatements(i);
}
switchBuilder.end();
pandaGen.freeTemps(tagReg);
LabelTarget.popLabelTarget();
compiler.popScope();
}
+380
View File
@@ -0,0 +1,380 @@
/*
* 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.
*/
import { Compiler, ControlFlowChange } from "../compiler";
import { Label, VReg } from "../irnodes";
import { PandaGen } from "../pandagen";
import * as ts from "typescript";
import { Recorder } from "../recorder";
import { LocalScope, LoopScope } from "../scope";
import { LReference } from "../base/lreference";
import { LabelTarget } from "./labelTarget";
import {
CacheList,
getVregisterCache
} from "../base/vregisterCache";
import { IteratorType, IteratorRecord } from "./forOfStatement";
import * as astutils from "../astutils";
import { VarDeclarationKind } from "../variable";
// adjust the try...catch...finally into nested try(try...catch) finally
export function transformTryCatchFinally(tryStmt: ts.TryStatement, recorder: Recorder) {
// after create new try block node, mapped with new scope, and adjust parent node
let tryStmtScope = <LocalScope>recorder.getScopeOfNode(tryStmt);
let newTryBlockScope = new LocalScope(tryStmtScope);
let newTryStmtScope = new LocalScope(newTryBlockScope);
(<LocalScope>recorder.getScopeOfNode(tryStmt.tryBlock)).setParent(newTryStmtScope);
(<LocalScope>recorder.getScopeOfNode(tryStmt.catchClause!)).setParent(newTryStmtScope);
const newTryStmt = ts.createTry(tryStmt.tryBlock, tryStmt.catchClause, undefined);
recorder.setScopeMap(newTryStmt, newTryStmtScope);
const newTryBlock = [newTryStmt];
newTryBlock[0].pos = tryStmt.tryBlock.pos;
newTryBlock[0].end = tryStmt.tryBlock.end;
tryStmt.tryBlock = ts.updateBlock(tryStmt.tryBlock, newTryBlock);
newTryBlock[0].parent = tryStmt.tryBlock;
recorder.setScopeMap(tryStmt.tryBlock, newTryBlockScope);
tryStmt.catchClause = undefined;
tryStmt = ts.updateTry(tryStmt, tryStmt.tryBlock, undefined, tryStmt.finallyBlock);
}
export class LabelPair {
private beginLabel: Label;
private endLabel: Label;
constructor(beginLabel: Label, endLabel: Label) {
this.beginLabel = beginLabel;
this.endLabel = endLabel;
}
getBeginLabel() {
return this.beginLabel;
}
getEndLabel() {
return this.endLabel;
}
}
export class CatchTable {
private labelPairs: LabelPair[] = [];
private catchBeginLabel: Label;
private depth: number;
constructor(pandaGen: PandaGen, catchBeginLabel: Label, labelPair: LabelPair) {
this.catchBeginLabel = catchBeginLabel;
this.labelPairs.push(labelPair);
this.depth = TryStatement.getcurrentTryStatementDepth();
pandaGen.getCatchMap().set(catchBeginLabel, this);
}
getLabelPairs() {
return this.labelPairs;
}
getCatchBeginLabel() {
return this.catchBeginLabel;
}
getDepth() {
return this.depth;
}
// split the last labelPair after inline finally.
splitLabelPair(inlinedLabelPair: LabelPair) {
let lastLabelPair = this.labelPairs.pop();
if (lastLabelPair) {
this.labelPairs.push(new LabelPair(lastLabelPair.getBeginLabel(), inlinedLabelPair.getBeginLabel()));
this.labelPairs.push(new LabelPair(inlinedLabelPair.getEndLabel(), lastLabelPair.getEndLabel()));
}
}
}
// record the info of the tryStatement
export class TryStatement {
private static currentTryStatement: TryStatement | undefined;
private static currentTryStatementDepth: number = 0;
private outer: TryStatement | undefined;
private stmt: ts.Statement;
private catchTable: CatchTable;
trybuilder: TryBuilderBase | undefined;
constructor(stmt: ts.Statement, catchTable: CatchTable, trybuilder?: TryBuilderBase) {
TryStatement.currentTryStatementDepth++;
this.outer = TryStatement.currentTryStatement;
this.stmt = stmt;
this.catchTable = catchTable;
if (trybuilder) {
this.trybuilder = trybuilder;
}
TryStatement.currentTryStatement = this;
}
destroy() {
TryStatement.currentTryStatementDepth--;
TryStatement.currentTryStatement = this.outer;
}
static setCurrentTryStatement(tryStatement: TryStatement | undefined) {
TryStatement.currentTryStatement = tryStatement;
}
static getCurrentTryStatement() {
return TryStatement.currentTryStatement;
}
static getcurrentTryStatementDepth() {
return TryStatement.currentTryStatementDepth;
}
getOuterTryStatement() {
return this.outer;
}
getStatement() {
return this.stmt;
}
getCatchTable() {
return this.catchTable;
}
}
export abstract class TryBuilderBase {
protected compiler: Compiler;
protected pandaGen: PandaGen;
protected stmt: ts.Statement;
protected tryStatement: TryStatement | undefined;
constructor(compiler: Compiler, pandaGen: PandaGen, Stmt: ts.Statement) {
this.compiler = compiler;
this.pandaGen = pandaGen;
this.stmt = Stmt;
}
abstract compileTryBlock(catchTable: CatchTable): void;
abstract compileFinallyBlockIfExisted(): void;
abstract compileExceptionHandler(): void;
abstract compileFinalizer(cfc: ControlFlowChange, continueTargetLabel: Label | undefined): void;
}
// generate the bytecode for TryStatement
// compiler just handle the basic controlFlow
export class TryBuilder extends TryBuilderBase {
constructor(compiler: Compiler, pandaGen: PandaGen, tryStmt: ts.TryStatement) {
super(compiler, pandaGen, tryStmt)
}
compileTryBlock(catchTable: CatchTable) {
if ((<ts.TryStatement>this.stmt).finallyBlock) {
this.tryStatement = new TryStatement(this.stmt, catchTable, this);
} else {
this.tryStatement = new TryStatement(this.stmt, catchTable);
}
this.compiler.compileStatement((<ts.TryStatement>this.stmt).tryBlock);
// when compiler is out of TryBlock, reset tryStatement
this.tryStatement.destroy();
}
compileFinallyBlockIfExisted() {
if ((<ts.TryStatement>this.stmt).finallyBlock) {
this.compiler.compileStatement((<ts.TryStatement>this.stmt).finallyBlock!);
}
}
compileExceptionHandler() {
let catchClause = (<ts.TryStatement>this.stmt).catchClause;
if (catchClause) {
this.compiler.pushScope(catchClause);
compileCatchClauseVariableDeclaration(this.compiler, catchClause.variableDeclaration);
let catchBlock = catchClause.block;
catchBlock.statements.forEach((stmt) => this.compiler.compileStatement(stmt));
this.compiler.popScope();
} else {
// finallyBlock rethrow exception when it catch the exception
let exceptionVreg = this.pandaGen.getTemp();
this.pandaGen.storeAccumulator(this.stmt, exceptionVreg);
this.compiler.compileStatement((<ts.TryStatement>this.stmt).finallyBlock!);
this.pandaGen.loadAccumulator(this.stmt, exceptionVreg);
this.pandaGen.throw(this.stmt);
this.pandaGen.freeTemps(exceptionVreg);
}
}
compileFinalizer(cfc: ControlFlowChange, continueTargetLabel: Label) {
this.compiler.compileStatement((<ts.TryStatement>this.stmt).finallyBlock!);
}
}
export class TryBuilderWithForOf extends TryBuilderBase {
private labelTarget: LabelTarget;
private doneReg: VReg;
private iterator: IteratorRecord;
private hasLoopEnv: boolean;
private loopEnv: VReg | undefined;
constructor(compiler: Compiler, pandaGen: PandaGen, forOfStmt: ts.ForOfStatement, doneReg: VReg, iterator: IteratorRecord, labelTarget: LabelTarget, hasLoopEnv: boolean, loopEnv?: VReg) {
super(compiler, pandaGen, forOfStmt);
this.labelTarget = labelTarget;
this.doneReg = doneReg;
this.iterator = iterator;
this.hasLoopEnv = hasLoopEnv;
this.loopEnv = loopEnv ? loopEnv : undefined;
}
compileTryBlock(catchTable: CatchTable) {
let stmt = <ts.ForOfStatement>this.stmt;
let compiler = <Compiler>this.compiler;
let pandaGen = this.pandaGen;
this.tryStatement = new TryStatement(stmt, catchTable, this);
let resultReg = this.pandaGen.getTemp();
let isDeclaration: boolean = false;
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let createLoopEnvAtBegining: boolean = false;
if (ts.isVariableDeclarationList(stmt.initializer)) {
isDeclaration = true;
if (this.hasLoopEnv) {
let decl = stmt.initializer.declarations[0];
let declKind = astutils.getVarDeclarationKind(decl);
if (declKind == VarDeclarationKind.LET || declKind == VarDeclarationKind.CONST) {
createLoopEnvAtBegining = true;
}
}
}
pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.True));
pandaGen.storeAccumulator(stmt, this.doneReg);
pandaGen.label(stmt, this.labelTarget.getContinueTargetLabel()!);
if (this.hasLoopEnv && createLoopEnvAtBegining) {
pandaGen.createLexEnv(stmt, <VReg>this.loopEnv, loopScope);
compiler.pushEnv(<VReg>this.loopEnv);
}
this.compileIteratorNext(stmt, pandaGen, this.iterator, resultReg);
pandaGen.loadObjProperty(stmt, resultReg, "done");
pandaGen.toBoolean(stmt);
pandaGen.condition(
stmt.expression,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.True),
this.labelTarget.getBreakTargetLabel());
pandaGen.loadObjProperty(stmt, resultReg, "value");
pandaGen.storeAccumulator(stmt, resultReg);
pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.False));
pandaGen.storeAccumulator(stmt, this.doneReg);
let lref = LReference.generateLReference(this.compiler, stmt.initializer, isDeclaration);
pandaGen.loadAccumulator(stmt, resultReg);
lref.setValue();
if (this.hasLoopEnv && !createLoopEnvAtBegining) {
pandaGen.createLexEnv(stmt, <VReg>this.loopEnv, loopScope);
compiler.pushEnv(<VReg>this.loopEnv);
}
this.compiler.compileStatement(stmt.statement);
this.tryStatement.destroy();
pandaGen.freeTemps(resultReg);
}
compileFinallyBlockIfExisted() { }
compileExceptionHandler() {
let pandaGen = this.pandaGen;
let noReturn = new Label();
let exceptionVreg = pandaGen.getTemp();
pandaGen.storeAccumulator(this.stmt, exceptionVreg);
pandaGen.loadAccumulator(this.stmt, this.doneReg);
pandaGen.condition(
(<ts.ForOfStatement>this.stmt).expression,
ts.SyntaxKind.ExclamationEqualsEqualsToken,
getVregisterCache(pandaGen, CacheList.True),
noReturn);
// Iterator Close
pandaGen.loadObjProperty(this.stmt, this.iterator.getObject(), "return");
pandaGen.storeAccumulator(this.stmt, this.iterator.getNextMethod());
pandaGen.condition(this.stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), noReturn);
pandaGen.call(this.stmt, [this.iterator.getNextMethod(), this.iterator.getObject()], true);
pandaGen.label(this.stmt, noReturn);
pandaGen.loadAccumulator(this.stmt, exceptionVreg);
pandaGen.throw(this.stmt);
pandaGen.freeTemps(exceptionVreg);
}
compileFinalizer(cfc: ControlFlowChange, continueTargetLabel: Label) {
if (cfc == ControlFlowChange.Break || continueTargetLabel != this.labelTarget.getContinueTargetLabel()) {
let noReturn = new Label();
let innerResult = this.pandaGen.getTemp();
this.pandaGen.loadObjProperty(this.stmt, this.iterator.getObject(), "return");
this.pandaGen.storeAccumulator(this.stmt, this.iterator.getNextMethod());
this.pandaGen.condition(this.stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(this.pandaGen, CacheList.undefined), noReturn);
this.pandaGen.call(this.stmt, [this.iterator.getNextMethod(), this.iterator.getObject()], true);
this.pandaGen.storeAccumulator(this.stmt, innerResult);
this.pandaGen.throwIfNotObject(this.stmt, innerResult);
this.pandaGen.label(this.stmt, noReturn);
this.pandaGen.freeTemps(innerResult);
}
}
private compileIteratorNext(stmt: ts.ForOfStatement, pandagen: PandaGen, iterator: IteratorRecord, resultObj: VReg) {
pandagen.call(stmt, [iterator.getNextMethod(), iterator.getObject()], true);
pandagen.storeAccumulator(stmt, resultObj);
// Support Async Await further
pandagen.throwIfNotObject(stmt, resultObj);
}
}
function compileCatchClauseVariableDeclaration(compiler: Compiler, param: ts.VariableDeclaration | undefined) {
if (param) {
compiler.compileVariableDeclaration(param);
}
}
export function updateCatchTables(inlinedTry: TryStatement | undefined, targetTry: TryStatement, inlinedLabelPair: LabelPair) {
for (; inlinedTry != targetTry; inlinedTry = inlinedTry ?.getOuterTryStatement()) {
inlinedTry!.getCatchTable().splitLabelPair(inlinedLabelPair);
}
targetTry.getCatchTable().splitLabelPair(inlinedLabelPair);
}
export function generateCatchTables(catchMap: Map<Label, CatchTable>): CatchTable[] {
let catchTableList: CatchTable[] = [];
catchMap.forEach((catchTable) => {
catchTableList.push(catchTable)
});
catchTableList.sort((a, b) => (b.getDepth() - a.getDepth()));
return catchTableList;
}
+92
View File
@@ -0,0 +1,92 @@
/*
* 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.
*/
import * as ts from "typescript";
import jshelpers from "./jshelpers";
let globalStrict = false;
export function checkStrictModeStatementList(node: ts.Node): boolean {
let statements;
if (node.kind == ts.SyntaxKind.SourceFile) {
statements = (<ts.SourceFile>node).statements;
} else {
let decl = <ts.FunctionLikeDeclaration>node;
if (decl && decl.body) {
if (decl.body.kind == ts.SyntaxKind.Block) {
statements = (<ts.Block>decl.body).statements;
}
} else {
return false;
}
}
if (statements == undefined) {
return false;
}
for (const statement of statements) {
if (!jshelpers.isPrologueDirective(statement)) {
return false;
}
if (isUseStrictPrologueDirective(<ts.ExpressionStatement>statement)) {
return true;
}
}
return false;
}
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
function isUseStrictPrologueDirective(node: ts.ExpressionStatement): boolean {
let file = jshelpers.getSourceFileOfNode(node);
const nodeText = jshelpers.getSourceTextOfNodeFromSourceFile(file, node.expression);
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
// string to contain unicode escapes (as per ES5).
return nodeText === '"use strict"' || nodeText === "'use strict'";
}
function checkStrictMode(node: ts.Node): boolean {
while (node && node.parent && node.parent.kind != ts.SyntaxKind.SourceFile) {
let func = jshelpers.getContainingFunctionDeclaration(node);
if (!func) {
return false;
}
if (checkStrictModeStatementList(func)) {
return true;
}
node = <ts.FunctionLikeDeclaration>func;
}
return false;
}
function getGlobalStrict(): boolean {
return globalStrict;
}
export function setGlobalStrict(flag: boolean) {
globalStrict = flag;
}
export function isStrictMode(node: ts.Node): boolean {
if (getGlobalStrict()) {
return true;
}
return checkStrictMode(node);
}
+273
View File
@@ -0,0 +1,273 @@
/*
* 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.
*/
import * as ts from "typescript";
import jshelpers = require("./jshelpers");
export function isOctalNumber(num: string): boolean {
if (!num || num.length < 2) {
return false;
}
let reg = /^0[0-7]+$/;
if (!reg.test(num)) {
return false;
}
return true;
}
export function isNewOrCallExpression(node: ts.Node): boolean {
return node.kind === ts.SyntaxKind.NewExpression || node.kind === ts.SyntaxKind.CallExpression;
}
export function stringLiteralIsInRegExp(node: ts.Node) {
let parent = node.parent;
if (parent && isNewOrCallExpression(parent)) {
let expression = (<ts.NewExpression | ts.CallExpression>parent).expression;
if (ts.isIdentifier(expression)) {
if (expression.escapedText === "RegExp") {
return true;
}
}
}
return false;
}
export function isIncludeOctalEscapeSequence(text: string): boolean {
let reg = /\\(?:[1-7][0-7]{0,2}|[0-7]{2,3})/g;
if (!text.match(reg)) {
return false;
}
// Like \\1, should not be treated as an octal escape sequence
let index = 0;
while (index < text.length) {
if (text[index] == '\\' && index != text.length - 1) {
if (text[index + 1] == "\\") {
index++;
} else if (text[index + 1] >= '0' && text[index + 1] <= '7') {
return true;
}
}
index++;
}
return false;
}
export function isEvalOrArgumentsIdentifier(node: ts.Node): boolean {
return ts.isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
}
export function isLeftHandSideExpressionKind(kind: ts.SyntaxKind) {
switch (kind) {
case ts.SyntaxKind.NumericLiteral:
case ts.SyntaxKind.BigIntLiteral:
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.RegularExpressionLiteral:
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.Identifier:
case ts.SyntaxKind.FalseKeyword:
case ts.SyntaxKind.ImportKeyword:
case ts.SyntaxKind.NullKeyword:
case ts.SyntaxKind.SuperKeyword:
case ts.SyntaxKind.ThisKeyword:
case ts.SyntaxKind.TrueKeyword:
case ts.SyntaxKind.ArrayLiteralExpression:
case ts.SyntaxKind.ObjectLiteralExpression:
case ts.SyntaxKind.PropertyAccessExpression:
case ts.SyntaxKind.ElementAccessExpression:
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.NewExpression:
case ts.SyntaxKind.TaggedTemplateExpression:
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.TemplateExpression:
case ts.SyntaxKind.ClassExpression:
case ts.SyntaxKind.NonNullExpression:
case ts.SyntaxKind.MetaProperty:
case ts.SyntaxKind.JsxElement:
case ts.SyntaxKind.JsxSelfClosingElement:
case ts.SyntaxKind.JsxFragment:
return true;
default:
return false;
}
}
export function isLeftHandSideExpression(node: ts.Node) {
return isLeftHandSideExpressionKind(ts.skipPartiallyEmittedExpressions(node).kind);
}
export function isAssignmentOperator(token: ts.SyntaxKind) {
return token >= ts.SyntaxKind.FirstAssignment && token <= ts.SyntaxKind.LastAssignment;
}
export function isOriginalKeyword(node: ts.Identifier): boolean {
if (node.originalKeywordKind! >= ts.SyntaxKind.FirstFutureReservedWord &&
node.originalKeywordKind! <= ts.SyntaxKind.LastFutureReservedWord) {
return true;
}
return false;
}
export function isFunctionLikeDeclaration(node: ts.Node): node is ts.FunctionLikeDeclaration {
if (!node) {
return false;
}
switch (node.kind) {
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.SetAccessor:
return true;
default:
return false;
}
}
export function allowLetAndConstDeclarations(node: ts.Node): boolean {
if (!node) {
return false;
}
switch (node.kind) {
case ts.SyntaxKind.DoStatement:
case ts.SyntaxKind.IfStatement:
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.ForOfStatement:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.WithStatement:
return false;
case ts.SyntaxKind.LabeledStatement:
return allowLetAndConstDeclarations(node.parent);
default:
break;
}
return true;
}
export function isGlobalIdentifier(name: string) {
switch (name) {
case "NaN":
case "undefined":
case "Infinity":
return true;
default:
return false;
}
}
export function isBindingPattern(node: ts.Node | undefined): boolean {
if (!node) {
return false;
}
switch (node.kind) {
case ts.SyntaxKind.ArrayBindingPattern:
case ts.SyntaxKind.ObjectBindingPattern:
return true;
default:
return false;
}
}
export function visibilityToString(flag: ts.ModifierFlags): string | undefined {
switch (flag) {
case ts.ModifierFlags.Private:
return "private";
case ts.ModifierFlags.Protected:
return "protected";
default:
return "public";
}
}
export function isDeclInGlobal(id: ts.Identifier): boolean {
let parent = id.parent;
while ((parent) && (parent.kind != ts.SyntaxKind.Block)) {
parent = parent.parent;
}
if (!parent) {
return true;
}
return false;
}
export function isInBlockScope(node: ts.Node): boolean {
switch (node.kind) {
case ts.SyntaxKind.SourceFile:
case ts.SyntaxKind.CaseBlock:
case ts.SyntaxKind.DefaultClause:
case ts.SyntaxKind.CaseClause:
case ts.SyntaxKind.Block:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.MethodDeclaration:
return true;
default:
break;
}
return false;
}
export function isIncludeBackslash8Or9InString(text: string): boolean {
// \8 and \9 are not allowed in strict mode
let index = 0;
while (index < text.length) {
if (text[index] == '\\' && index != text.length - 1) {
if (text[index + 1] == "\\") {
index++;
} else if (text[index + 1] == '8' || text[index + 1] == '9') {
return true;
}
}
index++;
}
return false;
}
export function isOptionalParameter(node: ts.ParameterDeclaration): boolean {
if (jshelpers.hasQuestionToken(node)) {
return true;
}
let iife = jshelpers.getImmediatelyInvokedFunctionExpression(node.parent);
if (iife) {
return !node.type && !node.dotDotDotToken && node.parent.parameters.indexOf(node) >= iife.arguments.length;
}
return false;
}
export function isStatement(kind: ts.SyntaxKind) {
if (kind >= ts.SyntaxKind.FirstStatement && kind <= ts.SyntaxKind.LastStatement) {
return true;
}
return false;
}
File diff suppressed because it is too large Load Diff
+236
View File
@@ -0,0 +1,236 @@
/*
* 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.
*/
import * as ts from "typescript";
import { CmdOptions } from "./cmdOptions";
import { DiagnosticCode, DiagnosticError } from "./diagnostic";
import { findInnerExprOfParenthesis } from "./expression/parenthesizedExpression";
import jshelpers from "./jshelpers";
import { checkStrictModeStatementList } from "./strictMode";
import {
isAssignmentOperator,
isEvalOrArgumentsIdentifier,
isInBlockScope,
isIncludeOctalEscapeSequence,
isLeftHandSideExpression,
isOctalNumber,
isOriginalKeyword,
stringLiteralIsInRegExp
} from "./syntaxCheckHelper";
function checkDeleteStatement(node: ts.DeleteExpression) {
let unaryExpr = node.expression;
if (ts.isIdentifier(unaryExpr)) {
throw new DiagnosticError(unaryExpr, DiagnosticCode.A_delete_cannot_be_called_on_an_identifier_in_strict_mode);
}
}
function checkNumericLiteral(node: ts.NumericLiteral) {
let num = jshelpers.getTextOfNode(node);
if (!isOctalNumber(num)) {
return;
}
throw new DiagnosticError(node, DiagnosticCode.Octal_literals_are_not_allowed_in_strict_mode);
}
function checkString(node: ts.Node, text: string) {
if (isIncludeOctalEscapeSequence(text)) {
throw new DiagnosticError(node, DiagnosticCode.Octal_escape_sequences_are_not_allowed_in_strict_mode);
}
if (isIncludeOctalEscapeSequence(text)) {
throw new DiagnosticError(node, DiagnosticCode._8_and_9_are_not_allowed_in_strict_mode);
}
}
function checkStringLiteral(node: ts.StringLiteral) {
// Octal escape has been deprecated in ES5, but it can be used in regular expressions.
if (stringLiteralIsInRegExp(node)) {
return;
}
let text = jshelpers.getTextOfNode(node);
checkString(node, text);
}
function checkEvalOrArgumentsOrOriginalKeyword(contextNode: ts.Node, name: ts.Node | undefined) {
if (!name || !ts.isIdentifier(name)) {
return;
}
let identifier = <ts.Identifier>name;
if (!isEvalOrArgumentsIdentifier(identifier) && !isOriginalKeyword(identifier)) {
return;
}
let file = jshelpers.getSourceFileOfNode(name);
let args = [ts.idText(identifier)];
throw new DiagnosticError(name, getStrictModeEvalOrArgumentsDiagnosticCode(contextNode), file, args);
}
function getStrictModeEvalOrArgumentsDiagnosticCode(node: ts.Node) {
if (jshelpers.getContainingClass(node)) {
return DiagnosticCode.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode;
}
return DiagnosticCode.Invalid_use_of_0_in_strict_mode;
}
function getStrictModeIdentifierDiagnosticCode(node: ts.Node) {
if (jshelpers.getContainingClass(node)) {
return DiagnosticCode.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode;
}
return DiagnosticCode.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
}
function checkBinaryExpression(node: ts.BinaryExpression) {
if (!isLeftHandSideExpression(node.left) || !isAssignmentOperator(node.operatorToken.kind)) {
return;
}
let contextNode = <ts.Node>node;
let name = node.left;
switch (node.left.kind) {
case ts.SyntaxKind.ParenthesizedExpression: {
let expr = findInnerExprOfParenthesis(<ts.ParenthesizedExpression>(node.left));
contextNode = <ts.Node>expr;
name = expr;
break;
}
default:
break;
}
checkEvalOrArgumentsOrOriginalKeyword(contextNode, <ts.Identifier>name);
}
function checkContextualIdentifier(node: ts.Identifier) {
let file = jshelpers.getSourceFileOfNode(node);
if (jshelpers.getTextOfIdentifierOrLiteral(node) == 'await' && CmdOptions.isModules()) {
throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, file, ['await']);
}
if (jshelpers.isIdentifierName(node)) {
return;
}
if (isOriginalKeyword(node)) {
throw new DiagnosticError(node, getStrictModeIdentifierDiagnosticCode(node), file, jshelpers.declarationNameToString(node));
}
}
function checkParameters(decl: ts.FunctionLikeDeclaration | ts.FunctionExpression) {
let parameters: ts.NodeArray<ts.ParameterDeclaration> = decl.parameters;
let obj = new Map();
for (let i = 0; i < parameters.length; i++) {
let param = parameters[i];
checkEvalOrArgumentsOrOriginalKeyword(param, param.name);
let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>param.name);
if (obj.has(name)) {
let args: (string | number)[] = [jshelpers.declarationNameToString(param.name)];
throw new DiagnosticError(param.name, DiagnosticCode.Duplicate_identifier_0, undefined, args);
}
if (name) {
obj.set(name, true);
}
if (param.initializer || param.dotDotDotToken) {
if (checkStrictModeStatementList(decl)) {
throw new DiagnosticError(param, DiagnosticCode.use_strict_directive_cannot_be_used_with_non_simple_parameter_list);
}
}
}
}
function checkWithStatement(node: ts.WithStatement) {
let file = jshelpers.getSourceFileOfNode(node);
throw new DiagnosticError(node, DiagnosticCode.A_with_statements_are_not_allowed_in_strict_mode, file);
}
function checkNoSubstitutionTemplateLiteral(expr: ts.NoSubstitutionTemplateLiteral) {
let text = jshelpers.getTextOfNode(expr);
checkString(expr, text.substring(1, text.length - 1));
}
function checkFunctionDeclaration(node: ts.FunctionDeclaration) {
checkEvalOrArgumentsOrOriginalKeyword(node, node.name);
checkParameters(node);
if (!isInBlockScope(node.parent!)) {
throw new DiagnosticError(node, DiagnosticCode.In_strict_mode_code_functions_can_only_be_declared_at_top_level_or_inside_a_block);
}
}
export function checkSyntaxErrorForStrictMode(node: ts.Node) {
switch (node.kind) {
case ts.SyntaxKind.NumericLiteral:
checkNumericLiteral(<ts.NumericLiteral>node);
break;
case ts.SyntaxKind.StringLiteral:
checkStringLiteral(<ts.StringLiteral>node);
break;
case ts.SyntaxKind.FunctionDeclaration:
checkFunctionDeclaration(<ts.FunctionDeclaration>node);
break;
case ts.SyntaxKind.FunctionExpression:
let funcNode = <ts.FunctionExpression>node;
checkEvalOrArgumentsOrOriginalKeyword(funcNode, funcNode.name);
checkParameters(funcNode);
break;
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.ArrowFunction:
checkParameters(<ts.FunctionLikeDeclaration | ts.FunctionExpression>node);
break;
case ts.SyntaxKind.VariableDeclaration:
let varNode = <ts.VariableDeclaration>node;
checkEvalOrArgumentsOrOriginalKeyword(varNode, varNode.name);
break;
case ts.SyntaxKind.BindingElement:
let bindNode = <ts.BindingElement>node;
checkEvalOrArgumentsOrOriginalKeyword(node, bindNode.name);
break;
case ts.SyntaxKind.BinaryExpression:
checkBinaryExpression(<ts.BinaryExpression>node);
break;
case ts.SyntaxKind.PrefixUnaryExpression:
case ts.SyntaxKind.PostfixUnaryExpression:
let unaryNode = <ts.PrefixUnaryExpression | ts.PostfixUnaryExpression>node;
checkEvalOrArgumentsOrOriginalKeyword(node, unaryNode.operand);
break;
case ts.SyntaxKind.DeleteExpression:
checkDeleteStatement(<ts.DeleteExpression>node);
break;
case ts.SyntaxKind.WithStatement:
checkWithStatement(<ts.WithStatement>node);
break;
case ts.SyntaxKind.Identifier:
checkContextualIdentifier(<ts.Identifier>node);
break;
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.FirstTemplateToken:
case ts.SyntaxKind.LastLiteralToken:
checkNoSubstitutionTemplateLiteral(<ts.NoSubstitutionTemplateLiteral>node);
break;
default:
break;
}
}
+229
View File
@@ -0,0 +1,229 @@
/*
* 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.
*/
import { CmdOptions } from "./cmdOptions";
import { DebugPosInfo } from "./debuginfo";
import {
BuiltinR2i,
Imm,
IRNode,
Label,
OperandType,
VReg
} from "./irnodes";
import { LOGD } from "./log";
import { PandaGen } from "./pandagen";
import { CatchTable, Function, Ins, Signature } from "./pandasm";
import { generateCatchTables } from "./statement/tryStatement";
import { escapeUnicode } from "./base/util";
const dollarSign: RegExp = /\$/g;
const JsonType = {
"function": 0,
"record": 1,
"string": 2,
"literal_arr": 3,
"options": 4
};
export class Ts2Panda {
static strings: Set<string> = new Set();
static labelPrefix = "LABEL_";
static jsonString: string = "";
constructor() {
}
static getFuncSignature(pg: PandaGen): Signature {
return new Signature(pg.getParametersCount());
}
static getFuncInsnsAndRegsNum(pg: PandaGen) {
let insns: Array<Ins> = [];
let labels: Array<string> = [];
pg.getInsns().forEach((insn: IRNode) => {
let insOpcode = insn.mnemonic;
let insRegs: Array<number> = [];
let insIds: Array<string> = [];
let insImms: Array<number> = [];
let insLabel: string = "";
let insDebugInfo: DebugPosInfo = new DebugPosInfo();
if (insn instanceof Label) {
insLabel = Ts2Panda.labelPrefix + insn.id;
labels.push(insLabel);
} else if (insn instanceof BuiltinR2i) {
// BuiltinR2i's format is builtin.r2i imm1, imm2, v:in:top
// and it may represent DynRange insn so we only pass the first vreg
let operands = insn.operands;
insImms.push((<Imm>operands[0]).value, (<Imm>operands[1]).value);
insRegs.push((<VReg>operands[2]).num);
} else {
insn.operands.forEach((operand: OperandType) => {
if (operand instanceof VReg) {
let v = <VReg>operand;
insRegs.push(v.num);
} else if (operand instanceof Imm) {
let imm = <Imm>operand;
insImms.push(imm.value);
} else if (typeof (operand) === "string") {
insIds.push(operand);
Ts2Panda.strings.add(operand);
} else if (operand instanceof Label) {
let labelName = Ts2Panda.labelPrefix + operand.id;
insIds.push(labelName);
}
});
}
insDebugInfo = insn.debugPosInfo;
if (CmdOptions.isDebugMode()) {
insDebugInfo.ClearMembersForDebugBuild();
} else {
insDebugInfo.ClearMembersForReleaseBuild();
}
insns.push(new Ins(
insOpcode,
insRegs.length == 0 ? undefined : insRegs,
insIds.length == 0 ? undefined : insIds,
insImms.length == 0 ? undefined : insImms,
insLabel === "" ? undefined : insLabel,
insDebugInfo,
));
});
return {
insns: insns,
regsNum: (pg.getTotalRegsNum() - pg.getParametersCount()),
labels: labels
};
}
static dumpStringsArray(ts2abc: any) {
let strings_arr = Array.from(Ts2Panda.strings);
if (CmdOptions.isEnableDebugLog()) {
Ts2Panda.jsonString += escapeUnicode(JSON.stringify(strings_arr, null, 2));
}
strings_arr.forEach(function(str){
let strObject = {
"type": JsonType.string,
"string": str
}
let jsonStrUnicode = escapeUnicode(JSON.stringify(strObject, null, 2));
Ts2Panda.jsonString += jsonStrUnicode;
jsonStrUnicode = "$" + jsonStrUnicode.replace(dollarSign, '#$') + "$";
ts2abc.stdio[3].write(jsonStrUnicode + '\n');
});
}
static dumpConstantPool(ts2abc: any): void {
let literalArrays = PandaGen.getLiteralArrayBuffer();
if (CmdOptions.isEnableDebugLog()) {
Ts2Panda.jsonString += escapeUnicode(JSON.stringify(literalArrays, null, 2));
}
literalArrays.forEach(function(literalArray){
let literalArrayObject = {
"type": JsonType.literal_arr,
"literalArray": literalArray
}
let jsonLiteralArrUnicode = escapeUnicode(JSON.stringify(literalArrayObject, null, 2));
jsonLiteralArrUnicode = "$" + jsonLiteralArrUnicode.replace(dollarSign, '#$') + "$";
ts2abc.stdio[3].write(jsonLiteralArrUnicode + '\n');
});
}
static dumpCmdOptions(ts2abc: any): void {
let options = {
"type": JsonType.options,
"module_mode": CmdOptions.isModules(),
"debug_mode": CmdOptions.isDebugMode(),
"log_enabled": CmdOptions.isEnableDebugLog(),
"opt_level": CmdOptions.getOptLevel(),
"opt_log_level": CmdOptions.getOptLogLevel()
};
let jsonOpt = JSON.stringify(options, null, 2);
if (CmdOptions.isEnableDebugLog()) {
Ts2Panda.jsonString += jsonOpt;
}
jsonOpt = "$" + jsonOpt.replace(dollarSign, '#$') + "$";
ts2abc.stdio[3].write(jsonOpt + '\n');
}
static dumpPandaGen(pg: PandaGen, ts2abc: any): void {
let funcName = pg.internalName;
let funcSignature = Ts2Panda.getFuncSignature(pg);
let funcInsnsAndRegsNum = Ts2Panda.getFuncInsnsAndRegsNum(pg);
let sourceFile = pg.getSourceFileDebugInfo();
let icSize = pg.getICSize();
let parameterLength = pg.getParameterLength();
let realName = pg.getFuncName();
let variables, sourceCode;
if (CmdOptions.isDebugMode()) {
variables = pg.getVariableDebugInfoArray();
sourceCode = pg.getSourceCodeDebugInfo();
} else {
variables = undefined;
sourceCode = undefined;
}
let func = new Function(
funcName,
funcSignature,
funcInsnsAndRegsNum.regsNum,
funcInsnsAndRegsNum.insns,
funcInsnsAndRegsNum.labels,
variables,
sourceFile,
sourceCode,
icSize,
parameterLength,
realName
);
let catchTables = generateCatchTables(pg.getCatchMap());
catchTables.forEach((catchTable) => {
let catchBeginLabel = catchTable.getCatchBeginLabel();
let labelPairs = catchTable.getLabelPairs();
labelPairs.forEach((labelPair) => {
func.catchTables.push(new CatchTable(
Ts2Panda.labelPrefix + labelPair.getBeginLabel().id,
Ts2Panda.labelPrefix + labelPair.getEndLabel().id,
Ts2Panda.labelPrefix + catchBeginLabel.id
));
});
});
LOGD(func);
let funcObject = {
"type": JsonType.function,
"func_body": func
}
let jsonFuncUnicode = escapeUnicode(JSON.stringify(funcObject, null, 2));
if (CmdOptions.isEnableDebugLog()) {
Ts2Panda.jsonString += jsonFuncUnicode;
}
jsonFuncUnicode = "$" + jsonFuncUnicode.replace(dollarSign, '#$') + "$";
ts2abc.stdio[3].write(jsonFuncUnicode + '\n');
}
static clearDumpData() {
Ts2Panda.strings.clear();
Ts2Panda.jsonString = "";
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../build",
"incremental": true,
"tsBuildInfoFile": "../build/src/tsconfig.tsbuildinfo",
"composite": true,
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../build-mac",
"incremental": true,
"tsBuildInfoFile": "../build-mac/src/tsconfig.tsbuildinfo",
"composite": true
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../build-win",
"incremental": true,
"tsBuildInfoFile": "../build-win/src/tsconfig.tsbuildinfo",
"composite": true
}
}
+178
View File
@@ -0,0 +1,178 @@
/*
* 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.
*/
import { VReg } from "./irnodes";
import {
InitStatus,
LoopScope,
VariableScope
} from "./scope";
export enum VarDeclarationKind {
NONE,
LET,
CONST,
VAR,
FUNCTION,
MODULE,
CLASS
}
export abstract class Variable {
private vreg: VReg | undefined;
private name: string;
isLexVar: boolean = false;
idxLex: number = 0;
constructor(
readonly declKind: VarDeclarationKind,
name: string
) {
this.name = name;
this.vreg = undefined;
this.name = name;
}
bindVreg(vreg: VReg) {
this.vreg = vreg;
}
hasAlreadyBinded(): boolean {
return this.vreg !== undefined;
}
getVreg(): VReg {
if (!this.vreg) {
throw new Error("variable has not been binded")
}
return this.vreg;
}
getName() {
return this.name;
}
setLexVar(scope: VariableScope | LoopScope) {
this.idxLex = scope.getLexVarIdx()
scope.pendingCreateEnv();
this.isLexVar = true;
}
clearLexVar() {
this.isLexVar = false;
this.idxLex = 0;
}
isLet(): boolean {
return this.declKind == VarDeclarationKind.LET;
}
isConst(): boolean {
return this.declKind == VarDeclarationKind.CONST;
}
isLetOrConst(): boolean {
return this.declKind == VarDeclarationKind.LET || this.declKind == VarDeclarationKind.CONST;
}
isVar(): boolean {
return this.declKind == VarDeclarationKind.VAR;
}
isNone(): boolean {
return this.declKind == VarDeclarationKind.NONE;
}
isClass(): boolean {
return this.declKind == VarDeclarationKind.CLASS;
}
}
export class LocalVariable extends Variable {
status: InitStatus | null;
isExport: boolean = false;
exportedName: string = "";
constructor(declKind: VarDeclarationKind, name: string, status?: InitStatus) {
super(declKind, name);
this.status = status ? status : null;
}
initialize() {
this.status = InitStatus.INITIALIZED;
}
isInitialized() {
if (this.status != null) {
return this.status == InitStatus.INITIALIZED;
}
return true;
}
setExport() {
this.isExport = true;
}
isExportVar() {
return this.isExport;
}
setExportedName(name: string) {
this.exportedName = name;
}
getExportedName() {
if (!this.exportedName) {
throw new Error("Exported Variable " + this.getName() + " doesn't have exported name");
}
return this.exportedName;
}
}
export class ModuleVariable extends LocalVariable {
private module: VReg | undefined;
private exoticName: string = "";
constructor(declKind: VarDeclarationKind, name: string, status: InitStatus) {
super(declKind, name, status);
}
bindModuleVreg(vreg: VReg) {
this.module = vreg;
}
setExoticName(exoticName: string) {
this.exoticName = exoticName;
}
getExoticName() {
if (this.exoticName == "") {
throw new Error("Variable doesn't have exotic name");
}
return this.exoticName;
}
getModule() {
if (!this.module) {
throw new Error("Variable's module has not been binded");
}
return this.module;
}
}
export class GlobalVariable extends Variable {
constructor(declKind: VarDeclarationKind, name: string) {
super(declKind, name);
}
}
+114
View File
@@ -0,0 +1,114 @@
// 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.
// Autogenerated file -- DO NOT EDIT!
import * as ir from "./irnodes";
export const builtinsCodeMap = {
% PandaBuiltins::instructions.each do |instr|
% sig = instr['sig']
% args = sig.split(/,?\s+/)
% args_len = args.length()
% builtin_num_of_instr = 0;
"<%= instr.mnemonic %>" : {
% PandaBuiltins::builtins.each do |builtin|
% if builtin.insn == instr.mnemonic
"<%= builtin.mnemonic %>" : <%= builtin.id %>,
<%= builtin.id %> : "<%= builtin.mnemonic %>",
% end
% end
},
% end
};
% def insn2node(insn)
% mnemonic = insn.mnemonic.split('.')
% return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join()
% end
export class BuiltinExpander {
static getSubCode(ins: ir.Intrinsic): number | undefined {
for (let key in builtinsCodeMap) {
let code = (builtinsCodeMap as any)[key][ins.mnemonic];
if (code != undefined) {
return code;
}
}
return undefined;
}
static expand2Builtin(ins: ir.Intrinsic, operands: ir.OperandType[]) {
let code = this.getSubCode(ins);
if ((code == undefined) || (code >= 256)) {
throw new Error("Intrinsic getSubCode subcode(" + ins.mnemonic + ") ir = " + ins.toString());
}
let codeImm = new ir.Imm(ir.ResultType.Int, code);
let newNode;
switch (ins.mnemonic) {
% PandaBuiltins::instructions.each do |instr|
% sig = instr['sig']
% args = sig.split(/,?\s+/)
% args_len = args.length()
% builtin_num_of_instr = 0;
% PandaBuiltins::builtins.each do |builtin|
% if builtin.insn == instr.mnemonic
% builtin_num_of_instr += 1;
case "<%= builtin.sig.split(' ')[0]%>":
% end
% end
% if builtin_num_of_instr > 0
% parameters = ""
% for i in 2..args_len-1 # ignore first two opcode
% if (args[i].start_with?("imm"))
if (!(operands[<%= i-2%>] instanceof ir.Imm)) {
throw new Error("<%= i-2%> parameters must be Imm <" + ins.toString() + ">");
% parameters += ", <ir.Imm>operands[" + (i-2).to_s + "]"
}
% elsif (args[i].start_with?("v"))
if (!(operands[<%= i-2%>] instanceof ir.VReg)) {
throw new Error("<%= i-2%> parameters must be VReg <" + ins.toString() + ">");
% parameters += ", <ir.VReg>operands[" + (i-2).to_s + "]"
}
% elsif (args[i].include?("string_id"))
if (typeof(operands[<%= i-2%>]) != 'string') {
throw new Error("<%= i-2%> parameters must be string <" + ins.toString() + ">");
% parameters += ", <string>operands[" + (i-2).to_s + "]"
}
% elsif (args[i].include?("method_id"))
if (typeof(operands[<%= i-2%>]) != 'string') {
throw new Error("<%= i-2%> parameters must be string <" + ins.toString() + ">");
% parameters += ", <string>operands[" + (i-2).to_s + "]"
}
% else
% raise "Unknown parameters type"
% end
% end
% if insn2node(instr) == "BuiltinR2i"
let imm = <ir.Imm>operands[0];
operands.shift();
newNode = new ir.<%= insn2node(instr)%>(codeImm, imm, <ir.VReg[]>operands);
break;
% else
newNode = new ir.<%= insn2node(instr)%>(codeImm<%= parameters%>);
break;
% end
% end
% end
default:
throw new Error("Intrinsic can't found subcode(" + ins.mnemonic + ") ir = " + ins.toString());
}
return newNode;
}
}
+186
View File
@@ -0,0 +1,186 @@
// 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.
import * as ts from "typescript";
import * as jshelpers from "./jshelpers"
import { LOGE } from "./log"
export class DiagnosticError {
irnode:ts.Node | undefined;
code:number;
file: ts.Node | undefined;
args: (string | number | undefined)[];
constructor(irnode:ts.Node | undefined, code:number,file?:ts.Node | undefined ,args?:(string | number | undefined)[]) {
this.code = code
this.irnode = irnode
this.file = file ? file : undefined
this.args = args ? args : []
}
}
export function printDiagnostic(diagnostic: ts.Diagnostic) {
let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
if (diagnostic.file && diagnostic.start!= undefined) {
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
LOGE(`${diagnostic.file.fileName} (${line + 1},${character + 1})`, `${message}`);
} else {
LOGE("Error",message);
}
}
export function createDiagnosticOnFirstToken(file:ts.Node | undefined,node: ts.Node ,message: ts.DiagnosticMessage|ts.DiagnosticMessageChain,...args:(string | number | undefined)[]) {
let span = jshelpers.getSpanOfTokenAtPosition(file, node.pos);
let diagnostic = jshelpers.createFileDiagnostic(file,span.start,span.length,message,...args);
return diagnostic;
}
export function createFileDiagnostic(file:ts.Node|undefined,node: ts.Node , message: ts.DiagnosticMessage|ts.DiagnosticMessageChain,...args:(string | number | undefined)[]) {
let diagnostic;
let span = jshelpers.getErrorSpanForNode(file, node);
switch (node.kind) {
case ts.SyntaxKind.Identifier:
diagnostic = jshelpers.createFileDiagnostic(file,span.start,span.length,message,ts.idText(<ts.Identifier>node));
break;
case ts.SyntaxKind.PrivateIdentifier:
diagnostic = jshelpers.createFileDiagnostic(file,span.start,span.length,message,ts.idText(<ts.PrivateIdentifier>node));
break;
case ts.SyntaxKind.ReturnStatement:
diagnostic = createDiagnosticOnFirstToken(file,node,message,...args);
break;
default:
diagnostic = jshelpers.createFileDiagnostic(file,span.start,span.length,message,...args);
break;
}
return diagnostic;
}
export function createDiagnostic(file:ts.Node|undefined, location: ts.Node | undefined, message: ts.DiagnosticMessage|ts.DiagnosticMessageChain,...args:(string | number | undefined)[]) {
var diagnostic;
if (!location) {
return jshelpers.createCompilerDiagnostic(message, ...args);
}
if (file) {
diagnostic = createFileDiagnostic(file,location,message,...args);
} else {
diagnostic = jshelpers.createDiagnosticForNode(location, message, ...args)
}
return diagnostic
}
function diag(code:number, category:ts.DiagnosticCategory, key:string, message:string, reportsUnnecessary?:{},elidedInCompatabilityPyramid?:{}):ts.DiagnosticMessage {
return { code: code, category: category, key: key, message: message, reportsUnnecessary: reportsUnnecessary };
}
% def convertPropertyName(origName)
% result = ""
% origName.each_char{|char|
% if char == "*"
% result += "_Asterisk"
% elsif char == "/"
% result += "_Slash"
% elsif char == ":"
% result += "_Colon"
% elsif /\w/.match(char)
% result += char
% else
% result += "_"
% end
% }
% #get rid of all multi-underscores
% result = result.gsub(/_+/, "_");
%
% #remove any leading underscore, unless it is followed by a number.
% result = result.gsub(/^_([^\d])/, "$1");
%
% #get rid of all trailing underscores.
% result = result.gsub(/_$/, "");
% return result
% end
export enum DiagnosticCode {
% Diagnostic::datas.each do |data|
% name = data[0]
% propName = convertPropertyName(name)
% code = data[1]["code"]
<%= propName %> = <%= code %>,
%end
};
export function getDiagnostic(code:DiagnosticCode): ts.DiagnosticMessage|undefined {
switch (code) {
%
% def createKey(name,code)
% key = ""
% name = name.slice(0,100)
% key = name + "_" + code.to_s
% return key
% end
%
% def genReportsUnnecessary(reportsUnnecessary)
% if reportsUnnecessary.nil?
% return ""
% end
% return ", /*reportsUnnecessary*/ " + reportsUnnecessary.to_s
% end
%
% def genElidedInCompatabilityPyramid(elidedInCompatabilityPyramid,reportsUnnecessary)
% reportsUnnecessaryVal = ""
% if reportsUnnecessary.nil? || !reportsUnnecessary
% reportsUnnecessaryVal = ", /*reportsUnnecessary*/ undefined"
% end
% if elidedInCompatabilityPyramid.nil? || !elidedInCompatabilityPyramid
% return ""
% end
% return reportsUnnecessaryVal + ", /*elidedInCompatabilityPyramid*/ " + elidedInCompatabilityPyramid.to_s
% end
%
% def genReportsDeprecated(reportsDeprecated,argElidedInCompatabilityPyramid)
% argElidedInCompatabilityPyramidVal = ""
% if argElidedInCompatabilityPyramid.nil?
% argElidedInCompatabilityPyramidVal = ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined"
% end
% if reportsDeprecated.nil? || !reportsDeprecated
% return ""
% end
% return argElidedInCompatabilityPyramidVal + "/*reportsDeprecated*/ " + reportsDeprecated.to_s
% end
%
% Diagnostic::datas.each do |data|
% name = data[0]
% propName = convertPropertyName(name)
% diagnosticDetials = data[1]
% code = diagnosticDetials["code"]
% category = diagnosticDetials["category"]
% reportsUnnecessary = diagnosticDetials["reportsUnnecessary"]
% elidedInCompatabilityPyramid = diagnosticDetials["elidedInCompatabilityPyramid"]
% reportsDeprecated = diagnosticDetials["reportsDeprecated"]
% key = createKey(propName,code)
% argReportsUnnecessary = genReportsUnnecessary(reportsUnnecessary)
% argElidedInCompatabilityPyramid = genElidedInCompatabilityPyramid(elidedInCompatabilityPyramid,reportsUnnecessary)
% argReportsDeprecated = genReportsDeprecated(reportsDeprecated,argElidedInCompatabilityPyramid)
% message = name.to_json + argReportsUnnecessary + argElidedInCompatabilityPyramid + argReportsDeprecated
case <%= code %> :
return diag(<%= code %>, ts.DiagnosticCategory.<%= category %>, "<%= key %>", <%= message %>);
% end
default :
console.log('The syntax error code is not supported.');
return undefined;
}
};

Some files were not shown because too many files have changed in this diff Show More