mirror of
https://github.com/openharmony/ark_ts2abc.git
synced 2026-07-01 09:24:57 -04:00
add ark ts2abc
Signed-off-by: wanyanglan <wanyanglan1@huawei.com> Change-Id: I3f5f1ddb0ff30ce85c8cccace6d78b7030cff2c6
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
test262/data/
|
||||
test262/eshost/
|
||||
test262/harness/
|
||||
out/
|
||||
@@ -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
|
||||
@@ -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:
|
||||
" == >
|
||||
& == >
|
||||
' == >
|
||||
< == >
|
||||
> == >
|
||||
-->
|
||||
<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>
|
||||
|
||||
@@ -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/)
|
||||
@@ -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
@@ -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
@@ -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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
};
|
||||
Executable
+102
@@ -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
@@ -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;
|
||||
--
|
||||
@@ -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
|
||||
Executable
+189
@@ -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())
|
||||
Executable
+446
@@ -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
Executable
+157
@@ -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'"
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
build
|
||||
src/builtinsMap.ts
|
||||
src/irnodes.ts
|
||||
src/diagnostic.ts
|
||||
@@ -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})",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
```
|
||||
Generated
+2509
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
Executable
+29
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Executable
+72
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
Executable
+87
@@ -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())
|
||||
Executable
+171
@@ -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())
|
||||
Executable
+95
@@ -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)
|
||||
@@ -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}`);
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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)
|
||||
];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Vendored
+74
@@ -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);
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../build",
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "../build/src/tsconfig.tsbuildinfo",
|
||||
"composite": true,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../build-mac",
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "../build-mac/src/tsconfig.tsbuildinfo",
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../build-win",
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "../build-win/src/tsconfig.tsbuildinfo",
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user