feat: add dependency
This commit is contained in:
@@ -9,9 +9,10 @@ edition = "2021"
|
|||||||
crate-type = ['cdylib']
|
crate-type = ['cdylib']
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wit-bindgen-core = { path = '../wit-bindgen/crates/bindgen-core' }
|
boa_engine = { version = "0.16.0", path = "external/boa/boa_engine"}
|
||||||
wit-bindgen-guest-rust = { path = '../wit-bindgen/crates/guest-rust' }
|
|
||||||
boa_engine = "0.16.0"
|
|
||||||
getrandom = { version = "0.2.8", features = ["js"] }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
iana-time-zone = { path = "external/iana-time-zone" }
|
||||||
|
getrandom = { path = "external/getrandom" }
|
||||||
|
|||||||
3
javascript-engine/external/boa/.config/nextest.toml
vendored
Normal file
3
javascript-engine/external/boa/.config/nextest.toml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[profile.ci]
|
||||||
|
# Don't fail fast in CI to run the full test suite.
|
||||||
|
fail-fast = false
|
||||||
11
javascript-engine/external/boa/.editorconfig
vendored
Normal file
11
javascript-engine/external/boa/.editorconfig
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[{Makefile,**.mk}]
|
||||||
|
# Use tabs for indentation (Makefiles require tabs)
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
30
javascript-engine/external/boa/.gitattributes
vendored
Normal file
30
javascript-engine/external/boa/.gitattributes
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Handle line endings automatically for files detected as text
|
||||||
|
# and leave all files detected as binary untouched.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# The above will handle all files NOT found below
|
||||||
|
#
|
||||||
|
# These files are text and should be normalized (Convert crlf => lf)
|
||||||
|
*.css eol=lf
|
||||||
|
*.htm eol=lf
|
||||||
|
*.html eol=lf
|
||||||
|
*.js eol=lf
|
||||||
|
*.json eol=lf
|
||||||
|
*.sh eol=lf
|
||||||
|
*.txt eol=lf
|
||||||
|
*.yml eol=lf
|
||||||
|
*.rs eol=lf
|
||||||
|
*.toml eol=lf
|
||||||
|
*.lock eol=lf
|
||||||
|
*.md eol=lf
|
||||||
|
*.svg eol=lf
|
||||||
|
|
||||||
|
# These files are binary and should be left untouched
|
||||||
|
# (binary is a macro for -text -diff)
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.jar binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.png binary
|
||||||
1
javascript-engine/external/boa/.github/FUNDING.yml
vendored
Normal file
1
javascript-engine/external/boa/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
open_collective: boa
|
||||||
52
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
52
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F41B Bug report"
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ""
|
||||||
|
labels: bug
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Thank you for reporting a bug in Boa! This will make us improve the engine. But first, fill the following template so that we better understand what's happening. Feel free to add or remove sections as you feel appropriate.
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
The variable statement is not working as expected, it always adds 10 when assigning a number to a variable"
|
||||||
|
-->
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the issue, or JavaScript code that causes this failure.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
This JavaScript code reproduces the issue:
|
||||||
|
```javascript
|
||||||
|
var a = 10;
|
||||||
|
a;
|
||||||
|
```
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
Explain what you expected to happen, and what is happening instead.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
Running this code, `a` should be set to `10` and printed, but `a` is instead set to `20`. The expected behaviour can be found in the [ECMAScript specification][spec].
|
||||||
|
|
||||||
|
[spec]: https://tc39.es/ecma262/#sec-variable-statement-runtime-semantics-evaluation
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Build environment (please complete the following information):**
|
||||||
|
|
||||||
|
- OS: [e.g. Fedora Linux]
|
||||||
|
- Version: [e.g. 32]
|
||||||
|
- Target triple: [e.g. x86_64-unknown-linux-gnu]
|
||||||
|
- Rustc version: [e.g. rustc 1.43.0 (4fb7144ed 2020-04-20), running `rustc -V`]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
You can find more information in [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var).
|
||||||
|
-->
|
||||||
5
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Discord channel
|
||||||
|
url: https://discord.gg/tUFFk9Y
|
||||||
|
about: Please ask and answer questions here.
|
||||||
13
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
13
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
name: Custom
|
||||||
|
about: Open an issue in the repo that is neither a bug or a feature, such a new idea
|
||||||
|
title: ""
|
||||||
|
labels: ""
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Thank you for contributing to Boa! Please, let us know how can we help you.
|
||||||
|
-->
|
||||||
|
|
||||||
|
E.g.: I think we should improve the way the JavaScript interpreter works by...
|
||||||
43
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
43
javascript-engine/external/boa/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F680 Feature request"
|
||||||
|
about: Suggest a new ECMAScript feature to be implemented, or a new capability of the engine.
|
||||||
|
title: ""
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Thank you for adding a feature request to Boa! As this is an experimental JavaScript engine, there will probably be many ECMAScript features left to implement. In order to understand the feature request as best as possible, please fill the following template. Feel free to add or remove sections as needed.
|
||||||
|
-->
|
||||||
|
|
||||||
|
**ECMASCript feature**
|
||||||
|
Explain the ECMAScript feature that you'd like to see implemented.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
I would like to see `switch` statement parsing and execution implemented. [ECMAScript specification][spec].
|
||||||
|
|
||||||
|
[spec]: https://tc39.es/ecma262/#sec-switch-statement
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Example code**
|
||||||
|
Give a code example that should work after the implementation of this feature.
|
||||||
|
|
||||||
|
<!-- E.g.:
|
||||||
|
This code should now work and give the expected result:
|
||||||
|
```javascript
|
||||||
|
let a = "hello";
|
||||||
|
let b;
|
||||||
|
switch (a) {
|
||||||
|
case 'hello':
|
||||||
|
b = 'world';
|
||||||
|
break;
|
||||||
|
case 'world':
|
||||||
|
b = 'hello';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
b = 'hello world';
|
||||||
|
}
|
||||||
|
b;
|
||||||
|
```
|
||||||
|
The expected output is `world`.
|
||||||
|
-->
|
||||||
12
javascript-engine/external/boa/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
12
javascript-engine/external/boa/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!---
|
||||||
|
Thank you for contributing to Boa! Please fill out the template below, and remove or add any
|
||||||
|
information as you feel necessary.
|
||||||
|
--->
|
||||||
|
|
||||||
|
This Pull Request fixes/closes #{issue_num}.
|
||||||
|
|
||||||
|
It changes the following:
|
||||||
|
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
10
javascript-engine/external/boa/.github/codecov.yml
vendored
Normal file
10
javascript-engine/external/boa/.github/codecov.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
github_checks:
|
||||||
|
annotations: false
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
threshold: 5% # allow 5% coverage variance
|
||||||
|
|
||||||
|
patch: off
|
||||||
50
javascript-engine/external/boa/.github/dependabot.yml
vendored
Normal file
50
javascript-engine/external/boa/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_cli/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_engine/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_gc/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_interner/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_profiler/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_tester/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_unicode/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: /boa_wasm/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: gitsubmodule
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
16
javascript-engine/external/boa/.github/release.yml
vendored
Normal file
16
javascript-engine/external/boa/.github/release.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# .github/release.yml
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
exclude:
|
||||||
|
authors:
|
||||||
|
- dependabot
|
||||||
|
categories:
|
||||||
|
- title: Feature Enhancements
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- title: Bug Fixes
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- title: Internal Improvements
|
||||||
|
labels:
|
||||||
|
- Internal
|
||||||
54
javascript-engine/external/boa/.github/workflows/master.yml
vendored
Normal file
54
javascript-engine/external/boa/.github/workflows/master.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
name: Main workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
benchmark:
|
||||||
|
if: ${{ github.actor != 'dependabot[bot]' }}
|
||||||
|
name: Upload docs and run benchmarks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- name: Cache cargo
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
target
|
||||||
|
!target/doc_upload
|
||||||
|
~/.cargo/git
|
||||||
|
~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-doc-bench-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
- name: Generate documentation
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: doc
|
||||||
|
args: -v --document-private-items --all-features --workspace --no-deps --exclude boa_examples
|
||||||
|
- run: echo "<meta http-equiv=refresh content=0;url=boa_engine/index.html>" > target/doc/index.html
|
||||||
|
- run: |
|
||||||
|
if [ -d target/doc_upload ]; then rm -rf target/doc_upload; fi
|
||||||
|
mkdir target/doc_upload && mv target/doc target/doc_upload/doc
|
||||||
|
- name: Upload documentation
|
||||||
|
uses: crazy-max/ghaction-github-pages@v3.1.0
|
||||||
|
with:
|
||||||
|
target_branch: gh-pages
|
||||||
|
keep_history: true
|
||||||
|
build_dir: target/doc_upload
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Run benchmark
|
||||||
|
run: cargo bench -p boa_engine -- --output-format bencher | tee output.txt
|
||||||
|
- name: Store benchmark result
|
||||||
|
uses: benchmark-action/github-action-benchmark@v1.15.0
|
||||||
|
with:
|
||||||
|
name: Boa Benchmarks
|
||||||
|
tool: "cargo"
|
||||||
|
output-file-path: output.txt
|
||||||
|
auto-push: true
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
34
javascript-engine/external/boa/.github/workflows/pull_request.yml
vendored
Normal file
34
javascript-engine/external/boa/.github/workflows/pull_request.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Benchmarks
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
runBenchmark:
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'run-benchmark')
|
||||||
|
name: run benchmark
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- name: Cache cargo
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
target
|
||||||
|
~/.cargo/git
|
||||||
|
~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
- uses: boa-dev/criterion-compare-action@v3.2.4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branchName: ${{ github.base_ref }}
|
||||||
|
cwd: ./boa_engine
|
||||||
62
javascript-engine/external/boa/.github/workflows/release.yml
vendored
Normal file
62
javascript-engine/external/boa/.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
name: Publish Release
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
profile: minimal
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Install cargo-workspaces
|
||||||
|
uses: actions-rs/install@v0.1
|
||||||
|
with:
|
||||||
|
crate: cargo-workspaces
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
env:
|
||||||
|
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||||
|
PATCH: ${{ github.run_number }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git config --global user.email "runner@gha.local"
|
||||||
|
git config --global user.name "Github Action"
|
||||||
|
cargo workspaces publish --from-git --yes minor
|
||||||
|
doc-publish:
|
||||||
|
# needs: publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install wasm-pack
|
||||||
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: "16"
|
||||||
|
- run: npm ci
|
||||||
|
- name: Cache npm build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
target
|
||||||
|
boa_wasm/pkg
|
||||||
|
~/.cargo/git
|
||||||
|
~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-npm-build-target-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
- run: npm run build:prod
|
||||||
|
- name: Deploy
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
publish_dir: ./dist
|
||||||
|
destination_dir: playground
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
88
javascript-engine/external/boa/.github/workflows/rust.yml
vendored
Normal file
88
javascript-engine/external/boa/.github/workflows/rust.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
name: Continuous integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- staging # bors
|
||||||
|
- trying # bors
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
coverage:
|
||||||
|
name: Coverage
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
key: tarpaulin
|
||||||
|
- name: Run cargo-tarpaulin
|
||||||
|
uses: actions-rs/tarpaulin@v0.1
|
||||||
|
with:
|
||||||
|
args: --features intl --ignore-tests --engine llvm
|
||||||
|
- name: Upload to codecov.io
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
|
||||||
|
tests:
|
||||||
|
name: Build and Test
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
- name: Build tests
|
||||||
|
run: cargo test --no-run --profile ci
|
||||||
|
# this order is faster according to rust-analyzer
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --all-targets --quiet --profile ci
|
||||||
|
- name: Install latest nextest
|
||||||
|
uses: taiki-e/install-action@nextest
|
||||||
|
- name: Test with nextest
|
||||||
|
run: cargo nextest run --profile ci --cargo-profile ci --features intl
|
||||||
|
|
||||||
|
misc:
|
||||||
|
name: Misc
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
components: rustfmt, clippy
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
key: misc
|
||||||
|
- name: Format (rustfmt)
|
||||||
|
run: cargo fmt --all --check
|
||||||
|
- name: Lint (All features)
|
||||||
|
run: cargo clippy --all-features --all-targets
|
||||||
|
- name: Lint (No features)
|
||||||
|
run: cargo clippy --no-default-features --all-targets
|
||||||
|
- name: Generate documentation
|
||||||
|
run: cargo doc -v --document-private-items --all-features
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --all-targets --quiet --profile ci
|
||||||
|
- run: cd boa_examples
|
||||||
|
- name: Build examples
|
||||||
|
run: cargo build --quiet --profile ci
|
||||||
|
- name: Run example classes
|
||||||
|
run: cargo run --bin classes --profile ci
|
||||||
12
javascript-engine/external/boa/.github/workflows/security_audit.yml
vendored
Normal file
12
javascript-engine/external/boa/.github/workflows/security_audit.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: Security audit
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
jobs:
|
||||||
|
audit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/audit-check@v1.2.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
118
javascript-engine/external/boa/.github/workflows/test262.yml
vendored
Normal file
118
javascript-engine/external/boa/.github/workflows/test262.yml
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
name: EcmaScript official test suite (test262)
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run_test262:
|
||||||
|
name: Run the test262 test suite
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
path: boa
|
||||||
|
- name: Install the Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- name: Cache cargo
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
target
|
||||||
|
~/.cargo/git
|
||||||
|
~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-test262-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
# Run the test suite and upload the results
|
||||||
|
- name: Checkout GitHub pages
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: gh-pages
|
||||||
|
path: gh-pages
|
||||||
|
|
||||||
|
- name: Run the test262 test suite
|
||||||
|
run: |
|
||||||
|
cd boa
|
||||||
|
mkdir ../results
|
||||||
|
cargo run --release --bin boa_tester -- run -v -o ../results/test262
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Run the results comparison
|
||||||
|
- name: Compare results
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
id: compare-non-vm
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd boa
|
||||||
|
comment="$(./target/release/boa_tester compare ../gh-pages/test262/refs/heads/main/latest.json ../results/test262/pull/latest.json -m)"
|
||||||
|
echo "comment<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$comment" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Get the PR number
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
id: pr-number
|
||||||
|
uses: kkak10/pr-number-action@v1.3
|
||||||
|
|
||||||
|
- name: Find Previous Comment
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: peter-evans/find-comment@v2
|
||||||
|
id: previous-comment
|
||||||
|
with:
|
||||||
|
issue-number: ${{ steps.pr-number.outputs.pr }}
|
||||||
|
body-includes: Test262 conformance changes
|
||||||
|
|
||||||
|
- name: Update comment
|
||||||
|
if: github.event_name == 'pull_request' && steps.previous-comment.outputs.comment-id
|
||||||
|
uses: peter-evans/create-or-update-comment@v2
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
comment-id: ${{ steps.previous-comment.outputs.comment-id }}
|
||||||
|
body: |
|
||||||
|
### Test262 conformance changes
|
||||||
|
|
||||||
|
${{ steps.compare-non-vm.outputs.comment }}
|
||||||
|
${{ steps.compare-vm.outputs.comment }}
|
||||||
|
edit-mode: replace
|
||||||
|
|
||||||
|
- name: Write a new comment
|
||||||
|
if: github.event_name == 'pull_request' && !steps.previous-comment.outputs.comment-id
|
||||||
|
uses: peter-evans/create-or-update-comment@v2
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
issue-number: ${{ steps.pr-number.outputs.pr }}
|
||||||
|
body: |
|
||||||
|
### Test262 conformance changes
|
||||||
|
|
||||||
|
${{ steps.compare-non-vm.outputs.comment }}
|
||||||
|
${{ steps.compare-vm.outputs.comment }}
|
||||||
|
|
||||||
|
# Commit changes to GitHub pages.
|
||||||
|
- name: Commit files
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
cp -r ./results/test262/* ./gh-pages/test262/
|
||||||
|
cd gh-pages
|
||||||
|
git config --local user.email "action@github.com"
|
||||||
|
git config --local user.name "GitHub Action"
|
||||||
|
git add test262
|
||||||
|
git commit -m "Add new test262 results" -a
|
||||||
|
cd ..
|
||||||
|
- name: Upload results
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: ad-m/github-push-action@v0.6.0
|
||||||
|
with:
|
||||||
|
directory: gh-pages
|
||||||
|
branch: gh-pages
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
49
javascript-engine/external/boa/.github/workflows/webassembly.yml
vendored
Normal file
49
javascript-engine/external/boa/.github/workflows/webassembly.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
name: Webassembly demo
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_style:
|
||||||
|
name: Check webassembly demo style
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Check code formatting
|
||||||
|
run: npx prettier --check .
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build webassembly demo
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
WASM_PACK_PATH: ~/.cargo/bin/wasm-pack
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1.0.7
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
profile: minimal
|
||||||
|
- name: Install wasm-pack
|
||||||
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
|
- name: Cache npm build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
target
|
||||||
|
~/.cargo/git
|
||||||
|
~/.cargo/registry
|
||||||
|
boa_wasm/pkg
|
||||||
|
key: ${{ runner.os }}-npm-build-target-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: "16"
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
34
javascript-engine/external/boa/.gitignore
vendored
Normal file
34
javascript-engine/external/boa/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
*.*.swp
|
||||||
|
*.*.swo
|
||||||
|
|
||||||
|
# Build
|
||||||
|
target
|
||||||
|
dist
|
||||||
|
**/*.rs.bk
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
yarn-error.log
|
||||||
|
.vscode/settings.json
|
||||||
|
|
||||||
|
# tests/js/test.js is used for testing changes locally
|
||||||
|
tests/js/test.js
|
||||||
|
.boa_history
|
||||||
|
|
||||||
|
# Profiling
|
||||||
|
*.string_data
|
||||||
|
*.string_index
|
||||||
|
*.events
|
||||||
|
chrome_profiler.json
|
||||||
|
*.mm_profdata
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
.yarn
|
||||||
|
.yarnrc.yml
|
||||||
3
javascript-engine/external/boa/.gitmodules
vendored
Normal file
3
javascript-engine/external/boa/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "test262"]
|
||||||
|
path = test262
|
||||||
|
url = https://github.com/tc39/test262.git
|
||||||
10
javascript-engine/external/boa/.prettierignore
vendored
Normal file
10
javascript-engine/external/boa/.prettierignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Ignore artifacts:
|
||||||
|
*.rs
|
||||||
|
target
|
||||||
|
node_modules
|
||||||
|
boa_engine/benches/bench_scripts/mini_js.js
|
||||||
|
boa_engine/benches/bench_scripts/clean_js.js
|
||||||
|
boa_wasm/pkg
|
||||||
|
dist
|
||||||
|
test262
|
||||||
|
tests/js/test.js
|
||||||
35
javascript-engine/external/boa/.vscode/launch.json
vendored
Normal file
35
javascript-engine/external/boa/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch",
|
||||||
|
"windows": {
|
||||||
|
"program": "${workspaceFolder}/target/debug/boa.exe"
|
||||||
|
},
|
||||||
|
"program": "${workspaceFolder}/target/debug/boa",
|
||||||
|
"args": ["${workspaceFolder}/tests/js/test.js"],
|
||||||
|
"sourceLanguages": ["rust"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch (VM)",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"--manifest-path",
|
||||||
|
"./boa_cli/Cargo.toml",
|
||||||
|
"--features",
|
||||||
|
"vm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"args": ["-t", "${workspaceFolder}/tests/js/test.js"],
|
||||||
|
"sourceLanguages": ["rust"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
90
javascript-engine/external/boa/.vscode/tasks.json
vendored
Normal file
90
javascript-engine/external/boa/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Cargo Run",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": ["run", "--bin", "boa", "./tests/js/test.js"],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"env": {
|
||||||
|
"RUST_BACKTRACE": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Cargo Run (Profiler)",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"--features",
|
||||||
|
"boa_engine/profiler",
|
||||||
|
"../tests/js/test.js"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"options": {
|
||||||
|
"env": {
|
||||||
|
"RUST_BACKTRACE": "full"
|
||||||
|
},
|
||||||
|
"cwd": "${workspaceFolder}/boa_cli"
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Run with VM trace",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": ["run", "--bin", "boa", "--", "-t", "./tests/js/test.js"],
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Get AST",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": ["run", "--bin", "boa", "--", "-a=Debug", "./tests/js/test.js"],
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Cargo Test",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": ["test"],
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"clear": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "process",
|
||||||
|
"label": "Cargo Test Build",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": ["test", "--no-run"],
|
||||||
|
"group": "build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1268
javascript-engine/external/boa/CHANGELOG.md
vendored
Normal file
1268
javascript-engine/external/boa/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
javascript-engine/external/boa/CODE_OF_CONDUCT.md
vendored
Normal file
133
javascript-engine/external/boa/CODE_OF_CONDUCT.md
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||||
|
identity and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
- Demonstrating empathy and kindness toward other people
|
||||||
|
- Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
- Giving and gracefully accepting constructive feedback
|
||||||
|
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
- Focusing on what is best not just for us as individuals, but for the overall
|
||||||
|
community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||||
|
any kind
|
||||||
|
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
- Public or private harassment
|
||||||
|
- Publishing others' private information, such as a physical or email address,
|
||||||
|
without their explicit permission
|
||||||
|
- Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
[discord](https://discord.gg/tUFFk9Y) by contacting anyone in the _@boa_dev_
|
||||||
|
group (check the yellow usernames).
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series of
|
||||||
|
actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or permanent
|
||||||
|
ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||||
|
community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.1, available at
|
||||||
|
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by
|
||||||
|
[Mozilla's code of conduct enforcement ladder][mozilla coc].
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
[https://www.contributor-covenant.org/faq][faq]. Translations are available at
|
||||||
|
[https://www.contributor-covenant.org/translations][translations].
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||||
|
[mozilla coc]: https://github.com/mozilla/diversity
|
||||||
|
[faq]: https://www.contributor-covenant.org/faq
|
||||||
|
[translations]: https://www.contributor-covenant.org/translations
|
||||||
115
javascript-engine/external/boa/CONTRIBUTING.md
vendored
Normal file
115
javascript-engine/external/boa/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# Contributing to Boa
|
||||||
|
|
||||||
|
Boa welcomes contribution from everyone. Here are the guidelines if you are
|
||||||
|
thinking of helping out:
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Contributions to Boa or its dependencies should be made in the form of GitHub
|
||||||
|
pull requests. Each pull request will be reviewed by a core contributor
|
||||||
|
(someone with permission to land patches) and either landed in the main tree or
|
||||||
|
given feedback for changes that would be required. All contributions should
|
||||||
|
follow this format.
|
||||||
|
|
||||||
|
Should you wish to work on an issue, please claim it first by commenting on
|
||||||
|
the GitHub issue that you want to work on it. This is to prevent duplicated
|
||||||
|
efforts from contributors on the same issue.
|
||||||
|
|
||||||
|
Head over to [issues][issues] and check for "good first issue" labels to find
|
||||||
|
good tasks to start with. If you come across words or jargon that do not make
|
||||||
|
sense, please ask!
|
||||||
|
|
||||||
|
If you don't already have Rust installed [_rustup_][rustup] is the recommended
|
||||||
|
tool to use. It will install Rust and allow you to switch between _nightly_,
|
||||||
|
_stable_ and _beta_. You can also install additional components. In Linux, you
|
||||||
|
can run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then simply clone this project and `cargo build`.
|
||||||
|
|
||||||
|
### Running the compiler
|
||||||
|
|
||||||
|
You can execute a Boa console by running `cargo run`, and you can compile a list
|
||||||
|
of JavaScript files by running `cargo run -- file1.js file2.js` and so on.
|
||||||
|
|
||||||
|
### Debugging
|
||||||
|
|
||||||
|
Knowing how to debug the interpreter should help you resolve problems quite quickly.
|
||||||
|
See [Debugging](./docs/debugging.md).
|
||||||
|
|
||||||
|
### Web Assembly
|
||||||
|
|
||||||
|
If you want to develop on the web assembly side you can run `yarn serve` and then go
|
||||||
|
to <http://localhost:8080>.
|
||||||
|
|
||||||
|
### boa-unicode
|
||||||
|
|
||||||
|
Boa uses the library `boa-unicode` to query Unicode character properties and classes in lexer and parser. See [boa_unicode/README.md](./boa_unicode/README.md) for development and more information.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
#### VSCode Plugins
|
||||||
|
|
||||||
|
Either the [Rust (RLS)][rls_vscode] or the [Rust Analyzer][rust-analyzer_vscode]
|
||||||
|
extensions are preferred. RLS is easier to set up but some of the development is
|
||||||
|
moving towards Rust Analyzer. Both of these plugins will help you with your Rust
|
||||||
|
Development
|
||||||
|
|
||||||
|
#### Tasks
|
||||||
|
|
||||||
|
There are some pre-defined tasks in [tasks.json](.vscode/tasks.json)
|
||||||
|
|
||||||
|
- Build - shift+cmd/ctrl+b should build and run cargo. You should be able to make changes and run this task.
|
||||||
|
- Test - (there is no shortcut, you'll need to make one) - Runs `Cargo Test`.
|
||||||
|
I personally set a shortcut of shift+cmd+option+T (or shift+ctrl+alt+T)
|
||||||
|
|
||||||
|
If you don't want to install everything on your machine, you can use the Dockerfile.
|
||||||
|
Start VSCode in container mode (you may need the docker container plugin) and use the Dockerfile.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Boa provides its own test suite, and can also run the official ECMAScript test suite. To run the Boa test
|
||||||
|
suite, you can just run the normal `cargo test`, and to run the full ECMAScript test suite, you can run it
|
||||||
|
with this command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run --release --bin boa_tester -- run -v 2> error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this requires the `test262` submodule to be checked out, so you will need to run the following first:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git submodule init && git submodule update
|
||||||
|
```
|
||||||
|
|
||||||
|
This will run the test suite in verbose mode (you can remove the `-v` part to run it in non-verbose mode),
|
||||||
|
and output nice colorings in the terminal. It will also output any panic information into the `error.log` file.
|
||||||
|
|
||||||
|
You can get some more verbose information that tells you the exact name of each test that is being run, useful
|
||||||
|
for debugging purposes by setting up the verbose flag twice, for example `-vv`. If you want to know the output of
|
||||||
|
each test that is executed, you can use the triple verbose (`-vvv`) flag.
|
||||||
|
|
||||||
|
If you want to only run one sub-suite or even one test (to just check if you fixed/broke something specific),
|
||||||
|
you can do it with the `-s` parameter, and then passing the path to the sub-suite or test that you want to run. Note
|
||||||
|
that the `-s` parameter value should be a path relative to the `test262` directory. For example, to run the number
|
||||||
|
type tests, use `-s test/language/types/number`.
|
||||||
|
|
||||||
|
Finally, if you're using the verbose flag and running a sub suite with a small number of tests, then the output will
|
||||||
|
be more readable if you disable parallelism with the `-d` flag. All together it might look something like:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run --release --bin boa_tester -- run -vv -d -s test/language/types/number 2> error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Communication
|
||||||
|
|
||||||
|
We have a Discord server, feel free to ask questions here:
|
||||||
|
<https://discord.gg/tUFFk9Y>
|
||||||
|
|
||||||
|
[issues]: https://github.com/boa-dev/boa/issues
|
||||||
|
[rustup]: https://rustup.rs/
|
||||||
|
[rls_vscode]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust
|
||||||
|
[rust-analyzer_vscode]: https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer
|
||||||
64
javascript-engine/external/boa/Cargo.toml
vendored
Normal file
64
javascript-engine/external/boa/Cargo.toml
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"boa_cli",
|
||||||
|
"boa_engine",
|
||||||
|
"boa_ast",
|
||||||
|
"boa_parser",
|
||||||
|
"boa_gc",
|
||||||
|
"boa_interner",
|
||||||
|
"boa_profiler",
|
||||||
|
"boa_tester",
|
||||||
|
"boa_unicode",
|
||||||
|
"boa_wasm",
|
||||||
|
"boa_examples",
|
||||||
|
"boa_macros",
|
||||||
|
"boa_icu_provider",
|
||||||
|
]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
edition = "2021"
|
||||||
|
version = "0.16.0"
|
||||||
|
rust-version = "1.66"
|
||||||
|
authors = ["boa-dev"]
|
||||||
|
repository = "https://github.com/boa-dev/boa"
|
||||||
|
license = "Unlicense/MIT"
|
||||||
|
description = "Boa is a Javascript lexer, parser and Just-in-Time compiler written in Rust. Currently, it has support for some of the language."
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
boa_engine = { version = "0.16.0", path = "boa_engine" }
|
||||||
|
boa_interner = { version = "0.16.0", path = "boa_interner" }
|
||||||
|
boa_gc = { version = "0.16.0", path = "boa_gc" }
|
||||||
|
boa_profiler = { version = "0.16.0", path = "boa_profiler" }
|
||||||
|
boa_unicode = { version = "0.16.0", path = "boa_unicode" }
|
||||||
|
boa_macros = { version = "0.16.0", path = "boa_macros" }
|
||||||
|
boa_ast = { version = "0.16.0", path = "boa_ast" }
|
||||||
|
boa_parser = { version = "0.16.0", path = "boa_parser" }
|
||||||
|
boa_icu_provider = { version = "0.16.0", path = "boa_icu_provider" }
|
||||||
|
|
||||||
|
[workspace.metadata.workspaces]
|
||||||
|
allow_branch = "main"
|
||||||
|
|
||||||
|
# The ci profile, designed to reduce size of target directory
|
||||||
|
[profile.ci]
|
||||||
|
inherits = "dev"
|
||||||
|
debug = false
|
||||||
|
incremental = false
|
||||||
|
|
||||||
|
# The release profile, used for `cargo build --release`.
|
||||||
|
[profile.release]
|
||||||
|
# Enables "fat" LTO, for faster release builds
|
||||||
|
lto = "fat"
|
||||||
|
# Makes sure that all code is compiled together, for LTO
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
|
# The test profile, used for `cargo test`.
|
||||||
|
[profile.test]
|
||||||
|
# Enables thin local LTO and some optimizations.
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
# The benchmark profile, used for `cargo bench`.
|
||||||
|
[profile.bench]
|
||||||
|
# Enables "fat" LTO, for faster benchmark builds
|
||||||
|
lto = "fat"
|
||||||
|
# Makes sure that all code is compiled together, for LTO
|
||||||
|
codegen-units = 1
|
||||||
21
javascript-engine/external/boa/LICENSE-MIT
vendored
Normal file
21
javascript-engine/external/boa/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Jason Williams
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
24
javascript-engine/external/boa/LICENSE-UNLICENSE
vendored
Normal file
24
javascript-engine/external/boa/LICENSE-UNLICENSE
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org>
|
||||||
115
javascript-engine/external/boa/README.md
vendored
Normal file
115
javascript-engine/external/boa/README.md
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# Boa
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img
|
||||||
|
alt="Boa Logo"
|
||||||
|
src="./assets/logo.svg"
|
||||||
|
width="30%"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
This is an experimental Javascript lexer, parser and interpreter written in Rust.
|
||||||
|
Currently, it has support for some of the language.
|
||||||
|
|
||||||
|
[![Build Status][build_badge]][build_link]
|
||||||
|
[](https://codecov.io/gh/boa-dev/boa)
|
||||||
|
[](https://crates.io/crates/boa_engine)
|
||||||
|
[](https://docs.rs/boa_engine)
|
||||||
|
[](https://discord.gg/tUFFk9Y)
|
||||||
|
|
||||||
|
[build_badge]: https://github.com/boa-dev/boa/actions/workflows/rust.yml/badge.svg?event=push&branch=main
|
||||||
|
[build_link]: https://github.com/boa-dev/boa/actions/workflows/rust.yml?query=event%3Apush+branch%3Amain
|
||||||
|
|
||||||
|
## Live Demo (WASM)
|
||||||
|
|
||||||
|
<https://boa-dev.github.io/boa/playground/>
|
||||||
|
|
||||||
|
You can get more verbose errors when running from the command line.
|
||||||
|
|
||||||
|
## Development documentation
|
||||||
|
|
||||||
|
You can check the internal development docs at <https://boa-dev.github.io/boa/doc>.
|
||||||
|
|
||||||
|
## Conformance
|
||||||
|
|
||||||
|
To know how much of the _ECMAScript_ specification does Boa cover, you can check out results running the _ECMASCript Test262_ test suite [here](https://boa-dev.github.io/boa/test262/).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please, check the [CONTRIBUTING.md](CONTRIBUTING.md) file to know how to
|
||||||
|
contribute in the project. You will need Rust installed and an editor. We have
|
||||||
|
some configurations ready for VSCode.
|
||||||
|
|
||||||
|
### Debugging
|
||||||
|
|
||||||
|
Check [debugging.md](./docs/debugging.md) for more info on debugging.
|
||||||
|
|
||||||
|
### Web Assembly
|
||||||
|
|
||||||
|
This interpreter can be exposed to JavaScript!
|
||||||
|
You can build the example locally with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
In the console you can use `window.evaluate` to pass JavaScript in.
|
||||||
|
To develop on the web assembly side you can run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
then go to `http://localhost:8080`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- Clone this repo.
|
||||||
|
- Run with `cargo run -- test.js` where `test.js` is an existing JS file with any JS valid code.
|
||||||
|
- If any JS doesn't work then it's a bug. Please raise an [issue](https://github.com/boa-dev/boa/issues/)!
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Command-line Options
|
||||||
|
|
||||||
|
```shell
|
||||||
|
USAGE:
|
||||||
|
boa [OPTIONS] [FILE]...
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-a, --dump-ast <FORMAT> Dump the abstract syntax tree (ast) to stdout with the given format [possible values: Debug, Json,
|
||||||
|
JsonPretty]
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<FILE>... The JavaScript file(s) to be evaluated
|
||||||
|
```
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
See [Milestones](https://github.com/boa-dev/boa/milestones).
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
See [Benchmarks](https://boa-dev.github.io/boa/dev/bench/).
|
||||||
|
|
||||||
|
## Profiling
|
||||||
|
|
||||||
|
See [Profiling](./docs/profiling.md).
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
See [CHANGELOG.md](./CHANGELOG.md).
|
||||||
|
|
||||||
|
## Communication
|
||||||
|
|
||||||
|
Feel free to contact us on [Discord](https://discord.gg/tUFFk9Y).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the [Unlicense](./LICENSE-UNLICENSE) or [MIT](./LICENSE-MIT) licenses, at your option.
|
||||||
BIN
javascript-engine/external/boa/assets/01_rust_loves_js.png
vendored
Normal file
BIN
javascript-engine/external/boa/assets/01_rust_loves_js.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 274 KiB |
184
javascript-engine/external/boa/assets/logo.svg
vendored
Normal file
184
javascript-engine/external/boa/assets/logo.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 135 KiB |
25
javascript-engine/external/boa/boa_ast/Cargo.toml
vendored
Normal file
25
javascript-engine/external/boa/boa_ast/Cargo.toml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "boa_ast"
|
||||||
|
description = "Abstract Syntax Tree definition for the Boa JavaScript engine."
|
||||||
|
keywords = ["javascript", "js", "syntax", "ast"]
|
||||||
|
categories = ["parser-implementations", "compilers"]
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
serde = ["boa_interner/serde", "dep:serde"]
|
||||||
|
|
||||||
|
fuzz = ["arbitrary", "boa_interner/fuzz", "num-bigint/arbitrary"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
boa_interner.workspace = true
|
||||||
|
boa_macros.workspace = true
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
|
serde = { version = "1.0.152", features = ["derive"], optional = true }
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
num-bigint = "0.4.3"
|
||||||
|
arbitrary = { version = "1", optional = true, features = ["derive"] }
|
||||||
97
javascript-engine/external/boa/boa_ast/src/declaration/mod.rs
vendored
Normal file
97
javascript-engine/external/boa/boa_ast/src/declaration/mod.rs
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//! The [`Declaration`] Parse Node, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! ECMAScript declarations include:
|
||||||
|
//! - [Lexical][lex] declarations (`let`, `const`).
|
||||||
|
//! - [Function][fun] declarations (`function`, `async function`).
|
||||||
|
//! - [Class][class] declarations.
|
||||||
|
//!
|
||||||
|
//! See [*Difference between statements and declarations*][diff] for an explanation on why `Declaration`s
|
||||||
|
//! and `Statement`s are distinct nodes.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#prod-Declaration
|
||||||
|
//! [lex]: https://tc39.es/ecma262/#prod-LexicalDeclaration
|
||||||
|
//! [fun]: https://tc39.es/ecma262/#prod-HoistableDeclaration
|
||||||
|
//! [class]: https://tc39.es/ecma262/#prod-ClassDeclaration
|
||||||
|
//! [diff]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements#difference_between_statements_and_declarations
|
||||||
|
|
||||||
|
use super::function::{AsyncFunction, AsyncGenerator, Class, Function, Generator};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
mod variable;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
pub use variable::*;
|
||||||
|
|
||||||
|
/// The `Declaration` Parse Node.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Declaration {
|
||||||
|
/// See [`Function`]
|
||||||
|
Function(Function),
|
||||||
|
|
||||||
|
/// See [`Generator`]
|
||||||
|
Generator(Generator),
|
||||||
|
|
||||||
|
/// See [`AsyncFunction`]
|
||||||
|
AsyncFunction(AsyncFunction),
|
||||||
|
|
||||||
|
/// See [`AsyncGenerator`]
|
||||||
|
AsyncGenerator(AsyncGenerator),
|
||||||
|
|
||||||
|
/// See [`Class`]
|
||||||
|
Class(Class),
|
||||||
|
|
||||||
|
/// See [`LexicalDeclaration`]
|
||||||
|
Lexical(LexicalDeclaration),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Declaration {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => f.to_indented_string(interner, indentation),
|
||||||
|
Self::Generator(g) => g.to_indented_string(interner, indentation),
|
||||||
|
Self::AsyncFunction(af) => af.to_indented_string(interner, indentation),
|
||||||
|
Self::AsyncGenerator(ag) => ag.to_indented_string(interner, indentation),
|
||||||
|
Self::Class(c) => c.to_indented_string(interner, indentation),
|
||||||
|
Self::Lexical(l) => {
|
||||||
|
let mut s = l.to_interned_string(interner);
|
||||||
|
s.push(';');
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Declaration {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => visitor.visit_function(f),
|
||||||
|
Self::Generator(g) => visitor.visit_generator(g),
|
||||||
|
Self::AsyncFunction(af) => visitor.visit_async_function(af),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag),
|
||||||
|
Self::Class(c) => visitor.visit_class(c),
|
||||||
|
Self::Lexical(ld) => visitor.visit_lexical_declaration(ld),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => visitor.visit_function_mut(f),
|
||||||
|
Self::Generator(g) => visitor.visit_generator_mut(g),
|
||||||
|
Self::AsyncFunction(af) => visitor.visit_async_function_mut(af),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag),
|
||||||
|
Self::Class(c) => visitor.visit_class_mut(c),
|
||||||
|
Self::Lexical(ld) => visitor.visit_lexical_declaration_mut(ld),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
385
javascript-engine/external/boa/boa_ast/src/declaration/variable.rs
vendored
Normal file
385
javascript-engine/external/boa/boa_ast/src/declaration/variable.rs
vendored
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
//! Variable related declarations.
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes,
|
||||||
|
pattern::Pattern,
|
||||||
|
Statement,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
|
||||||
|
use super::Declaration;
|
||||||
|
|
||||||
|
/// A [`var`][var] statement, also called [`VariableStatement`][varstmt] in the spec.
|
||||||
|
///
|
||||||
|
/// The scope of a variable declared with `var` is its current execution context, which is either
|
||||||
|
/// the enclosing function or, for variables declared outside any function, global. If you
|
||||||
|
/// re-declare a ECMAScript variable, it will not lose its value.
|
||||||
|
///
|
||||||
|
/// Although a bit confusing, `VarDeclaration`s are not considered [`Declaration`]s by the spec.
|
||||||
|
/// This is partly because it has very different semantics from `let` and `const` declarations, but
|
||||||
|
/// also because a `var` statement can be labelled just like any other [`Statement`]:
|
||||||
|
///
|
||||||
|
/// ```javascript
|
||||||
|
/// label: var a = 5;
|
||||||
|
/// a;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// returns `5` as the value of the statement list, while:
|
||||||
|
///
|
||||||
|
/// ```javascript
|
||||||
|
/// label: let a = 5;
|
||||||
|
/// a;
|
||||||
|
/// ```
|
||||||
|
/// throws a `SyntaxError`.
|
||||||
|
///
|
||||||
|
/// `var` declarations, wherever they occur, are processed before any code is executed. This is
|
||||||
|
/// called <code>[hoisting]</code>.
|
||||||
|
///
|
||||||
|
/// [var]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
|
||||||
|
/// [varstmt]: https://tc39.es/ecma262/#prod-VariableStatement
|
||||||
|
/// [hoisting]: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct VarDeclaration(pub VariableList);
|
||||||
|
|
||||||
|
impl From<VarDeclaration> for Statement {
|
||||||
|
fn from(var: VarDeclaration) -> Self {
|
||||||
|
Self::Var(var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for VarDeclaration {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("var {}", self.0.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for VarDeclaration {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_variable_list(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_variable_list_mut(&mut self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A **[lexical declaration]** defines variables that are scoped to the lexical environment of
|
||||||
|
/// the variable declaration.
|
||||||
|
///
|
||||||
|
/// [lexical declaration]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum LexicalDeclaration {
|
||||||
|
/// A <code>[const]</code> variable creates a constant whose scope can be either global or local
|
||||||
|
/// to the block in which it is declared.
|
||||||
|
///
|
||||||
|
/// An initializer for a constant is required. You must specify its value in the same statement
|
||||||
|
/// in which it's declared. (This makes sense, given that it can't be changed later)
|
||||||
|
///
|
||||||
|
/// [const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
||||||
|
Const(VariableList),
|
||||||
|
|
||||||
|
/// A <code>[let]</code> variable is limited to a scope of a block statement, or expression on
|
||||||
|
/// which it is used, unlike the `var` keyword, which defines a variable globally, or locally to
|
||||||
|
/// an entire function regardless of block scope.
|
||||||
|
///
|
||||||
|
/// Just like const, `let` does not create properties of the window object when declared
|
||||||
|
/// globally (in the top-most scope).
|
||||||
|
///
|
||||||
|
/// If a let declaration does not have an initializer, the variable is assigned the value `undefined`.
|
||||||
|
///
|
||||||
|
/// [let]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
||||||
|
Let(VariableList),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LexicalDeclaration {
|
||||||
|
/// Gets the inner variable list of the `LexicalDeclaration`
|
||||||
|
#[must_use]
|
||||||
|
pub const fn variable_list(&self) -> &VariableList {
|
||||||
|
match self {
|
||||||
|
Self::Const(list) | Self::Let(list) => list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LexicalDeclaration> for Declaration {
|
||||||
|
fn from(lex: LexicalDeclaration) -> Self {
|
||||||
|
Self::Lexical(lex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for LexicalDeclaration {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{} {}",
|
||||||
|
match &self {
|
||||||
|
Self::Let(_) => "let",
|
||||||
|
Self::Const(_) => "const",
|
||||||
|
},
|
||||||
|
self.variable_list().to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for LexicalDeclaration {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Const(vars) | Self::Let(vars) => visitor.visit_variable_list(vars),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Const(vars) | Self::Let(vars) => visitor.visit_variable_list_mut(vars),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of variables in a variable declaration.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct VariableList {
|
||||||
|
list: Box<[Variable]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableList {
|
||||||
|
/// Creates a variable list if the provided list of [`Variable`] is not empty.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(list: Box<[Variable]>) -> Option<Self> {
|
||||||
|
if list.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Self { list })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[Variable]> for VariableList {
|
||||||
|
fn as_ref(&self) -> &[Variable] {
|
||||||
|
&self.list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for VariableList {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
join_nodes(interner, self.list.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for VariableList {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for variable in self.list.iter() {
|
||||||
|
try_break!(visitor.visit_variable(variable));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for variable in self.list.iter_mut() {
|
||||||
|
try_break!(visitor.visit_variable_mut(variable));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The error returned by the [`VariableList::try_from`] function.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TryFromVariableListError(());
|
||||||
|
|
||||||
|
impl std::fmt::Display for TryFromVariableListError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
"provided list of variables cannot be empty".fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Box<[Variable]>> for VariableList {
|
||||||
|
type Error = TryFromVariableListError;
|
||||||
|
|
||||||
|
fn try_from(value: Box<[Variable]>) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value).ok_or(TryFromVariableListError(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<Variable>> for VariableList {
|
||||||
|
type Error = TryFromVariableListError;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<Variable>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.into_boxed_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Variable represents a variable declaration of some kind.
|
||||||
|
///
|
||||||
|
/// For `let` and `const` declarations this type represents a [`LexicalBinding`][spec1]
|
||||||
|
///
|
||||||
|
/// For `var` declarations this type represents a [`VariableDeclaration`][spec2]
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3 Declarations and the Variable Statement][spec3]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-LexicalBinding
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-VariableDeclaration
|
||||||
|
/// [spec3]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Variable {
|
||||||
|
binding: Binding,
|
||||||
|
init: Option<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Variable {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = self.binding.to_interned_string(interner);
|
||||||
|
|
||||||
|
if let Some(ref init) = self.init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Variable {
|
||||||
|
/// Creates a new variable declaration from a `BindingIdentifier`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_identifier(ident: Identifier, init: Option<Expression>) -> Self {
|
||||||
|
Self {
|
||||||
|
binding: Binding::Identifier(ident),
|
||||||
|
init,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new variable declaration from a `Pattern`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_pattern(pattern: Pattern, init: Option<Expression>) -> Self {
|
||||||
|
Self {
|
||||||
|
binding: Binding::Pattern(pattern),
|
||||||
|
init,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Gets the variable declaration binding.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn binding(&self) -> &Binding {
|
||||||
|
&self.binding
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initialization expression for the variable declaration, if any.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn init(&self) -> Option<&Expression> {
|
||||||
|
self.init.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Variable {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_binding(&self.binding));
|
||||||
|
if let Some(init) = &self.init {
|
||||||
|
try_break!(visitor.visit_expression(init));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_binding_mut(&mut self.binding));
|
||||||
|
if let Some(init) = &mut self.init {
|
||||||
|
try_break!(visitor.visit_expression_mut(init));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binding represents either an individual binding or a binding pattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3 Declarations and the Variable Statement][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Binding {
|
||||||
|
/// A single identifier binding.
|
||||||
|
Identifier(Identifier),
|
||||||
|
/// A pattern binding.
|
||||||
|
Pattern(Pattern),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Identifier> for Binding {
|
||||||
|
fn from(id: Identifier) -> Self {
|
||||||
|
Self::Identifier(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Pattern> for Binding {
|
||||||
|
fn from(pat: Pattern) -> Self {
|
||||||
|
Self::Pattern(pat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Binding {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => id.to_interned_string(interner),
|
||||||
|
Self::Pattern(ref pattern) => pattern.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Binding {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier(id),
|
||||||
|
Self::Pattern(pattern) => visitor.visit_pattern(pattern),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier_mut(id),
|
||||||
|
Self::Pattern(pattern) => visitor.visit_pattern_mut(pattern),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
348
javascript-engine/external/boa/boa_ast/src/expression/access.rs
vendored
Normal file
348
javascript-engine/external/boa/boa_ast/src/expression/access.rs
vendored
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
//! Property access expressions, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! [Property access expressions][access] provide two ways to access properties of an object: *dot notation*
|
||||||
|
//! and *bracket notation*.
|
||||||
|
//! - *Dot notation* is mostly used when the name of the property is static, and a valid Javascript
|
||||||
|
//! identifier e.g. `obj.prop`, `arr.$val`.
|
||||||
|
//! - *Bracket notation* is used when the name of the property is either variable, not a valid
|
||||||
|
//! identifier or a symbol e.g. `arr[var]`, `arr[5]`, `arr[Symbol.iterator]`.
|
||||||
|
//!
|
||||||
|
//! A property access expression can be represented by a [`SimplePropertyAccess`] (`x.y`), a
|
||||||
|
//! [`PrivatePropertyAccess`] (`x.#y`) or a [`SuperPropertyAccess`] (`super["y"]`), each of them with
|
||||||
|
//! slightly different semantics overall.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-property-accessors
|
||||||
|
//! [access]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors
|
||||||
|
|
||||||
|
use crate::expression::Expression;
|
||||||
|
use crate::function::PrivateName;
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// A property access field.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PropertyAccessField {
|
||||||
|
/// A constant property field, such as `x.prop`.
|
||||||
|
Const(Sym),
|
||||||
|
/// An expression property field, such as `x["val"]`.
|
||||||
|
Expr(Box<Expression>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sym> for PropertyAccessField {
|
||||||
|
#[inline]
|
||||||
|
fn from(id: Sym) -> Self {
|
||||||
|
Self::Const(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Expression> for PropertyAccessField {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: Expression) -> Self {
|
||||||
|
Self::Expr(Box::new(expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PropertyAccessField {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Const(sym) => visitor.visit_sym(sym),
|
||||||
|
Self::Expr(expr) => visitor.visit_expression(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Const(sym) => visitor.visit_sym_mut(sym),
|
||||||
|
Self::Expr(expr) => visitor.visit_expression_mut(&mut *expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A property access expression.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PropertyAccess {
|
||||||
|
/// A simple property access (`x.prop`).
|
||||||
|
Simple(SimplePropertyAccess),
|
||||||
|
/// A property access of a private property (`x.#priv`).
|
||||||
|
Private(PrivatePropertyAccess),
|
||||||
|
/// A property access of a `super` reference. (`super["prop"]`).
|
||||||
|
Super(SuperPropertyAccess),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for PropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Simple(s) => s.to_interned_string(interner),
|
||||||
|
Self::Private(p) => p.to_interned_string(interner),
|
||||||
|
Self::Super(s) => s.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PropertyAccess> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(access: PropertyAccess) -> Self {
|
||||||
|
Self::PropertyAccess(access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PropertyAccess {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Simple(spa) => visitor.visit_simple_property_access(spa),
|
||||||
|
Self::Private(ppa) => visitor.visit_private_property_access(ppa),
|
||||||
|
Self::Super(supa) => visitor.visit_super_property_access(supa),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Simple(spa) => visitor.visit_simple_property_access_mut(spa),
|
||||||
|
Self::Private(ppa) => visitor.visit_private_property_access_mut(ppa),
|
||||||
|
Self::Super(supa) => visitor.visit_super_property_access_mut(supa),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple property access, where the target object is an [`Expression`].
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SimplePropertyAccess {
|
||||||
|
target: Box<Expression>,
|
||||||
|
field: PropertyAccessField,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimplePropertyAccess {
|
||||||
|
/// Gets the target object of the property access.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the accessed field of the target object.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn field(&self) -> &PropertyAccessField {
|
||||||
|
&self.field
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `PropertyAccess` AST Expression.
|
||||||
|
pub fn new<F>(target: Expression, field: F) -> Self
|
||||||
|
where
|
||||||
|
F: Into<PropertyAccessField>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
target: target.into(),
|
||||||
|
field: field.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for SimplePropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let target = self.target.to_interned_string(interner);
|
||||||
|
match self.field {
|
||||||
|
PropertyAccessField::Const(sym) => format!("{target}.{}", interner.resolve_expect(sym)),
|
||||||
|
PropertyAccessField::Expr(ref expr) => {
|
||||||
|
format!("{target}[{}]", expr.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SimplePropertyAccess> for PropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn from(access: SimplePropertyAccess) -> Self {
|
||||||
|
Self::Simple(access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for SimplePropertyAccess {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.target));
|
||||||
|
visitor.visit_property_access_field(&self.field)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.target));
|
||||||
|
visitor.visit_property_access_field_mut(&mut self.field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An access expression to a class object's [private fields][mdn].
|
||||||
|
///
|
||||||
|
/// Private property accesses differ slightly from plain property accesses, since the accessed
|
||||||
|
/// property must be prefixed by `#`, and the bracket notation is not allowed. For example,
|
||||||
|
/// `this.#a` is a valid private property access.
|
||||||
|
///
|
||||||
|
/// This expression corresponds to the [`MemberExpression.PrivateIdentifier`][spec] production.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MemberExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct PrivatePropertyAccess {
|
||||||
|
target: Box<Expression>,
|
||||||
|
field: PrivateName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrivatePropertyAccess {
|
||||||
|
/// Creates a `GetPrivateField` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(value: Expression, field: PrivateName) -> Self {
|
||||||
|
Self {
|
||||||
|
target: value.into(),
|
||||||
|
field,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the original object from where to get the field from.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the field to retrieve.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn field(&self) -> PrivateName {
|
||||||
|
self.field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for PrivatePropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{}.#{}",
|
||||||
|
self.target.to_interned_string(interner),
|
||||||
|
interner.resolve_expect(self.field.description())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PrivatePropertyAccess> for PropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn from(access: PrivatePropertyAccess) -> Self {
|
||||||
|
Self::Private(access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PrivatePropertyAccess {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.target));
|
||||||
|
visitor.visit_private_name(&self.field)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.target));
|
||||||
|
visitor.visit_private_name_mut(&mut self.field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A property access of an object's parent, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// A `SuperPropertyAccess` is much like a regular [`PropertyAccess`], but where its `target` object
|
||||||
|
/// is not a regular object, but a reference to the parent object of the current object ([`super`][mdn]).
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-SuperProperty
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SuperPropertyAccess {
|
||||||
|
field: PropertyAccessField,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SuperPropertyAccess {
|
||||||
|
/// Creates a new property access field node.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(field: PropertyAccessField) -> Self {
|
||||||
|
Self { field }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the field to retrieve.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn field(&self) -> &PropertyAccessField {
|
||||||
|
&self.field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for SuperPropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match &self.field {
|
||||||
|
PropertyAccessField::Const(field) => {
|
||||||
|
format!("super.{}", interner.resolve_expect(*field))
|
||||||
|
}
|
||||||
|
PropertyAccessField::Expr(field) => {
|
||||||
|
format!("super[{}]", field.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SuperPropertyAccess> for PropertyAccess {
|
||||||
|
#[inline]
|
||||||
|
fn from(access: SuperPropertyAccess) -> Self {
|
||||||
|
Self::Super(access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for SuperPropertyAccess {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_property_access_field(&self.field)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_property_access_field_mut(&mut self.field)
|
||||||
|
}
|
||||||
|
}
|
||||||
71
javascript-engine/external/boa/boa_ast/src/expression/await.rs
vendored
Normal file
71
javascript-engine/external/boa/boa_ast/src/expression/await.rs
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//! Await expression Expression.
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
|
||||||
|
/// An await expression is used within an async function to pause execution and wait for a
|
||||||
|
/// promise to resolve.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Await {
|
||||||
|
target: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Await {
|
||||||
|
/// Return the target expression that should be awaited.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Await
|
||||||
|
where
|
||||||
|
T: Into<Box<Expression>>,
|
||||||
|
{
|
||||||
|
fn from(e: T) -> Self {
|
||||||
|
Self { target: e.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Await {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("await {}", self.target.to_indented_string(interner, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Await> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(awaitexpr: Await) -> Self {
|
||||||
|
Self::Await(awaitexpr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Await {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression(&self.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression_mut(&mut self.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
164
javascript-engine/external/boa/boa_ast/src/expression/call.rs
vendored
Normal file
164
javascript-engine/external/boa/boa_ast/src/expression/call.rs
vendored
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
use crate::join_nodes;
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// Calling the function actually performs the specified actions with the indicated parameters.
|
||||||
|
///
|
||||||
|
/// Defining a function does not execute it. Defining it simply names the function and
|
||||||
|
/// specifies what to do when the function is called. Functions must be in scope when they are
|
||||||
|
/// called, but the function declaration can be hoisted. The scope of a function is the
|
||||||
|
/// function in which it is declared (or the entire program, if it is declared at the top
|
||||||
|
/// level).
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-CallExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Call {
|
||||||
|
function: Box<Expression>,
|
||||||
|
args: Box<[Expression]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Call {
|
||||||
|
/// Creates a new `Call` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(function: Expression, args: Box<[Expression]>) -> Self {
|
||||||
|
Self {
|
||||||
|
function: function.into(),
|
||||||
|
args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the target function of this call expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn function(&self) -> &Expression {
|
||||||
|
&self.function
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the arguments passed to the function.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn args(&self) -> &[Expression] {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Call {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{}({})",
|
||||||
|
self.function.to_interned_string(interner),
|
||||||
|
join_nodes(interner, &self.args)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Call> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(call: Call) -> Self {
|
||||||
|
Self::Call(call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Call {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.function));
|
||||||
|
for expr in self.args.iter() {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.function));
|
||||||
|
for expr in self.args.iter_mut() {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `super` keyword is used to access and call functions on an object's parent.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-SuperCall
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SuperCall {
|
||||||
|
args: Box<[Expression]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SuperCall {
|
||||||
|
/// Creates a new `SuperCall` AST node.
|
||||||
|
pub fn new<A>(args: A) -> Self
|
||||||
|
where
|
||||||
|
A: Into<Box<[Expression]>>,
|
||||||
|
{
|
||||||
|
Self { args: args.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the arguments of the super call.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn arguments(&self) -> &[Expression] {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for SuperCall {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("super({})", join_nodes(interner, &self.args))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SuperCall> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(call: SuperCall) -> Self {
|
||||||
|
Self::SuperCall(call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for SuperCall {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for expr in self.args.iter() {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for expr in self.args.iter_mut() {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
122
javascript-engine/external/boa/boa_ast/src/expression/identifier.rs
vendored
Normal file
122
javascript-engine/external/boa/boa_ast/src/expression/identifier.rs
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
//! Local identifier Expression.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
ToStringEscaped,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// List of reserved keywords exclusive to strict mode.
|
||||||
|
pub const RESERVED_IDENTIFIERS_STRICT: [Sym; 9] = [
|
||||||
|
Sym::IMPLEMENTS,
|
||||||
|
Sym::INTERFACE,
|
||||||
|
Sym::LET,
|
||||||
|
Sym::PACKAGE,
|
||||||
|
Sym::PRIVATE,
|
||||||
|
Sym::PROTECTED,
|
||||||
|
Sym::PUBLIC,
|
||||||
|
Sym::STATIC,
|
||||||
|
Sym::YIELD,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// An `identifier` is a sequence of characters in the code that identifies a variable,
|
||||||
|
/// function, or property.
|
||||||
|
///
|
||||||
|
/// In ECMAScript, identifiers are case-sensitive and can contain Unicode letters, $, _, and
|
||||||
|
/// digits (0-9), but may not start with a digit.
|
||||||
|
///
|
||||||
|
/// An identifier differs from a string in that a string is data, while an identifier is part
|
||||||
|
/// of the code. In JavaScript, there is no way to convert identifiers to strings, but
|
||||||
|
/// sometimes it is possible to parse strings into identifiers.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-Identifier
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Identifier
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "serde",
|
||||||
|
derive(serde::Serialize, serde::Deserialize),
|
||||||
|
serde(transparent)
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Identifier {
|
||||||
|
ident: Sym,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Sym> for Identifier {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Sym) -> bool {
|
||||||
|
self.ident == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Identifier> for Sym {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Identifier) -> bool {
|
||||||
|
*self == other.ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Identifier {
|
||||||
|
/// Creates a new identifier AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(ident: Sym) -> Self {
|
||||||
|
Self { ident }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the identifier's string symbol in the interner.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn sym(self) -> Sym {
|
||||||
|
self.ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Identifier {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
interner.resolve_expect(self.ident).join(
|
||||||
|
String::from,
|
||||||
|
ToStringEscaped::to_string_escaped,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sym> for Identifier {
|
||||||
|
#[inline]
|
||||||
|
fn from(sym: Sym) -> Self {
|
||||||
|
Self { ident: sym }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Identifier> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(local: Identifier) -> Self {
|
||||||
|
Self::Identifier(local)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Identifier {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_sym(&self.ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_sym_mut(&mut self.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
223
javascript-engine/external/boa/boa_ast/src/expression/literal/array.rs
vendored
Normal file
223
javascript-engine/external/boa/boa_ast/src/expression/literal/array.rs
vendored
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
//! Array declaration Expression.
|
||||||
|
|
||||||
|
use crate::expression::operator::assign::AssignTarget;
|
||||||
|
use crate::expression::Expression;
|
||||||
|
use crate::pattern::{ArrayPattern, ArrayPatternElement, Pattern};
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// An array is an ordered collection of data (either primitive or object depending upon the
|
||||||
|
/// language).
|
||||||
|
///
|
||||||
|
/// Arrays are used to store multiple values in a single variable.
|
||||||
|
/// This is compared to a variable that can store only one value.
|
||||||
|
///
|
||||||
|
/// Each item in an array has a number attached to it, called a numeric index, that allows you
|
||||||
|
/// to access it. In JavaScript, arrays start at index zero and can be manipulated with various
|
||||||
|
/// methods.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ArrayLiteral
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ArrayLiteral {
|
||||||
|
arr: Box<[Option<Expression>]>,
|
||||||
|
has_trailing_comma_spread: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayLiteral {
|
||||||
|
/// Creates a new array literal.
|
||||||
|
pub fn new<A>(array: A, has_trailing_comma_spread: bool) -> Self
|
||||||
|
where
|
||||||
|
A: Into<Box<[Option<Expression>]>>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
arr: array.into(),
|
||||||
|
has_trailing_comma_spread,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if a spread operator in the array literal has a trailing comma.
|
||||||
|
/// This is a syntax error in some cases.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_trailing_comma_spread(&self) -> bool {
|
||||||
|
self.has_trailing_comma_spread
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this `ArrayLiteral` into an [`ArrayPattern`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_pattern(&self, strict: bool) -> Option<ArrayPattern> {
|
||||||
|
if self.has_trailing_comma_spread() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
for (i, expr) in self.arr.iter().enumerate() {
|
||||||
|
let expr = if let Some(expr) = expr {
|
||||||
|
expr
|
||||||
|
} else {
|
||||||
|
bindings.push(ArrayPatternElement::Elision);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
match expr {
|
||||||
|
Expression::Identifier(ident) => {
|
||||||
|
if strict && *ident == Sym::ARGUMENTS {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings.push(ArrayPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Expression::Spread(spread) => {
|
||||||
|
match spread.target() {
|
||||||
|
Expression::Identifier(ident) => {
|
||||||
|
bindings.push(ArrayPatternElement::SingleNameRest { ident: *ident });
|
||||||
|
}
|
||||||
|
Expression::PropertyAccess(access) => {
|
||||||
|
bindings.push(ArrayPatternElement::PropertyAccessRest {
|
||||||
|
access: access.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Expression::ArrayLiteral(array) => {
|
||||||
|
let pattern = array.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ArrayPatternElement::PatternRest { pattern });
|
||||||
|
}
|
||||||
|
Expression::ObjectLiteral(object) => {
|
||||||
|
let pattern = object.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ArrayPatternElement::PatternRest { pattern });
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
if i + 1 != self.arr.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Assign(assign) => match assign.lhs() {
|
||||||
|
AssignTarget::Identifier(ident) => {
|
||||||
|
bindings.push(ArrayPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
AssignTarget::Access(access) => {
|
||||||
|
bindings.push(ArrayPatternElement::PropertyAccess {
|
||||||
|
access: access.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
AssignTarget::Pattern(pattern) => match pattern {
|
||||||
|
Pattern::Object(pattern) => {
|
||||||
|
bindings.push(ArrayPatternElement::Pattern {
|
||||||
|
pattern: Pattern::Object(pattern.clone()),
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Array(pattern) => {
|
||||||
|
bindings.push(ArrayPatternElement::Pattern {
|
||||||
|
pattern: Pattern::Array(pattern.clone()),
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Expression::ArrayLiteral(array) => {
|
||||||
|
let pattern = array.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ArrayPatternElement::Pattern {
|
||||||
|
pattern,
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Expression::ObjectLiteral(object) => {
|
||||||
|
let pattern = object.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ArrayPatternElement::Pattern {
|
||||||
|
pattern,
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Expression::PropertyAccess(access) => {
|
||||||
|
bindings.push(ArrayPatternElement::PropertyAccess {
|
||||||
|
access: access.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ArrayPattern::new(bindings.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[Option<Expression>]> for ArrayLiteral {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &[Option<Expression>] {
|
||||||
|
&self.arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for ArrayLiteral
|
||||||
|
where
|
||||||
|
T: Into<Box<[Option<Expression>]>>,
|
||||||
|
{
|
||||||
|
fn from(decl: T) -> Self {
|
||||||
|
Self {
|
||||||
|
arr: decl.into(),
|
||||||
|
has_trailing_comma_spread: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ArrayLiteral {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = String::from("[");
|
||||||
|
let mut first = true;
|
||||||
|
for e in &*self.arr {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
buf.push_str(", ");
|
||||||
|
}
|
||||||
|
if let Some(e) = e {
|
||||||
|
buf.push_str(&e.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.push(']');
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArrayLiteral> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(arr: ArrayLiteral) -> Self {
|
||||||
|
Self::ArrayLiteral(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ArrayLiteral {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for expr in self.arr.iter().flatten() {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for expr in self.arr.iter_mut().flatten() {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
202
javascript-engine/external/boa/boa_ast/src/expression/literal/mod.rs
vendored
Normal file
202
javascript-engine/external/boa/boa_ast/src/expression/literal/mod.rs
vendored
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
//! This module contains all literal expressions, which represents the primitive values in ECMAScript.
|
||||||
|
//!
|
||||||
|
//! More information:
|
||||||
|
//! - [ECMAScript reference][spec]
|
||||||
|
//! - [MDN documentation][mdn]
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#sec-primary-expression-literals
|
||||||
|
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
|
||||||
|
|
||||||
|
mod array;
|
||||||
|
mod object;
|
||||||
|
mod template;
|
||||||
|
|
||||||
|
pub use array::ArrayLiteral;
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
pub use object::ObjectLiteral;
|
||||||
|
pub use template::{TemplateElement, TemplateLiteral};
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// Literals represent values in ECMAScript.
|
||||||
|
///
|
||||||
|
/// These are fixed values **not variables** that you literally provide in your script.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-primary-expression-literals
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Literal {
|
||||||
|
/// A string literal is zero or more characters enclosed in double (`"`) or single (`'`) quotation marks.
|
||||||
|
///
|
||||||
|
/// A string must be delimited by quotation marks of the same type (that is, either both single quotation marks, or both double quotation marks).
|
||||||
|
/// You can call any of the String object's methods on a string literal value.
|
||||||
|
/// ECMAScript automatically converts the string literal to a temporary String object,
|
||||||
|
/// calls the method, then discards the temporary String object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-string-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#String_literals
|
||||||
|
String(Sym),
|
||||||
|
|
||||||
|
/// A floating-point number literal.
|
||||||
|
///
|
||||||
|
/// The exponent part is an "`e`" or "`E`" followed by an integer, which can be signed (preceded by "`+`" or "`-`").
|
||||||
|
/// A floating-point literal must have at least one digit, and either a decimal point or "`e`" (or "`E`").
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-number-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Floating-point_literals
|
||||||
|
Num(f64),
|
||||||
|
|
||||||
|
/// Integer types can be expressed in decimal (base 10), hexadecimal (base 16), octal (base 8) and binary (base 2).
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-number-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Numeric_literals
|
||||||
|
Int(i32),
|
||||||
|
|
||||||
|
/// BigInt provides a way to represent whole numbers larger than the largest number ECMAScript
|
||||||
|
/// can reliably represent with the `Number` primitive.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-bigint-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Numeric_literals
|
||||||
|
BigInt(Box<BigInt>),
|
||||||
|
|
||||||
|
/// The Boolean type has two literal values: `true` and `false`.
|
||||||
|
///
|
||||||
|
/// The Boolean object is a wrapper around the primitive Boolean data type.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-boolean-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Boolean_literals
|
||||||
|
Bool(bool),
|
||||||
|
|
||||||
|
/// In JavaScript, `null` is marked as one of the primitive values, cause it's behaviour is seemingly primitive.
|
||||||
|
///
|
||||||
|
/// In computer science, a null value represents a reference that points,
|
||||||
|
/// generally intentionally, to a nonexistent or invalid object or address.
|
||||||
|
/// The meaning of a null reference varies among language implementations.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-null-value
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/null
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sym> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(string: Sym) -> Self {
|
||||||
|
Self::String(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(num: f64) -> Self {
|
||||||
|
Self::Num(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(i: i32) -> Self {
|
||||||
|
Self::Int(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BigInt> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(i: BigInt) -> Self {
|
||||||
|
Self::BigInt(Box::new(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<BigInt>> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(i: Box<BigInt>) -> Self {
|
||||||
|
Self::BigInt(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn from(b: bool) -> Self {
|
||||||
|
Self::Bool(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Literal> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(lit: Literal) -> Self {
|
||||||
|
Self::Literal(lit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Literal {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match *self {
|
||||||
|
Self::String(st) => {
|
||||||
|
format!("\"{}\"", interner.resolve_expect(st))
|
||||||
|
}
|
||||||
|
Self::Num(num) => num.to_string(),
|
||||||
|
Self::Int(num) => num.to_string(),
|
||||||
|
Self::BigInt(ref num) => num.to_string(),
|
||||||
|
Self::Bool(v) => v.to_string(),
|
||||||
|
Self::Null => "null".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Literal {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Self::String(sym) = self {
|
||||||
|
visitor.visit_sym(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Self::String(sym) = self {
|
||||||
|
visitor.visit_sym_mut(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
326
javascript-engine/external/boa/boa_ast/src/expression/literal/object.rs
vendored
Normal file
326
javascript-engine/external/boa/boa_ast/src/expression/literal/object.rs
vendored
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
//! Object Expression.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
block_to_string,
|
||||||
|
expression::{operator::assign::AssignTarget, Expression, RESERVED_IDENTIFIERS_STRICT},
|
||||||
|
function::Function,
|
||||||
|
join_nodes,
|
||||||
|
pattern::{ObjectPattern, ObjectPatternElement},
|
||||||
|
property::{MethodDefinition, PropertyDefinition, PropertyName},
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// Objects in ECMAScript may be defined as an unordered collection of related data, of
|
||||||
|
/// primitive or reference types, in the form of “key: value” pairs.
|
||||||
|
///
|
||||||
|
/// Objects can be initialized using `new Object()`, `Object.create()`, or using the literal
|
||||||
|
/// notation.
|
||||||
|
///
|
||||||
|
/// An object initializer is an expression that describes the initialization of an
|
||||||
|
/// [`Object`][object]. Objects consist of properties, which are used to describe an object.
|
||||||
|
/// Values of object properties can either contain [`primitive`][primitive] data types or other
|
||||||
|
/// objects.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ObjectLiteral
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
||||||
|
/// [object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||||
|
/// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ObjectLiteral {
|
||||||
|
properties: Box<[PropertyDefinition]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectLiteral {
|
||||||
|
/// Gets the object literal properties
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn properties(&self) -> &[PropertyDefinition] {
|
||||||
|
&self.properties
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the object literal into an [`ObjectPattern`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_pattern(&self, strict: bool) -> Option<ObjectPattern> {
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
let mut excluded_keys = Vec::new();
|
||||||
|
for (i, property) in self.properties.iter().enumerate() {
|
||||||
|
match property {
|
||||||
|
PropertyDefinition::IdentifierReference(ident) if strict && *ident == Sym::EVAL => {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
PropertyDefinition::IdentifierReference(ident) => {
|
||||||
|
if strict && RESERVED_IDENTIFIERS_STRICT.contains(&ident.sym()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
excluded_keys.push(*ident);
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Literal(ident.sym()),
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PropertyDefinition::Property(name, expr) => match (name, expr) {
|
||||||
|
(PropertyName::Literal(name), Expression::Identifier(ident))
|
||||||
|
if *name == *ident =>
|
||||||
|
{
|
||||||
|
if strict && *name == Sym::EVAL {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if strict && RESERVED_IDENTIFIERS_STRICT.contains(name) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
excluded_keys.push(*ident);
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Literal(*name),
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(PropertyName::Literal(name), Expression::Identifier(ident)) => {
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Literal(*name),
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(PropertyName::Literal(name), Expression::ObjectLiteral(object)) => {
|
||||||
|
let pattern = object.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ObjectPatternElement::Pattern {
|
||||||
|
name: PropertyName::Literal(*name),
|
||||||
|
pattern,
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(PropertyName::Literal(name), Expression::ArrayLiteral(array)) => {
|
||||||
|
let pattern = array.to_pattern(strict)?.into();
|
||||||
|
bindings.push(ObjectPatternElement::Pattern {
|
||||||
|
name: PropertyName::Literal(*name),
|
||||||
|
pattern,
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(_, Expression::Assign(assign)) => match assign.lhs() {
|
||||||
|
AssignTarget::Identifier(ident) => {
|
||||||
|
if let Some(name) = name.literal() {
|
||||||
|
if name == *ident {
|
||||||
|
if strict && name == Sym::EVAL {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if strict && RESERVED_IDENTIFIERS_STRICT.contains(&name) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
excluded_keys.push(*ident);
|
||||||
|
}
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Literal(name),
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignTarget::Pattern(pattern) => {
|
||||||
|
bindings.push(ObjectPatternElement::Pattern {
|
||||||
|
name: name.clone(),
|
||||||
|
pattern: pattern.clone(),
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
AssignTarget::Access(access) => {
|
||||||
|
bindings.push(ObjectPatternElement::AssignmentPropertyAccess {
|
||||||
|
name: name.clone(),
|
||||||
|
access: access.clone(),
|
||||||
|
default_init: Some(assign.rhs().clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(_, Expression::PropertyAccess(access)) => {
|
||||||
|
bindings.push(ObjectPatternElement::AssignmentPropertyAccess {
|
||||||
|
name: name.clone(),
|
||||||
|
access: access.clone(),
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(PropertyName::Computed(name), Expression::Identifier(ident)) => {
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Computed(name.clone()),
|
||||||
|
default_init: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
PropertyDefinition::SpreadObject(spread) => {
|
||||||
|
match spread {
|
||||||
|
Expression::Identifier(ident) => {
|
||||||
|
bindings.push(ObjectPatternElement::RestProperty {
|
||||||
|
ident: *ident,
|
||||||
|
excluded_keys: excluded_keys.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Expression::PropertyAccess(access) => {
|
||||||
|
bindings.push(ObjectPatternElement::AssignmentRestPropertyAccess {
|
||||||
|
access: access.clone(),
|
||||||
|
excluded_keys: excluded_keys.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
if i + 1 != self.properties.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropertyDefinition::MethodDefinition(_, _) => return None,
|
||||||
|
PropertyDefinition::CoverInitializedName(ident, expr) => {
|
||||||
|
if strict && [Sym::EVAL, Sym::ARGUMENTS].contains(&ident.sym()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings.push(ObjectPatternElement::SingleName {
|
||||||
|
ident: *ident,
|
||||||
|
name: PropertyName::Literal(ident.sym()),
|
||||||
|
default_init: Some(expr.clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ObjectPattern::new(bindings.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for ObjectLiteral {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
|
||||||
|
let mut buf = "{\n".to_owned();
|
||||||
|
let indentation = " ".repeat(indent_n + 1);
|
||||||
|
for property in self.properties().iter() {
|
||||||
|
buf.push_str(&match property {
|
||||||
|
PropertyDefinition::IdentifierReference(ident) => {
|
||||||
|
format!("{indentation}{},\n", interner.resolve_expect(ident.sym()))
|
||||||
|
}
|
||||||
|
PropertyDefinition::Property(key, value) => {
|
||||||
|
let value = if let Expression::Function(f) = value {
|
||||||
|
Function::new(None, f.parameters().clone(), f.body().clone()).into()
|
||||||
|
} else {
|
||||||
|
value.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{indentation}{}: {},\n",
|
||||||
|
key.to_interned_string(interner),
|
||||||
|
value.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PropertyDefinition::SpreadObject(key) => {
|
||||||
|
format!("{indentation}...{},\n", key.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
PropertyDefinition::MethodDefinition(key, method) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}{}{}({}) {},\n",
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(_) => "get ",
|
||||||
|
MethodDefinition::Set(_) => "set ",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
key.to_interned_string(interner),
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expression)
|
||||||
|
| MethodDefinition::Set(expression)
|
||||||
|
| MethodDefinition::Ordinary(expression) => {
|
||||||
|
join_nodes(interner, expression.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expression) => {
|
||||||
|
join_nodes(interner, expression.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expression) => {
|
||||||
|
join_nodes(interner, expression.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expression) => {
|
||||||
|
join_nodes(interner, expression.parameters().as_ref())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expression)
|
||||||
|
| MethodDefinition::Set(expression)
|
||||||
|
| MethodDefinition::Ordinary(expression) => {
|
||||||
|
block_to_string(expression.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expression) => {
|
||||||
|
block_to_string(expression.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expression) => {
|
||||||
|
block_to_string(expression.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expression) => {
|
||||||
|
block_to_string(expression.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PropertyDefinition::CoverInitializedName(ident, expr) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}{} = {},\n",
|
||||||
|
interner.resolve_expect(ident.sym()),
|
||||||
|
expr.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
buf.push_str(&format!("{}}}", " ".repeat(indent_n)));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for ObjectLiteral
|
||||||
|
where
|
||||||
|
T: Into<Box<[PropertyDefinition]>>,
|
||||||
|
{
|
||||||
|
fn from(props: T) -> Self {
|
||||||
|
Self {
|
||||||
|
properties: props.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ObjectLiteral> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(obj: ObjectLiteral) -> Self {
|
||||||
|
Self::ObjectLiteral(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ObjectLiteral {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for pd in self.properties.iter() {
|
||||||
|
try_break!(visitor.visit_property_definition(pd));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for pd in self.properties.iter_mut() {
|
||||||
|
try_break!(visitor.visit_property_definition_mut(pd));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
133
javascript-engine/external/boa/boa_ast/src/expression/literal/template.rs
vendored
Normal file
133
javascript-engine/external/boa/boa_ast/src/expression/literal/template.rs
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
//! Template literal Expression.
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
ToStringEscaped,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Template literals are string literals allowing embedded expressions.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-template-literals
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct TemplateLiteral {
|
||||||
|
elements: Box<[TemplateElement]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TemplateLiteral> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(tem: TemplateLiteral) -> Self {
|
||||||
|
Self::TemplateLiteral(tem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An element found within a [`TemplateLiteral`].
|
||||||
|
///
|
||||||
|
/// The [spec] doesn't define an element akin to `TemplateElement`. However, the AST defines this
|
||||||
|
/// node as the equivalent of the components found in a template literal.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-template-literals
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum TemplateElement {
|
||||||
|
/// A simple string.
|
||||||
|
String(Sym),
|
||||||
|
/// An expression that is evaluated and replaced by its string representation.
|
||||||
|
Expr(Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TemplateLiteral {
|
||||||
|
/// Creates a new `TemplateLiteral` from a list of [`TemplateElement`]s.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(elements: Box<[TemplateElement]>) -> Self {
|
||||||
|
Self { elements }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the element list of this `TemplateLiteral`.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn elements(&self) -> &[TemplateElement] {
|
||||||
|
&self.elements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for TemplateLiteral {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = "`".to_owned();
|
||||||
|
|
||||||
|
for elt in self.elements.iter() {
|
||||||
|
match elt {
|
||||||
|
TemplateElement::String(s) => buf.push_str(&interner.resolve_expect(*s).join(
|
||||||
|
Cow::Borrowed,
|
||||||
|
|utf16| Cow::Owned(utf16.to_string_escaped()),
|
||||||
|
true,
|
||||||
|
)),
|
||||||
|
TemplateElement::Expr(n) => {
|
||||||
|
buf.push_str(&format!("${{{}}}", n.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.push('`');
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for TemplateLiteral {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for element in self.elements.iter() {
|
||||||
|
try_break!(visitor.visit_template_element(element));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for element in self.elements.iter_mut() {
|
||||||
|
try_break!(visitor.visit_template_element_mut(element));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for TemplateElement {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::String(sym) => visitor.visit_sym(sym),
|
||||||
|
Self::Expr(expr) => visitor.visit_expression(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::String(sym) => visitor.visit_sym_mut(sym),
|
||||||
|
Self::Expr(expr) => visitor.visit_expression_mut(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
332
javascript-engine/external/boa/boa_ast/src/expression/mod.rs
vendored
Normal file
332
javascript-engine/external/boa/boa_ast/src/expression/mod.rs
vendored
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
//! The [`Expression`] Parse Node, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! ECMAScript expressions include:
|
||||||
|
//! - [Primary][primary] expressions (`this`, function expressions, literals).
|
||||||
|
//! - [Left hand side][lhs] expressions (accessors, `new` operator, `super`).
|
||||||
|
//! - [operator] expressions.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#prod-Expression
|
||||||
|
//! [primary]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#primary_expressions
|
||||||
|
//! [lhs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#left-hand-side_expressions
|
||||||
|
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
access::PropertyAccess,
|
||||||
|
literal::{ArrayLiteral, Literal, ObjectLiteral, TemplateLiteral},
|
||||||
|
operator::{Assign, Binary, Conditional, Unary},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
function::{ArrowFunction, AsyncFunction, AsyncGenerator, Class, Function, Generator},
|
||||||
|
function::{AsyncArrowFunction, FormalParameterList},
|
||||||
|
Statement,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod r#await;
|
||||||
|
mod call;
|
||||||
|
mod identifier;
|
||||||
|
mod new;
|
||||||
|
mod optional;
|
||||||
|
mod spread;
|
||||||
|
mod tagged_template;
|
||||||
|
mod r#yield;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
pub use call::{Call, SuperCall};
|
||||||
|
pub use identifier::{Identifier, RESERVED_IDENTIFIERS_STRICT};
|
||||||
|
pub use new::New;
|
||||||
|
pub use optional::{Optional, OptionalOperation, OptionalOperationKind};
|
||||||
|
pub use r#await::Await;
|
||||||
|
pub use r#yield::Yield;
|
||||||
|
pub use spread::Spread;
|
||||||
|
pub use tagged_template::TaggedTemplate;
|
||||||
|
|
||||||
|
pub mod access;
|
||||||
|
pub mod literal;
|
||||||
|
pub mod operator;
|
||||||
|
|
||||||
|
/// The `Expression` Parse Node.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Expression {
|
||||||
|
/// The ECMAScript `this` keyword refers to the object it belongs to.
|
||||||
|
///
|
||||||
|
/// A property of an execution context (global, function or eval) that,
|
||||||
|
/// in non–strict mode, is always a reference to an object and in strict
|
||||||
|
/// mode can be any value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-this-keyword
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
|
||||||
|
This,
|
||||||
|
|
||||||
|
/// See [`Identifier`].
|
||||||
|
Identifier(Identifier),
|
||||||
|
|
||||||
|
/// See [`Literal`].
|
||||||
|
Literal(Literal),
|
||||||
|
|
||||||
|
/// See [`ArrayLiteral`].
|
||||||
|
ArrayLiteral(ArrayLiteral),
|
||||||
|
|
||||||
|
/// See [`ObjectLiteral`].
|
||||||
|
ObjectLiteral(ObjectLiteral),
|
||||||
|
|
||||||
|
/// See [`Spread`],
|
||||||
|
Spread(Spread),
|
||||||
|
|
||||||
|
/// See [`Function`].
|
||||||
|
Function(Function),
|
||||||
|
|
||||||
|
/// See [`ArrowFunction`].
|
||||||
|
ArrowFunction(ArrowFunction),
|
||||||
|
|
||||||
|
/// See [`AsyncArrowFunction`].
|
||||||
|
AsyncArrowFunction(AsyncArrowFunction),
|
||||||
|
|
||||||
|
/// See [`Generator`].
|
||||||
|
Generator(Generator),
|
||||||
|
|
||||||
|
/// See [`AsyncFunction`].
|
||||||
|
AsyncFunction(AsyncFunction),
|
||||||
|
|
||||||
|
/// See [`AsyncGenerator`].
|
||||||
|
AsyncGenerator(AsyncGenerator),
|
||||||
|
|
||||||
|
/// See [`Class`].
|
||||||
|
Class(Box<Class>),
|
||||||
|
|
||||||
|
// TODO: Extract regexp literal Expression
|
||||||
|
// RegExpLiteral,
|
||||||
|
/// See [`TemplateLiteral`].
|
||||||
|
TemplateLiteral(TemplateLiteral),
|
||||||
|
|
||||||
|
/// See [`PropertyAccess`].
|
||||||
|
PropertyAccess(PropertyAccess),
|
||||||
|
|
||||||
|
/// See [`New`].
|
||||||
|
New(New),
|
||||||
|
|
||||||
|
/// See [`Call`].
|
||||||
|
Call(Call),
|
||||||
|
|
||||||
|
/// See [`SuperCall`].
|
||||||
|
SuperCall(SuperCall),
|
||||||
|
|
||||||
|
/// See [`Optional`].
|
||||||
|
Optional(Optional),
|
||||||
|
|
||||||
|
// TODO: Import calls
|
||||||
|
/// See [`TaggedTemplate`].
|
||||||
|
TaggedTemplate(TaggedTemplate),
|
||||||
|
|
||||||
|
/// The `new.target` pseudo-property expression.
|
||||||
|
NewTarget,
|
||||||
|
|
||||||
|
// TODO: import.meta
|
||||||
|
/// See [`Assign`].
|
||||||
|
Assign(Assign),
|
||||||
|
|
||||||
|
/// See [`Unary`].
|
||||||
|
Unary(Unary),
|
||||||
|
|
||||||
|
/// See [`Binary`].
|
||||||
|
Binary(Binary),
|
||||||
|
|
||||||
|
/// See [`Conditional`].
|
||||||
|
Conditional(Conditional),
|
||||||
|
|
||||||
|
/// See [`Await`].
|
||||||
|
Await(Await),
|
||||||
|
|
||||||
|
/// See [`Yield`].
|
||||||
|
Yield(Yield),
|
||||||
|
|
||||||
|
/// A FormalParameterList.
|
||||||
|
///
|
||||||
|
/// This is only used in the parser itself.
|
||||||
|
/// It is not a valid expression node.
|
||||||
|
#[doc(hidden)]
|
||||||
|
FormalParameterList(FormalParameterList),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
/// Implements the display formatting with indentation.
|
||||||
|
///
|
||||||
|
/// This will not prefix the value with any indentation. If you want to prefix this with proper
|
||||||
|
/// indents, use [`to_indented_string()`](Self::to_indented_string).
|
||||||
|
pub(crate) fn to_no_indent_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
match self {
|
||||||
|
Self::This => "this".to_owned(),
|
||||||
|
Self::Identifier(id) => id.to_interned_string(interner),
|
||||||
|
Self::Literal(lit) => lit.to_interned_string(interner),
|
||||||
|
Self::ArrayLiteral(arr) => arr.to_interned_string(interner),
|
||||||
|
Self::ObjectLiteral(o) => o.to_indented_string(interner, indentation),
|
||||||
|
Self::Spread(sp) => sp.to_interned_string(interner),
|
||||||
|
Self::Function(f) => f.to_indented_string(interner, indentation),
|
||||||
|
Self::AsyncArrowFunction(f) => f.to_indented_string(interner, indentation),
|
||||||
|
Self::ArrowFunction(arrf) => arrf.to_indented_string(interner, indentation),
|
||||||
|
Self::Class(cl) => cl.to_indented_string(interner, indentation),
|
||||||
|
Self::Generator(gen) => gen.to_indented_string(interner, indentation),
|
||||||
|
Self::AsyncFunction(asf) => asf.to_indented_string(interner, indentation),
|
||||||
|
Self::AsyncGenerator(asgen) => asgen.to_indented_string(interner, indentation),
|
||||||
|
Self::TemplateLiteral(tem) => tem.to_interned_string(interner),
|
||||||
|
Self::PropertyAccess(prop) => prop.to_interned_string(interner),
|
||||||
|
Self::New(new) => new.to_interned_string(interner),
|
||||||
|
Self::Call(call) => call.to_interned_string(interner),
|
||||||
|
Self::SuperCall(supc) => supc.to_interned_string(interner),
|
||||||
|
Self::Optional(opt) => opt.to_interned_string(interner),
|
||||||
|
Self::NewTarget => "new.target".to_owned(),
|
||||||
|
Self::TaggedTemplate(tag) => tag.to_interned_string(interner),
|
||||||
|
Self::Assign(assign) => assign.to_interned_string(interner),
|
||||||
|
Self::Unary(unary) => unary.to_interned_string(interner),
|
||||||
|
Self::Binary(bin) => bin.to_interned_string(interner),
|
||||||
|
Self::Conditional(cond) => cond.to_interned_string(interner),
|
||||||
|
Self::Await(aw) => aw.to_interned_string(interner),
|
||||||
|
Self::Yield(yi) => yi.to_interned_string(interner),
|
||||||
|
Self::FormalParameterList(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns if the expression is a function definition according to the spec.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-isfunctiondefinition
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_function_definition(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::ArrowFunction(_)
|
||||||
|
| Self::AsyncArrowFunction(_)
|
||||||
|
| Self::Function(_)
|
||||||
|
| Self::Generator(_)
|
||||||
|
| Self::AsyncGenerator(_)
|
||||||
|
| Self::AsyncFunction(_)
|
||||||
|
| Self::Class(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns if the expression is a function definition without a name.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_anonymous_function_definition(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::ArrowFunction(f) => f.name().is_none(),
|
||||||
|
Self::AsyncArrowFunction(f) => f.name().is_none(),
|
||||||
|
Self::Function(f) => f.name().is_none(),
|
||||||
|
Self::Generator(f) => f.name().is_none(),
|
||||||
|
Self::AsyncGenerator(f) => f.name().is_none(),
|
||||||
|
Self::AsyncFunction(f) => f.name().is_none(),
|
||||||
|
Self::Class(f) => f.name().is_none(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Expression> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: Expression) -> Self {
|
||||||
|
Self::Expression(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
self.to_no_indent_string(interner, indentation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Expression {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier(id),
|
||||||
|
Self::Literal(lit) => visitor.visit_literal(lit),
|
||||||
|
Self::ArrayLiteral(arlit) => visitor.visit_array_literal(arlit),
|
||||||
|
Self::ObjectLiteral(olit) => visitor.visit_object_literal(olit),
|
||||||
|
Self::Spread(sp) => visitor.visit_spread(sp),
|
||||||
|
Self::Function(f) => visitor.visit_function(f),
|
||||||
|
Self::ArrowFunction(af) => visitor.visit_arrow_function(af),
|
||||||
|
Self::AsyncArrowFunction(af) => visitor.visit_async_arrow_function(af),
|
||||||
|
Self::Generator(g) => visitor.visit_generator(g),
|
||||||
|
Self::AsyncFunction(af) => visitor.visit_async_function(af),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag),
|
||||||
|
Self::Class(c) => visitor.visit_class(c),
|
||||||
|
Self::TemplateLiteral(tlit) => visitor.visit_template_literal(tlit),
|
||||||
|
Self::PropertyAccess(pa) => visitor.visit_property_access(pa),
|
||||||
|
Self::New(n) => visitor.visit_new(n),
|
||||||
|
Self::Call(c) => visitor.visit_call(c),
|
||||||
|
Self::SuperCall(sc) => visitor.visit_super_call(sc),
|
||||||
|
Self::Optional(opt) => visitor.visit_optional(opt),
|
||||||
|
Self::TaggedTemplate(tt) => visitor.visit_tagged_template(tt),
|
||||||
|
Self::Assign(a) => visitor.visit_assign(a),
|
||||||
|
Self::Unary(u) => visitor.visit_unary(u),
|
||||||
|
Self::Binary(b) => visitor.visit_binary(b),
|
||||||
|
Self::Conditional(c) => visitor.visit_conditional(c),
|
||||||
|
Self::Await(a) => visitor.visit_await(a),
|
||||||
|
Self::Yield(y) => visitor.visit_yield(y),
|
||||||
|
Self::FormalParameterList(fpl) => visitor.visit_formal_parameter_list(fpl),
|
||||||
|
Self::This | Self::NewTarget => {
|
||||||
|
// do nothing; can be handled as special case by visitor
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier_mut(id),
|
||||||
|
Self::Literal(lit) => visitor.visit_literal_mut(lit),
|
||||||
|
Self::ArrayLiteral(arlit) => visitor.visit_array_literal_mut(arlit),
|
||||||
|
Self::ObjectLiteral(olit) => visitor.visit_object_literal_mut(olit),
|
||||||
|
Self::Spread(sp) => visitor.visit_spread_mut(sp),
|
||||||
|
Self::Function(f) => visitor.visit_function_mut(f),
|
||||||
|
Self::ArrowFunction(af) => visitor.visit_arrow_function_mut(af),
|
||||||
|
Self::AsyncArrowFunction(af) => visitor.visit_async_arrow_function_mut(af),
|
||||||
|
Self::Generator(g) => visitor.visit_generator_mut(g),
|
||||||
|
Self::AsyncFunction(af) => visitor.visit_async_function_mut(af),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag),
|
||||||
|
Self::Class(c) => visitor.visit_class_mut(c),
|
||||||
|
Self::TemplateLiteral(tlit) => visitor.visit_template_literal_mut(tlit),
|
||||||
|
Self::PropertyAccess(pa) => visitor.visit_property_access_mut(pa),
|
||||||
|
Self::New(n) => visitor.visit_new_mut(n),
|
||||||
|
Self::Call(c) => visitor.visit_call_mut(c),
|
||||||
|
Self::SuperCall(sc) => visitor.visit_super_call_mut(sc),
|
||||||
|
Self::Optional(opt) => visitor.visit_optional_mut(opt),
|
||||||
|
Self::TaggedTemplate(tt) => visitor.visit_tagged_template_mut(tt),
|
||||||
|
Self::Assign(a) => visitor.visit_assign_mut(a),
|
||||||
|
Self::Unary(u) => visitor.visit_unary_mut(u),
|
||||||
|
Self::Binary(b) => visitor.visit_binary_mut(b),
|
||||||
|
Self::Conditional(c) => visitor.visit_conditional_mut(c),
|
||||||
|
Self::Await(a) => visitor.visit_await_mut(a),
|
||||||
|
Self::Yield(y) => visitor.visit_yield_mut(y),
|
||||||
|
Self::FormalParameterList(fpl) => visitor.visit_formal_parameter_list_mut(fpl),
|
||||||
|
Self::This | Self::NewTarget => {
|
||||||
|
// do nothing; can be handled as special case by visitor
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
javascript-engine/external/boa/boa_ast/src/expression/new.rs
vendored
Normal file
87
javascript-engine/external/boa/boa_ast/src/expression/new.rs
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use crate::expression::Call;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// The `new` operator lets developers create an instance of a user-defined object type or of
|
||||||
|
/// one of the built-in object types that has a constructor function.
|
||||||
|
///
|
||||||
|
/// The new keyword does the following things:
|
||||||
|
/// - Creates a blank, plain JavaScript object;
|
||||||
|
/// - Links (sets the constructor of) this object to another object;
|
||||||
|
/// - Passes the newly created object from Step 1 as the this context;
|
||||||
|
/// - Returns this if the function doesn't return its own object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-NewExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct New {
|
||||||
|
call: Call,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl New {
|
||||||
|
/// Gets the constructor of the new expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn constructor(&self) -> &Expression {
|
||||||
|
self.call.function()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the arguments passed to the constructor.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn arguments(&self) -> &[Expression] {
|
||||||
|
self.call.args()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the inner call expression.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn call(&self) -> &Call {
|
||||||
|
&self.call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Call> for New {
|
||||||
|
#[inline]
|
||||||
|
fn from(call: Call) -> Self {
|
||||||
|
Self { call }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for New {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("new {}", self.call.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<New> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(new: New) -> Self {
|
||||||
|
Self::New(new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for New {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_call(&self.call)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_call_mut(&mut self.call)
|
||||||
|
}
|
||||||
|
}
|
||||||
191
javascript-engine/external/boa/boa_ast/src/expression/operator/assign/mod.rs
vendored
Normal file
191
javascript-engine/external/boa/boa_ast/src/expression/operator/assign/mod.rs
vendored
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
//! Assignment expression nodes, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! An [assignment operator][mdn] assigns a value to its left operand based on the value of its right
|
||||||
|
//! operand. Almost any [`LeftHandSideExpression`][lhs] Parse Node can be the target of a simple
|
||||||
|
//! assignment expression (`=`). However, the compound assignment operations such as `%=` or `??=`
|
||||||
|
//! only allow ["simple"][simple] left hand side expressions as an assignment target.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators
|
||||||
|
//! [lhs]: https://tc39.es/ecma262/#prod-LeftHandSideExpression
|
||||||
|
//! [simple]: https://tc39.es/ecma262/#sec-static-semantics-assignmenttargettype
|
||||||
|
|
||||||
|
mod op;
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
pub use op::*;
|
||||||
|
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expression::{access::PropertyAccess, identifier::Identifier, Expression},
|
||||||
|
pattern::Pattern,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An assignment operator expression.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Assign {
|
||||||
|
op: AssignOp,
|
||||||
|
lhs: Box<AssignTarget>,
|
||||||
|
rhs: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assign {
|
||||||
|
/// Creates an `Assign` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(op: AssignOp, lhs: AssignTarget, rhs: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
op,
|
||||||
|
lhs: Box::new(lhs),
|
||||||
|
rhs: Box::new(rhs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the operator of the assignment operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn op(&self) -> AssignOp {
|
||||||
|
self.op
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the left hand side of the assignment operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn lhs(&self) -> &AssignTarget {
|
||||||
|
&self.lhs
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the right hand side of the assignment operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn rhs(&self) -> &Expression {
|
||||||
|
&self.rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Assign {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{} {} {}",
|
||||||
|
self.lhs.to_interned_string(interner),
|
||||||
|
self.op,
|
||||||
|
self.rhs.to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Assign> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: Assign) -> Self {
|
||||||
|
Self::Assign(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Assign {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_assign_target(&self.lhs));
|
||||||
|
visitor.visit_expression(&self.rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_assign_target_mut(&mut self.lhs));
|
||||||
|
visitor.visit_expression_mut(&mut self.rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The valid left-hand-side expressions of an assignment operator. Also called
|
||||||
|
/// [`LeftHandSideExpression`][spec] in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: hhttps://tc39.es/ecma262/#prod-LeftHandSideExpression
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum AssignTarget {
|
||||||
|
/// A simple identifier, such as `a`.
|
||||||
|
Identifier(Identifier),
|
||||||
|
/// A property access, such as `a.prop`.
|
||||||
|
Access(PropertyAccess),
|
||||||
|
/// A pattern assignment, such as `{a, b, ...c}`.
|
||||||
|
Pattern(Pattern),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssignTarget {
|
||||||
|
/// Converts the left-hand-side Expression of an assignment expression into an [`AssignTarget`].
|
||||||
|
/// Returns `None` if the given Expression is an invalid left-hand-side for a assignment expression.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_expression(
|
||||||
|
expression: &Expression,
|
||||||
|
strict: bool,
|
||||||
|
destructure: bool,
|
||||||
|
) -> Option<Self> {
|
||||||
|
match expression {
|
||||||
|
Expression::Identifier(id) => Some(Self::Identifier(*id)),
|
||||||
|
Expression::PropertyAccess(access) => Some(Self::Access(access.clone())),
|
||||||
|
Expression::ObjectLiteral(object) if destructure => {
|
||||||
|
let pattern = object.to_pattern(strict)?;
|
||||||
|
Some(Self::Pattern(pattern.into()))
|
||||||
|
}
|
||||||
|
Expression::ArrayLiteral(array) if destructure => {
|
||||||
|
let pattern = array.to_pattern(strict)?;
|
||||||
|
Some(Self::Pattern(pattern.into()))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for AssignTarget {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => id.to_interned_string(interner),
|
||||||
|
Self::Access(access) => access.to_interned_string(interner),
|
||||||
|
Self::Pattern(pattern) => pattern.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Identifier> for AssignTarget {
|
||||||
|
#[inline]
|
||||||
|
fn from(target: Identifier) -> Self {
|
||||||
|
Self::Identifier(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for AssignTarget {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier(id),
|
||||||
|
Self::Access(pa) => visitor.visit_property_access(pa),
|
||||||
|
Self::Pattern(pat) => visitor.visit_pattern(pat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier_mut(id),
|
||||||
|
Self::Access(pa) => visitor.visit_property_access_mut(pa),
|
||||||
|
Self::Pattern(pat) => visitor.visit_pattern_mut(pat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
244
javascript-engine/external/boa/boa_ast/src/expression/operator/assign/op.rs
vendored
Normal file
244
javascript-engine/external/boa/boa_ast/src/expression/operator/assign/op.rs
vendored
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/// An assignment operator assigns a value to its left operand based on the value of its right operand.
|
||||||
|
///
|
||||||
|
/// The simple assignment operator is equal (`=`), which assigns the value of its right operand to its
|
||||||
|
/// left operand. That is, `x = y` assigns the value of `y to x`.
|
||||||
|
///
|
||||||
|
/// There are also compound assignment operators that are shorthand for the operations
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum AssignOp {
|
||||||
|
/// The assignment operator assigns the value of the right operand to the left operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x = y`
|
||||||
|
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment
|
||||||
|
Assign,
|
||||||
|
/// The addition assignment operator adds the value of the right operand to a variable and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x += y`
|
||||||
|
///
|
||||||
|
/// The types of the two operands determine the behavior of the addition assignment operator. Addition or concatenation is possible.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Addition_assignment
|
||||||
|
Add,
|
||||||
|
|
||||||
|
/// The subtraction assignment operator subtracts the value of the right operand from a variable and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x -= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Subtraction_assignment
|
||||||
|
Sub,
|
||||||
|
|
||||||
|
/// The multiplication assignment operator multiplies a variable by the value of the right operand and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x *= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Multiplication_assignment
|
||||||
|
Mul,
|
||||||
|
|
||||||
|
/// The division assignment operator divides a variable by the value of the right operand and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x /= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Division_assignment
|
||||||
|
Div,
|
||||||
|
|
||||||
|
/// The remainder assignment operator divides a variable by the value of the right operand and assigns the remainder to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x %= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Remainder_assignment
|
||||||
|
Mod,
|
||||||
|
|
||||||
|
/// The exponentiation assignment operator raises the value of a variable to the power of the right operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ** y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Exponentiation_assignment
|
||||||
|
Exp,
|
||||||
|
|
||||||
|
/// The bitwise AND assignment operator uses the binary representation of both operands, does a bitwise AND operation on
|
||||||
|
/// them and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x &= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_AND_assignment
|
||||||
|
And,
|
||||||
|
|
||||||
|
/// The bitwise OR assignment operator uses the binary representation of both operands, does a bitwise OR operation on
|
||||||
|
/// them and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x |= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_OR_assignment
|
||||||
|
Or,
|
||||||
|
|
||||||
|
/// The bitwise XOR assignment operator uses the binary representation of both operands, does a bitwise XOR operation on
|
||||||
|
/// them and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ^= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_XOR_assignment
|
||||||
|
Xor,
|
||||||
|
|
||||||
|
/// The left shift assignment operator moves the specified amount of bits to the left and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x <<= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Left_shift_assignment
|
||||||
|
Shl,
|
||||||
|
|
||||||
|
/// The right shift assignment operator moves the specified amount of bits to the right and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x >>= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Right_shift_assignment
|
||||||
|
Shr,
|
||||||
|
|
||||||
|
/// The unsigned right shift assignment operator moves the specified amount of bits to the right and assigns the result to the variable.
|
||||||
|
///
|
||||||
|
/// Syntax: `x >>>= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift_assignment
|
||||||
|
Ushr,
|
||||||
|
|
||||||
|
/// The logical and assignment operator only assigns if the target variable is truthy.
|
||||||
|
///
|
||||||
|
/// Syntax: `x &&= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND_assignment
|
||||||
|
BoolAnd,
|
||||||
|
|
||||||
|
/// The logical or assignment operator only assigns if the target variable is falsy.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ||= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment
|
||||||
|
BoolOr,
|
||||||
|
|
||||||
|
/// The logical nullish assignment operator only assigns if the target variable is nullish (null or undefined).
|
||||||
|
///
|
||||||
|
/// Syntax: `x ??= y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment
|
||||||
|
Coalesce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssignOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Assign => "=",
|
||||||
|
Self::Add => "+=",
|
||||||
|
Self::Sub => "-=",
|
||||||
|
Self::Mul => "*=",
|
||||||
|
Self::Exp => "**=",
|
||||||
|
Self::Div => "/=",
|
||||||
|
Self::Mod => "%=",
|
||||||
|
Self::And => "&=",
|
||||||
|
Self::Or => "|=",
|
||||||
|
Self::Xor => "^=",
|
||||||
|
Self::Shl => "<<=",
|
||||||
|
Self::Shr => ">>=",
|
||||||
|
Self::Ushr => ">>>=",
|
||||||
|
Self::BoolAnd => "&&=",
|
||||||
|
Self::BoolOr => "||=",
|
||||||
|
Self::Coalesce => "??=",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for AssignOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
111
javascript-engine/external/boa/boa_ast/src/expression/operator/binary/mod.rs
vendored
Normal file
111
javascript-engine/external/boa/boa_ast/src/expression/operator/binary/mod.rs
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
//! Binary expression nodes.
|
||||||
|
//!
|
||||||
|
//! A Binary expression comprises any operation between two expressions (excluding assignments),
|
||||||
|
//! such as:
|
||||||
|
//! - [Logic operations][logic] (`||`, `&&`).
|
||||||
|
//! - [Relational math][relat] (`==`, `<`).
|
||||||
|
//! - [Bit manipulation][bit] (`^`, `|`).
|
||||||
|
//! - [Arithmetic][arith] (`+`, `%`).
|
||||||
|
//! - The [comma operator][comma] (`,`)
|
||||||
|
//!
|
||||||
|
//! [logic]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#binary_logical_operators
|
||||||
|
//! [relat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#relational_operators
|
||||||
|
//! [bit]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#binary_bitwise_operators
|
||||||
|
//! [arith]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#arithmetic_operators
|
||||||
|
//! [comma]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
|
||||||
|
|
||||||
|
mod op;
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
pub use op::*;
|
||||||
|
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Binary operations require two operands, one before the operator and one after the operator.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Binary {
|
||||||
|
op: BinaryOp,
|
||||||
|
lhs: Box<Expression>,
|
||||||
|
rhs: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Binary {
|
||||||
|
/// Creates a `BinOp` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(op: BinaryOp, lhs: Expression, rhs: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
op,
|
||||||
|
lhs: Box::new(lhs),
|
||||||
|
rhs: Box::new(rhs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the binary operation of the Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn op(&self) -> BinaryOp {
|
||||||
|
self.op
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the left hand side of the binary operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn lhs(&self) -> &Expression {
|
||||||
|
&self.lhs
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the right hand side of the binary operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn rhs(&self) -> &Expression {
|
||||||
|
&self.rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Binary {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{} {} {}",
|
||||||
|
self.lhs.to_interned_string(interner),
|
||||||
|
self.op,
|
||||||
|
self.rhs.to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Binary> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: Binary) -> Self {
|
||||||
|
Self::Binary(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Binary {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.lhs));
|
||||||
|
visitor.visit_expression(&self.rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.lhs));
|
||||||
|
visitor.visit_expression_mut(&mut self.rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
578
javascript-engine/external/boa/boa_ast/src/expression/operator/binary/op.rs
vendored
Normal file
578
javascript-engine/external/boa/boa_ast/src/expression/operator/binary/op.rs
vendored
Normal file
@@ -0,0 +1,578 @@
|
|||||||
|
//! This module implements various structure for logic handling.
|
||||||
|
|
||||||
|
use std::fmt::{Display, Formatter, Result};
|
||||||
|
|
||||||
|
/// This represents a binary operation between two values.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BinaryOp {
|
||||||
|
/// Numeric operation.
|
||||||
|
///
|
||||||
|
/// see: [`NumOp`](enum.NumOp.html)
|
||||||
|
Arithmetic(ArithmeticOp),
|
||||||
|
|
||||||
|
/// Bitwise operation.
|
||||||
|
///
|
||||||
|
/// see: [`BitOp`](enum.BitOp.html).
|
||||||
|
Bitwise(BitwiseOp),
|
||||||
|
|
||||||
|
/// Comparative operation.
|
||||||
|
///
|
||||||
|
/// see: [`CompOp`](enum.CompOp.html).
|
||||||
|
Relational(RelationalOp),
|
||||||
|
|
||||||
|
/// Logical operation.
|
||||||
|
///
|
||||||
|
/// see: [`LogOp`](enum.LogOp.html).
|
||||||
|
Logical(LogicalOp),
|
||||||
|
|
||||||
|
/// Comma operation.
|
||||||
|
Comma,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArithmeticOp> for BinaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: ArithmeticOp) -> Self {
|
||||||
|
Self::Arithmetic(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BitwiseOp> for BinaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: BitwiseOp) -> Self {
|
||||||
|
Self::Bitwise(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RelationalOp> for BinaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: RelationalOp) -> Self {
|
||||||
|
Self::Relational(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LogicalOp> for BinaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: LogicalOp) -> Self {
|
||||||
|
Self::Logical(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Arithmetic(ref op) => op.as_str(),
|
||||||
|
Self::Bitwise(ref op) => op.as_str(),
|
||||||
|
Self::Relational(ref op) => op.as_str(),
|
||||||
|
Self::Logical(ref op) => op.as_str(),
|
||||||
|
Self::Comma => ",",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BinaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arithmetic operators take numerical values (either literals or variables)
|
||||||
|
/// as their operands and return a single numerical value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ArithmeticOp {
|
||||||
|
/// The addition operator produces the sum of numeric operands or string concatenation.
|
||||||
|
///
|
||||||
|
/// Syntax: `x + y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec].
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-addition-operator-plus
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition
|
||||||
|
Add,
|
||||||
|
|
||||||
|
/// The subtraction operator subtracts the two operands, producing their difference.
|
||||||
|
///
|
||||||
|
/// Syntax: `x - y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec].
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-subtraction-operator-minus
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Subtraction
|
||||||
|
Sub,
|
||||||
|
|
||||||
|
/// The division operator produces the quotient of its operands where the left operand
|
||||||
|
/// is the dividend and the right operand is the divisor.
|
||||||
|
///
|
||||||
|
/// Syntax: `x / y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Division
|
||||||
|
Div,
|
||||||
|
|
||||||
|
/// The multiplication operator produces the product of the operands.
|
||||||
|
///
|
||||||
|
/// Syntax: `x * y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Multiplication
|
||||||
|
Mul,
|
||||||
|
|
||||||
|
/// The exponentiation operator returns the result of raising the first operand to
|
||||||
|
/// the power of the second operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ** y`
|
||||||
|
///
|
||||||
|
/// The exponentiation operator is right-associative. a ** b ** c is equal to a ** (b ** c).
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-exp-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation
|
||||||
|
Exp,
|
||||||
|
|
||||||
|
/// The remainder operator returns the remainder left over when one operand is divided by a second operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x % y`
|
||||||
|
///
|
||||||
|
/// The remainder operator always takes the sign of the dividend.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeOperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder
|
||||||
|
Mod,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArithmeticOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Add => "+",
|
||||||
|
Self::Sub => "-",
|
||||||
|
Self::Div => "/",
|
||||||
|
Self::Mul => "*",
|
||||||
|
Self::Exp => "**",
|
||||||
|
Self::Mod => "%",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ArithmeticOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A bitwise operator is an operator used to perform bitwise operations
|
||||||
|
/// on bit patterns or binary numerals that involve the manipulation of individual bits.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BitwiseOp {
|
||||||
|
/// Performs the AND operation on each pair of bits. a AND b yields 1 only if both a and b are 1.
|
||||||
|
///
|
||||||
|
/// Syntax: `x & y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BitwiseANDExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_AND
|
||||||
|
And,
|
||||||
|
|
||||||
|
/// Performs the OR operation on each pair of bits. a OR b yields 1 if either a or b is 1.
|
||||||
|
///
|
||||||
|
/// Syntax: `x | y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BitwiseORExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR
|
||||||
|
Or,
|
||||||
|
|
||||||
|
/// Performs the XOR operation on each pair of bits. a XOR b yields 1 if a and b are different.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ^ y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BitwiseXORExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_XOR
|
||||||
|
Xor,
|
||||||
|
|
||||||
|
/// This operator shifts the first operand the specified number of bits to the left.
|
||||||
|
///
|
||||||
|
/// Syntax: `x << y`
|
||||||
|
///
|
||||||
|
/// Excess bits shifted off to the left are discarded. Zero bits are shifted in from the right.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-left-shift-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift
|
||||||
|
Shl,
|
||||||
|
|
||||||
|
/// This operator shifts the first operand the specified number of bits to the right.
|
||||||
|
///
|
||||||
|
/// Syntax: `x >> y`
|
||||||
|
///
|
||||||
|
/// Excess bits shifted off to the right are discarded. Copies of the leftmost bit
|
||||||
|
/// are shifted in from the left. Since the new leftmost bit has the same value as
|
||||||
|
/// the previous leftmost bit, the sign bit (the leftmost bit) does not change.
|
||||||
|
/// Hence the name "sign-propagating".
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-signed-right-shift-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift
|
||||||
|
Shr,
|
||||||
|
|
||||||
|
/// This operator shifts the first operand the specified number of bits to the right.
|
||||||
|
///
|
||||||
|
/// Syntax: `x >>> y`
|
||||||
|
///
|
||||||
|
/// Excess bits shifted off to the right are discarded. Zero bits are shifted in
|
||||||
|
/// from the left. The sign bit becomes 0, so the result is always non-negative.
|
||||||
|
/// Unlike the other bitwise operators, zero-fill right shift returns an unsigned 32-bit integer.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-unsigned-right-shift-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Unsigned_right_shift
|
||||||
|
UShr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitwiseOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::And => "&",
|
||||||
|
Self::Or => "|",
|
||||||
|
Self::Xor => "^",
|
||||||
|
Self::Shl => "<<",
|
||||||
|
Self::Shr => ">>",
|
||||||
|
Self::UShr => ">>>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BitwiseOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A relational operator compares its operands and returns a logical value based on whether the relation is true.
|
||||||
|
///
|
||||||
|
/// The operands can be numerical, string, logical, or object values. Strings are compared based on standard
|
||||||
|
/// lexicographical ordering, using Unicode values. In most cases, if the two operands are not of the same type,
|
||||||
|
/// JavaScript attempts to convert them to an appropriate type for the comparison. This behavior generally results in
|
||||||
|
/// comparing the operands numerically. The sole exceptions to type conversion within comparisons involve the `===` and `!==`
|
||||||
|
/// operators, which perform strict equality and inequality comparisons. These operators do not attempt to convert the operands
|
||||||
|
/// to compatible types before checking equality.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: tc39.es/ecma262/#sec-testing-and-comparison-operations
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Comparison
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum RelationalOp {
|
||||||
|
/// The equality operator converts the operands if they are not of the same type, then applies
|
||||||
|
/// strict comparison.
|
||||||
|
///
|
||||||
|
/// Syntax: `y == y`
|
||||||
|
///
|
||||||
|
/// If both operands are objects, then JavaScript compares internal references which are equal
|
||||||
|
/// when operands refer to the same object in memory.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-abstract-equality-comparison
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality
|
||||||
|
Equal,
|
||||||
|
|
||||||
|
/// The inequality operator returns `true` if the operands are not equal.
|
||||||
|
///
|
||||||
|
/// Syntax: `x != y`
|
||||||
|
///
|
||||||
|
/// If the two operands are not of the same type, JavaScript attempts to convert the operands
|
||||||
|
/// to an appropriate type for the comparison. If both operands are objects, then JavaScript
|
||||||
|
/// compares internal references which are not equal when operands refer to different objects
|
||||||
|
/// in memory.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-EqualityExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Inequality
|
||||||
|
NotEqual,
|
||||||
|
|
||||||
|
/// The identity operator returns `true` if the operands are strictly equal **with no type
|
||||||
|
/// conversion**.
|
||||||
|
///
|
||||||
|
/// Syntax: `x === y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the operands are equal and of the same type.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-strict-equality-comparison
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity
|
||||||
|
StrictEqual,
|
||||||
|
|
||||||
|
/// The non-identity operator returns `true` if the operands **are not equal and/or not of the
|
||||||
|
/// same type**.
|
||||||
|
///
|
||||||
|
/// Syntax: `x !== y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the operands are of the same type but not equal, or are of different type.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-EqualityExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Nonidentity>
|
||||||
|
StrictNotEqual,
|
||||||
|
|
||||||
|
/// The greater than operator returns `true` if the left operand is greater than the right
|
||||||
|
/// operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x > y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the left operand is greater than the right operand.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator
|
||||||
|
GreaterThan,
|
||||||
|
|
||||||
|
/// The greater than or equal operator returns `true` if the left operand is greater than or
|
||||||
|
/// equal to the right operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x >= y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the left operand is greater than the right operand.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator
|
||||||
|
GreaterThanOrEqual,
|
||||||
|
|
||||||
|
/// The less than operator returns `true` if the left operand is less than the right operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x < y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the left operand is less than the right operand.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_operator
|
||||||
|
LessThan,
|
||||||
|
|
||||||
|
/// The less than or equal operator returns `true` if the left operand is less than or equal to
|
||||||
|
/// the right operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x <= y`
|
||||||
|
///
|
||||||
|
/// Returns `true` if the left operand is less than or equal to the right operand.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_or_equal_operator
|
||||||
|
LessThanOrEqual,
|
||||||
|
|
||||||
|
/// The `in` operator returns `true` if the specified property is in the specified object or
|
||||||
|
/// its prototype chain.
|
||||||
|
///
|
||||||
|
/// Syntax: `prop in object`
|
||||||
|
///
|
||||||
|
/// Returns `true` the specified property is in the specified object or its prototype chain.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
|
||||||
|
In,
|
||||||
|
|
||||||
|
/// The `instanceof` operator returns `true` if the specified object is an instance of the
|
||||||
|
/// right hand side object.
|
||||||
|
///
|
||||||
|
/// Syntax: `obj instanceof Object`
|
||||||
|
///
|
||||||
|
/// Returns `true` the `prototype` property of the right hand side constructor appears anywhere
|
||||||
|
/// in the prototype chain of the object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
|
||||||
|
InstanceOf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelationalOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Equal => "==",
|
||||||
|
Self::NotEqual => "!=",
|
||||||
|
Self::StrictEqual => "===",
|
||||||
|
Self::StrictNotEqual => "!==",
|
||||||
|
Self::GreaterThan => ">",
|
||||||
|
Self::GreaterThanOrEqual => ">=",
|
||||||
|
Self::LessThan => "<",
|
||||||
|
Self::LessThanOrEqual => "<=",
|
||||||
|
Self::In => "in",
|
||||||
|
Self::InstanceOf => "instanceof",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for RelationalOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Logical operators are typically used with Boolean (logical) values; when they are, they return a Boolean value.
|
||||||
|
///
|
||||||
|
/// However, the `&&` and `||` operators actually return the value of one of the specified operands,
|
||||||
|
/// so if these operators are used with non-Boolean values, they may return a non-Boolean value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-binary-logical-operators
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum LogicalOp {
|
||||||
|
/// The logical AND operator returns the value of the first operand if it can be coerced into `false`;
|
||||||
|
/// otherwise, it returns the second operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x && y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-LogicalANDExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_AND
|
||||||
|
And,
|
||||||
|
|
||||||
|
/// The logical OR operator returns the value the first operand if it can be coerced into `true`;
|
||||||
|
/// otherwise, it returns the second operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x || y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-LogicalORExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR
|
||||||
|
Or,
|
||||||
|
|
||||||
|
/// The nullish coalescing operator is a logical operator that returns the second operand
|
||||||
|
/// when its first operand is null or undefined, and otherwise returns its first operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `x ?? y`
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-CoalesceExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
|
||||||
|
Coalesce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogicalOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::And => "&&",
|
||||||
|
Self::Or => "||",
|
||||||
|
Self::Coalesce => "??",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for LogicalOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
103
javascript-engine/external/boa/boa_ast/src/expression/operator/conditional.rs
vendored
Normal file
103
javascript-engine/external/boa/boa_ast/src/expression/operator/conditional.rs
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `conditional` (ternary) operation is the only ECMAScript operation that takes three
|
||||||
|
/// operands.
|
||||||
|
///
|
||||||
|
/// This operation takes three operands: a condition followed by a question mark (`?`),
|
||||||
|
/// then an expression to execute `if` the condition is truthy followed by a colon (`:`),
|
||||||
|
/// and finally the expression to execute if the condition is `false`.
|
||||||
|
/// This operator is frequently used as a shortcut for the `if` statement.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Conditional {
|
||||||
|
condition: Box<Expression>,
|
||||||
|
if_true: Box<Expression>,
|
||||||
|
if_false: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Conditional {
|
||||||
|
/// Gets the condition of the `Conditional` expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn condition(&self) -> &Expression {
|
||||||
|
&self.condition
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the expression returned if `condition` is truthy.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn if_true(&self) -> &Expression {
|
||||||
|
&self.if_true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the expression returned if `condition` is falsy.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn if_false(&self) -> &Expression {
|
||||||
|
&self.if_false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `Conditional` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(condition: Expression, if_true: Expression, if_false: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
condition: Box::new(condition),
|
||||||
|
if_true: Box::new(if_true),
|
||||||
|
if_false: Box::new(if_false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Conditional {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!(
|
||||||
|
"{} ? {} : {}",
|
||||||
|
self.condition().to_interned_string(interner),
|
||||||
|
self.if_true().to_interned_string(interner),
|
||||||
|
self.if_false().to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Conditional> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(cond_op: Conditional) -> Self {
|
||||||
|
Self::Conditional(cond_op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Conditional {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.condition));
|
||||||
|
try_break!(visitor.visit_expression(&self.if_true));
|
||||||
|
visitor.visit_expression(&self.if_false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.condition));
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.if_true));
|
||||||
|
visitor.visit_expression_mut(&mut self.if_false)
|
||||||
|
}
|
||||||
|
}
|
||||||
20
javascript-engine/external/boa/boa_ast/src/expression/operator/mod.rs
vendored
Normal file
20
javascript-engine/external/boa/boa_ast/src/expression/operator/mod.rs
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//! Operator expression nodes.
|
||||||
|
//!
|
||||||
|
//! An [operator][op] expression is an expression that takes an operator (such as `+`, `typeof`, `+=`)
|
||||||
|
//! and one or more expressions and returns an expression as a result.
|
||||||
|
//! An operator expression can be any of the following:
|
||||||
|
//!
|
||||||
|
//! - A [`Unary`] expression.
|
||||||
|
//! - An [`Assign`] expression.
|
||||||
|
//! - A [`Binary`] expression.
|
||||||
|
//! - A [`Conditional`] expression.
|
||||||
|
//!
|
||||||
|
//! [op]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators
|
||||||
|
|
||||||
|
mod conditional;
|
||||||
|
|
||||||
|
pub mod assign;
|
||||||
|
pub mod binary;
|
||||||
|
pub mod unary;
|
||||||
|
|
||||||
|
pub use self::{assign::Assign, binary::Binary, conditional::Conditional, unary::Unary};
|
||||||
102
javascript-engine/external/boa/boa_ast/src/expression/operator/unary/mod.rs
vendored
Normal file
102
javascript-engine/external/boa/boa_ast/src/expression/operator/unary/mod.rs
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
//! Unary expression nodes.
|
||||||
|
//!
|
||||||
|
//! A Binary expression comprises any operation applied to a single expression. Some examples include:
|
||||||
|
//!
|
||||||
|
//! - [Increment and decrement operations][inc] (`++`, `--`).
|
||||||
|
//! - The [`delete`][del] operator.
|
||||||
|
//! - The [bitwise NOT][not] operator (`~`).
|
||||||
|
//!
|
||||||
|
//! The full list of valid unary operators is defined in [`UnaryOp`].
|
||||||
|
//!
|
||||||
|
//! [inc]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#increment_and_decrement
|
||||||
|
//! [del]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
|
||||||
|
//! [not]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT
|
||||||
|
mod op;
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
pub use op::*;
|
||||||
|
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
|
||||||
|
use crate::expression::Expression;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
|
||||||
|
/// A unary expression is an operation with only one operand.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary_operators
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Unary {
|
||||||
|
op: UnaryOp,
|
||||||
|
target: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unary {
|
||||||
|
/// Creates a new `UnaryOp` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(op: UnaryOp, target: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
op,
|
||||||
|
target: Box::new(target),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the unary operation of the Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn op(&self) -> UnaryOp {
|
||||||
|
self.op
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the target of this unary operator.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn target(&self) -> &Expression {
|
||||||
|
self.target.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Unary {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let space = match self.op {
|
||||||
|
UnaryOp::TypeOf | UnaryOp::Delete | UnaryOp::Void => " ",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}{space}{}",
|
||||||
|
self.op,
|
||||||
|
self.target.to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Unary> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(op: Unary) -> Self {
|
||||||
|
Self::Unary(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Unary {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression(&self.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression_mut(&mut self.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
216
javascript-engine/external/boa/boa_ast/src/expression/operator/unary/op.rs
vendored
Normal file
216
javascript-engine/external/boa/boa_ast/src/expression/operator/unary/op.rs
vendored
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/// A unary operator is one that takes a single operand/argument and performs an operation.
|
||||||
|
///
|
||||||
|
/// A unary operation is an operation with only one operand. This operand comes either
|
||||||
|
/// before or after the operator. Unary operators are more efficient than standard JavaScript
|
||||||
|
/// function calls.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum UnaryOp {
|
||||||
|
/// The increment operator increments (adds one to) its operand and returns a value.
|
||||||
|
///
|
||||||
|
/// Syntax: `++x`
|
||||||
|
///
|
||||||
|
/// This operator increments and returns the value after incrementing.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-postfix-increment-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Increment
|
||||||
|
IncrementPost,
|
||||||
|
|
||||||
|
/// The increment operator increments (adds one to) its operand and returns a value.
|
||||||
|
///
|
||||||
|
/// Syntax: `x++`
|
||||||
|
///
|
||||||
|
/// This operator increments and returns the value before incrementing.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-prefix-increment-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Increment
|
||||||
|
IncrementPre,
|
||||||
|
|
||||||
|
/// The decrement operator decrements (subtracts one from) its operand and returns a value.
|
||||||
|
///
|
||||||
|
/// Syntax: `--x`
|
||||||
|
///
|
||||||
|
/// This operator decrements and returns the value before decrementing.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-postfix-decrement-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Decrement
|
||||||
|
DecrementPost,
|
||||||
|
|
||||||
|
/// The decrement operator decrements (subtracts one from) its operand and returns a value.
|
||||||
|
///
|
||||||
|
/// Syntax: `x--`
|
||||||
|
///
|
||||||
|
/// This operator decrements the operand and returns the value after decrementing.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-prefix-decrement-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Decrement
|
||||||
|
DecrementPre,
|
||||||
|
|
||||||
|
/// The unary negation operator precedes its operand and negates it.
|
||||||
|
///
|
||||||
|
/// Syntax: `-x`
|
||||||
|
///
|
||||||
|
/// Converts non-numbers data types to numbers like unary plus,
|
||||||
|
/// however, it performs an additional operation, negation.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-unary-minus-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_negation
|
||||||
|
Minus,
|
||||||
|
|
||||||
|
/// The unary plus operator attempts to convert the operand into a number, if it isn't already.
|
||||||
|
///
|
||||||
|
/// Syntax: `+x`
|
||||||
|
///
|
||||||
|
/// Although unary negation (`-`) also can convert non-numbers, unary plus is the fastest and preferred
|
||||||
|
/// way of converting something into a number, because it does not perform any other operations on the number.
|
||||||
|
/// It can convert `string` representations of integers and floats, as well as the non-string values `true`, `false`, and `null`.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-unary-plus-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus
|
||||||
|
Plus,
|
||||||
|
|
||||||
|
/// Returns `false` if its single operand can be converted to `true`; otherwise, returns `true`.
|
||||||
|
///
|
||||||
|
/// Syntax: `!x`
|
||||||
|
///
|
||||||
|
/// Boolean values simply get inverted: `!true === false` and `!false === true`.
|
||||||
|
/// Non-boolean values get converted to boolean values first, then are negated.
|
||||||
|
/// This means that it is possible to use a couple of NOT operators in series to explicitly
|
||||||
|
/// force the conversion of any value to the corresponding boolean primitive.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-logical-not-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT
|
||||||
|
Not,
|
||||||
|
|
||||||
|
/// Performs the NOT operator on each bit.
|
||||||
|
///
|
||||||
|
/// Syntax: `~x`
|
||||||
|
///
|
||||||
|
/// NOT `a` yields the inverted value (or one's complement) of `a`.
|
||||||
|
/// Bitwise NOTing any number x yields -(x + 1). For example, ~-5 yields 4.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-bitwise-not-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT
|
||||||
|
Tilde,
|
||||||
|
|
||||||
|
/// The `typeof` operator returns a string indicating the type of the unevaluated operand.
|
||||||
|
///
|
||||||
|
/// Syntax: `typeof x` or `typeof(x)`
|
||||||
|
///
|
||||||
|
/// The `typeof` is a JavaScript keyword that will return the type of a variable when you call it.
|
||||||
|
/// You can use this to validate function parameters or check if variables are defined.
|
||||||
|
/// There are other uses as well.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-typeof-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
|
||||||
|
TypeOf,
|
||||||
|
|
||||||
|
/// The JavaScript `delete` operator removes a property from an object.
|
||||||
|
///
|
||||||
|
/// Syntax: `delete x`
|
||||||
|
///
|
||||||
|
/// Unlike what common belief suggests, the delete operator has nothing to do with
|
||||||
|
/// directly freeing memory. Memory management is done indirectly via breaking references.
|
||||||
|
/// If no more references to the same property are held, it is eventually released automatically.
|
||||||
|
///
|
||||||
|
/// The `delete` operator returns `true` for all cases except when the property is an
|
||||||
|
/// [own](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)
|
||||||
|
/// [non-configurable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cant_delete)
|
||||||
|
/// property, in which case, `false` is returned in non-strict mode.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-delete-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
|
||||||
|
Delete,
|
||||||
|
|
||||||
|
/// The `void` operator evaluates the given `expression` and then returns `undefined`.
|
||||||
|
///
|
||||||
|
/// Syntax: `void x`
|
||||||
|
///
|
||||||
|
/// This operator allows evaluating expressions that produce a value into places where an
|
||||||
|
/// expression that evaluates to `undefined` is desired.
|
||||||
|
/// The `void` operator is often used merely to obtain the `undefined` primitive value, usually using `void(0)`
|
||||||
|
/// (which is equivalent to `void 0`). In these cases, the global variable undefined can be used.
|
||||||
|
///
|
||||||
|
/// When using an [immediately-invoked function expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE),
|
||||||
|
/// `void` can be used to force the function keyword to be treated as an expression instead of a declaration.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-void-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
|
||||||
|
Void,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnaryOp {
|
||||||
|
/// Retrieves the operation as a static string.
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::IncrementPost | Self::IncrementPre => "++",
|
||||||
|
Self::DecrementPost | Self::DecrementPre => "--",
|
||||||
|
Self::Plus => "+",
|
||||||
|
Self::Minus => "-",
|
||||||
|
Self::Not => "!",
|
||||||
|
Self::Tilde => "~",
|
||||||
|
Self::Delete => "delete",
|
||||||
|
Self::TypeOf => "typeof",
|
||||||
|
Self::Void => "void",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for UnaryOp {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
249
javascript-engine/external/boa/boa_ast/src/expression/optional.rs
vendored
Normal file
249
javascript-engine/external/boa/boa_ast/src/expression/optional.rs
vendored
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
use super::{access::PropertyAccessField, Expression};
|
||||||
|
use crate::{
|
||||||
|
function::PrivateName,
|
||||||
|
join_nodes, try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// List of valid operations in an [`Optional`] chain.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum OptionalOperationKind {
|
||||||
|
/// A property access (`a?.prop`).
|
||||||
|
SimplePropertyAccess {
|
||||||
|
/// The field accessed.
|
||||||
|
field: PropertyAccessField,
|
||||||
|
},
|
||||||
|
/// A private property access (`a?.#prop`).
|
||||||
|
PrivatePropertyAccess {
|
||||||
|
/// The private property accessed.
|
||||||
|
field: PrivateName,
|
||||||
|
},
|
||||||
|
/// A function call (`a?.(arg)`).
|
||||||
|
Call {
|
||||||
|
/// The args passed to the function call.
|
||||||
|
args: Box<[Expression]>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for OptionalOperationKind {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SimplePropertyAccess { field } => visitor.visit_property_access_field(field),
|
||||||
|
Self::PrivatePropertyAccess { field } => visitor.visit_private_name(field),
|
||||||
|
Self::Call { args } => {
|
||||||
|
for arg in args.iter() {
|
||||||
|
try_break!(visitor.visit_expression(arg));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SimplePropertyAccess { field } => visitor.visit_property_access_field_mut(field),
|
||||||
|
Self::PrivatePropertyAccess { field } => visitor.visit_private_name_mut(field),
|
||||||
|
Self::Call { args } => {
|
||||||
|
for arg in args.iter_mut() {
|
||||||
|
try_break!(visitor.visit_expression_mut(arg));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Operation within an [`Optional`] chain.
|
||||||
|
///
|
||||||
|
/// An operation within an `Optional` chain can be either shorted or non-shorted. A shorted operation
|
||||||
|
/// (`?.item`) will force the expression to return `undefined` if the target is `undefined` or `null`.
|
||||||
|
/// In contrast, a non-shorted operation (`.prop`) will try to access the property, even if the target
|
||||||
|
/// is `undefined` or `null`.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct OptionalOperation {
|
||||||
|
kind: OptionalOperationKind,
|
||||||
|
shorted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OptionalOperation {
|
||||||
|
/// Creates a new `OptionalOperation`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(kind: OptionalOperationKind, shorted: bool) -> Self {
|
||||||
|
Self { kind, shorted }
|
||||||
|
}
|
||||||
|
/// Gets the kind of operation.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn kind(&self) -> &OptionalOperationKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the operation short-circuits the [`Optional`] chain when the target is
|
||||||
|
/// `undefined` or `null`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn shorted(&self) -> bool {
|
||||||
|
self.shorted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for OptionalOperation {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = if self.shorted {
|
||||||
|
String::from("?.")
|
||||||
|
} else {
|
||||||
|
if let OptionalOperationKind::SimplePropertyAccess {
|
||||||
|
field: PropertyAccessField::Const(name),
|
||||||
|
} = &self.kind
|
||||||
|
{
|
||||||
|
return format!(".{}", interner.resolve_expect(*name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let OptionalOperationKind::PrivatePropertyAccess { field } = &self.kind {
|
||||||
|
return format!(".#{}", interner.resolve_expect(field.description()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
buf.push_str(&match &self.kind {
|
||||||
|
OptionalOperationKind::SimplePropertyAccess { field } => match field {
|
||||||
|
PropertyAccessField::Const(name) => interner.resolve_expect(*name).to_string(),
|
||||||
|
PropertyAccessField::Expr(expr) => {
|
||||||
|
format!("[{}]", expr.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OptionalOperationKind::PrivatePropertyAccess { field } => {
|
||||||
|
format!("#{}", interner.resolve_expect(field.description()))
|
||||||
|
}
|
||||||
|
OptionalOperationKind::Call { args } => format!("({})", join_nodes(interner, args)),
|
||||||
|
});
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for OptionalOperation {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_optional_operation_kind(&self.kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_optional_operation_kind_mut(&mut self.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An optional chain expression, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [Optional chaining][mdn] allows for short-circuiting property accesses and function calls, which
|
||||||
|
/// will return `undefined` instead of returning an error if the access target or the call is
|
||||||
|
/// either `undefined` or `null`.
|
||||||
|
///
|
||||||
|
/// An example of optional chaining:
|
||||||
|
///
|
||||||
|
/// ```Javascript
|
||||||
|
/// const adventurer = {
|
||||||
|
/// name: 'Alice',
|
||||||
|
/// cat: {
|
||||||
|
/// name: 'Dinah'
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// console.log(adventurer.cat?.name); // Dinah
|
||||||
|
/// console.log(adventurer.dog?.name); // undefined
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-OptionalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Optional {
|
||||||
|
target: Box<Expression>,
|
||||||
|
chain: Box<[OptionalOperation]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Optional {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.target));
|
||||||
|
for op in self.chain.iter() {
|
||||||
|
try_break!(visitor.visit_optional_operation(op));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.target));
|
||||||
|
for op in self.chain.iter_mut() {
|
||||||
|
try_break!(visitor.visit_optional_operation_mut(op));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Optional {
|
||||||
|
/// Creates a new `Optional` expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(target: Expression, chain: Box<[OptionalOperation]>) -> Self {
|
||||||
|
Self {
|
||||||
|
target: Box::new(target),
|
||||||
|
chain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the target of this `Optional` expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn target(&self) -> &Expression {
|
||||||
|
self.target.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the chain of accesses and calls that will be applied to the target at runtime.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn chain(&self) -> &[OptionalOperation] {
|
||||||
|
self.chain.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Optional> for Expression {
|
||||||
|
fn from(opt: Optional) -> Self {
|
||||||
|
Self::Optional(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Optional {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = self.target.to_interned_string(interner);
|
||||||
|
|
||||||
|
for item in &*self.chain {
|
||||||
|
buf.push_str(&item.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
78
javascript-engine/external/boa/boa_ast/src/expression/spread.rs
vendored
Normal file
78
javascript-engine/external/boa/boa_ast/src/expression/spread.rs
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// The `spread` operator allows an iterable such as an array expression or string to be
|
||||||
|
/// expanded.
|
||||||
|
///
|
||||||
|
/// Syntax: `...x`
|
||||||
|
///
|
||||||
|
/// It expands array expressions or strings in places where zero or more arguments (for
|
||||||
|
/// function calls) or elements (for array literals)
|
||||||
|
/// are expected, or an object expression to be expanded in places where zero or more key-value
|
||||||
|
/// pairs (for object literals) are expected.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-SpreadElement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Spread {
|
||||||
|
target: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Spread {
|
||||||
|
/// Gets the target expression to be expanded by the spread operator.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `Spread` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(target: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
target: Box::new(target),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Spread {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("...{}", self.target().to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Spread> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(spread: Spread) -> Self {
|
||||||
|
Self::Spread(spread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Spread {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression(&self.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression_mut(&mut self.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
132
javascript-engine/external/boa/boa_ast/src/expression/tagged_template.rs
vendored
Normal file
132
javascript-engine/external/boa/boa_ast/src/expression/tagged_template.rs
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// A [`TaggedTemplate`][moz] expression, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// `TaggedTemplate`s are a type of template literals that are parsed by a custom function to generate
|
||||||
|
/// arbitrary objects from the inner strings and expressions.
|
||||||
|
///
|
||||||
|
/// [moz]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-tagged-templates
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct TaggedTemplate {
|
||||||
|
tag: Box<Expression>,
|
||||||
|
raws: Box<[Sym]>,
|
||||||
|
cookeds: Box<[Option<Sym>]>,
|
||||||
|
exprs: Box<[Expression]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaggedTemplate {
|
||||||
|
/// Creates a new tagged template with a tag, the list of raw strings, the cooked strings and
|
||||||
|
/// the expressions.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
tag: Expression,
|
||||||
|
raws: Box<[Sym]>,
|
||||||
|
cookeds: Box<[Option<Sym>]>,
|
||||||
|
exprs: Box<[Expression]>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
tag: tag.into(),
|
||||||
|
raws,
|
||||||
|
cookeds,
|
||||||
|
exprs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the tag function of the template.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn tag(&self) -> &Expression {
|
||||||
|
&self.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the inner raw strings of the template.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn raws(&self) -> &[Sym] {
|
||||||
|
&self.raws
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the cooked strings of the template.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cookeds(&self) -> &[Option<Sym>] {
|
||||||
|
&self.cookeds
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the interpolated expressions of the template.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn exprs(&self) -> &[Expression] {
|
||||||
|
&self.exprs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for TaggedTemplate {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = format!("{}`", self.tag.to_interned_string(interner));
|
||||||
|
for (&raw, expr) in self.raws.iter().zip(self.exprs.iter()) {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"{}${{{}}}",
|
||||||
|
interner.resolve_expect(raw),
|
||||||
|
expr.to_interned_string(interner)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
buf.push('`');
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TaggedTemplate> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(template: TaggedTemplate) -> Self {
|
||||||
|
Self::TaggedTemplate(template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for TaggedTemplate {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.tag));
|
||||||
|
for raw in self.raws.iter() {
|
||||||
|
try_break!(visitor.visit_sym(raw));
|
||||||
|
}
|
||||||
|
for cooked in self.cookeds.iter().flatten() {
|
||||||
|
try_break!(visitor.visit_sym(cooked));
|
||||||
|
}
|
||||||
|
for expr in self.exprs.iter() {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.tag));
|
||||||
|
for raw in self.raws.iter_mut() {
|
||||||
|
try_break!(visitor.visit_sym_mut(raw));
|
||||||
|
}
|
||||||
|
for cooked in self.cookeds.iter_mut().flatten() {
|
||||||
|
try_break!(visitor.visit_sym_mut(cooked));
|
||||||
|
}
|
||||||
|
for expr in self.exprs.iter_mut() {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
90
javascript-engine/external/boa/boa_ast/src/expression/yield.rs
vendored
Normal file
90
javascript-engine/external/boa/boa_ast/src/expression/yield.rs
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
|
||||||
|
use super::Expression;
|
||||||
|
|
||||||
|
/// The `yield` keyword is used to pause and resume a generator function
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-YieldExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Yield {
|
||||||
|
target: Option<Box<Expression>>,
|
||||||
|
delegate: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Yield {
|
||||||
|
/// Gets the target expression of this `Yield` statement.
|
||||||
|
#[inline]
|
||||||
|
pub fn target(&self) -> Option<&Expression> {
|
||||||
|
self.target.as_ref().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this `Yield` statement delegates to another generator or iterable object.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn delegate(&self) -> bool {
|
||||||
|
self.delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `Yield` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(expr: Option<Expression>, delegate: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
target: expr.map(Box::new),
|
||||||
|
delegate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Yield> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(r#yield: Yield) -> Self {
|
||||||
|
Self::Yield(r#yield)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Yield {
|
||||||
|
#[inline]
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let y = if self.delegate { "yield*" } else { "yield" };
|
||||||
|
if let Some(ex) = self.target() {
|
||||||
|
format!("{y} {}", ex.to_interned_string(interner))
|
||||||
|
} else {
|
||||||
|
y.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Yield {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(expr) = &self.target {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(expr) = &mut self.target {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
118
javascript-engine/external/boa/boa_ast/src/function/arrow_function.rs
vendored
Normal file
118
javascript-engine/external/boa/boa_ast/src/function/arrow_function.rs
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes, StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::FormalParameterList;
|
||||||
|
|
||||||
|
/// An arrow function expression, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// An [arrow function][mdn] expression is a syntactically compact alternative to a regular function
|
||||||
|
/// expression. Arrow function expressions are ill suited as methods, and they cannot be used as
|
||||||
|
/// constructors. Arrow functions cannot be used as constructors and will throw an error when
|
||||||
|
/// used with new.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ArrowFunction {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrowFunction {
|
||||||
|
/// Creates a new `ArrowFunctionDecl` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
params: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters: params,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_name(&mut self, name: Option<Identifier>) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the arrow function.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the arrow function.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for ArrowFunction {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = format!("({}", join_nodes(interner, self.parameters.as_ref()));
|
||||||
|
if self.body().statements().is_empty() {
|
||||||
|
buf.push_str(") => {}");
|
||||||
|
} else {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
") => {{\n{}{}}}",
|
||||||
|
self.body.to_indented_string(interner, indentation + 1),
|
||||||
|
" ".repeat(indentation)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArrowFunction> for Expression {
|
||||||
|
fn from(decl: ArrowFunction) -> Self {
|
||||||
|
Self::ArrowFunction(decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ArrowFunction {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
118
javascript-engine/external/boa/boa_ast/src/function/async_arrow_function.rs
vendored
Normal file
118
javascript-engine/external/boa/boa_ast/src/function/async_arrow_function.rs
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::FormalParameterList;
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes, StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
|
||||||
|
/// An async arrow function expression, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// An [async arrow function][mdn] expression is a syntactically compact alternative to a regular function
|
||||||
|
/// expression. Arrow function expressions are ill suited as methods, and they cannot be used as
|
||||||
|
/// constructors. Arrow functions cannot be used as constructors and will throw an error when
|
||||||
|
/// used with new.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct AsyncArrowFunction {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncArrowFunction {
|
||||||
|
/// Creates a new `AsyncArrowFunction` AST Expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_name(&mut self, name: Option<Identifier>) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the arrow function.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the arrow function.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for AsyncArrowFunction {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = format!("async ({}", join_nodes(interner, self.parameters.as_ref()));
|
||||||
|
if self.body().statements().is_empty() {
|
||||||
|
buf.push_str(") => {}");
|
||||||
|
} else {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
") => {{\n{}{}}}",
|
||||||
|
self.body.to_indented_string(interner, indentation + 1),
|
||||||
|
" ".repeat(indentation)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AsyncArrowFunction> for Expression {
|
||||||
|
fn from(decl: AsyncArrowFunction) -> Self {
|
||||||
|
Self::AsyncArrowFunction(decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for AsyncArrowFunction {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
138
javascript-engine/external/boa/boa_ast/src/function/async_function.rs
vendored
Normal file
138
javascript-engine/external/boa/boa_ast/src/function/async_function.rs
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
//! Async Function Expression.
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes, Declaration, StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::FormalParameterList;
|
||||||
|
|
||||||
|
/// An async function definition, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// An [async function][mdn] is a function where await expressions are allowed within it.
|
||||||
|
/// The async and await keywords enable asynchronous programming on Javascript without the use
|
||||||
|
/// of promise chains.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-async-function-definitions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct AsyncFunction {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncFunction {
|
||||||
|
/// Creates a new function expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
has_binding_identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the function expression has a binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_binding_identifier(&self) -> bool {
|
||||||
|
self.has_binding_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for AsyncFunction {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = "async function".to_owned();
|
||||||
|
if let Some(name) = self.name {
|
||||||
|
buf.push_str(&format!(" {}", interner.resolve_expect(name.sym())));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"({}",
|
||||||
|
join_nodes(interner, self.parameters.as_ref())
|
||||||
|
));
|
||||||
|
if self.body().statements().is_empty() {
|
||||||
|
buf.push_str(") {}");
|
||||||
|
} else {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
") {{\n{}{}}}",
|
||||||
|
self.body.to_indented_string(interner, indentation + 1),
|
||||||
|
" ".repeat(indentation)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AsyncFunction> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: AsyncFunction) -> Self {
|
||||||
|
Self::AsyncFunction(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AsyncFunction> for Declaration {
|
||||||
|
#[inline]
|
||||||
|
fn from(f: AsyncFunction) -> Self {
|
||||||
|
Self::AsyncFunction(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for AsyncFunction {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
130
javascript-engine/external/boa/boa_ast/src/function/async_generator.rs
vendored
Normal file
130
javascript-engine/external/boa/boa_ast/src/function/async_generator.rs
vendored
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
//! Async Generator Expression
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
block_to_string,
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes, Declaration, StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::FormalParameterList;
|
||||||
|
|
||||||
|
/// An async generator definition, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// An [async generator][mdn] combines async functions with generators, making it possible to use
|
||||||
|
/// `await` and `yield` expressions within the definition of the function.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-async-generator-function-definitions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct AsyncGenerator {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncGenerator {
|
||||||
|
/// Creates a new async generator expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
has_binding_identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the async generator expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the async generator expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the async generator expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the function expression has a binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_binding_identifier(&self) -> bool {
|
||||||
|
self.has_binding_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for AsyncGenerator {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = "async function*".to_owned();
|
||||||
|
if let Some(name) = self.name {
|
||||||
|
buf.push_str(&format!(" {}", interner.resolve_expect(name.sym())));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"({}) {}",
|
||||||
|
join_nodes(interner, self.parameters.as_ref()),
|
||||||
|
block_to_string(&self.body, interner, indentation)
|
||||||
|
));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AsyncGenerator> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: AsyncGenerator) -> Self {
|
||||||
|
Self::AsyncGenerator(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AsyncGenerator> for Declaration {
|
||||||
|
#[inline]
|
||||||
|
fn from(f: AsyncGenerator) -> Self {
|
||||||
|
Self::AsyncGenerator(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for AsyncGenerator {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
579
javascript-engine/external/boa/boa_ast/src/function/class.rs
vendored
Normal file
579
javascript-engine/external/boa/boa_ast/src/function/class.rs
vendored
Normal file
@@ -0,0 +1,579 @@
|
|||||||
|
use super::Function;
|
||||||
|
use crate::{
|
||||||
|
block_to_string,
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes,
|
||||||
|
property::{MethodDefinition, PropertyName},
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
Declaration, StatementList, ToStringEscaped,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
/// A class declaration, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// A [class][mdn] declaration defines a class with the specified methods, fields, and optional constructor.
|
||||||
|
/// Classes can be used to create objects, which can also be created through literals (using `{}`).
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-class-definitions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Class {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
super_ref: Option<Expression>,
|
||||||
|
pub(crate) constructor: Option<Function>,
|
||||||
|
pub(crate) elements: Box<[ClassElement]>,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Class {
|
||||||
|
/// Creates a new class declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
super_ref: Option<Expression>,
|
||||||
|
constructor: Option<Function>,
|
||||||
|
elements: Box<[ClassElement]>,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
super_ref,
|
||||||
|
constructor,
|
||||||
|
elements,
|
||||||
|
has_binding_identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the class.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the super class ref of the class.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn super_ref(&self) -> Option<&Expression> {
|
||||||
|
self.super_ref.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the constructor of the class.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn constructor(&self) -> Option<&Function> {
|
||||||
|
self.constructor.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of all fields defined on the class.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn elements(&self) -> &[ClassElement] {
|
||||||
|
&self.elements
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the class has a binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_binding_identifier(&self) -> bool {
|
||||||
|
self.has_binding_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Class {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
|
||||||
|
let class_name = self.name.map_or(Cow::Borrowed(""), |s| {
|
||||||
|
interner.resolve_expect(s.sym()).join(
|
||||||
|
Cow::Borrowed,
|
||||||
|
|utf16| Cow::Owned(utf16.to_string_escaped()),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
if self.elements.is_empty() && self.constructor().is_none() {
|
||||||
|
return format!(
|
||||||
|
"class {class_name}{} {{}}",
|
||||||
|
self.super_ref
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(String::new, |sup| format!(
|
||||||
|
" extends {}",
|
||||||
|
sup.to_interned_string(interner)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let indentation = " ".repeat(indent_n + 1);
|
||||||
|
let mut buf = format!(
|
||||||
|
"class {class_name}{} {{\n",
|
||||||
|
self.super_ref
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(String::new, |sup| format!(
|
||||||
|
"extends {}",
|
||||||
|
sup.to_interned_string(interner)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
if let Some(expr) = &self.constructor {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"{indentation}constructor({}) {}\n",
|
||||||
|
join_nodes(interner, expr.parameters().as_ref()),
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for element in self.elements.iter() {
|
||||||
|
buf.push_str(&match element {
|
||||||
|
ClassElement::MethodDefinition(name, method) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}{}{}({}) {}\n",
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(_) => "get ",
|
||||||
|
MethodDefinition::Set(_) => "set ",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
name.to_interned_string(interner),
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ClassElement::StaticMethodDefinition(name, method) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static {}{}({}) {}\n",
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(_) => "get ",
|
||||||
|
MethodDefinition::Set(_) => "set ",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
name.to_interned_string(interner),
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ClassElement::FieldDefinition(name, field) => match field {
|
||||||
|
Some(expr) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}{} = {};\n",
|
||||||
|
name.to_interned_string(interner),
|
||||||
|
expr.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format!("{indentation}{};\n", name.to_interned_string(interner),)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassElement::StaticFieldDefinition(name, field) => match field {
|
||||||
|
Some(expr) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static {} = {};\n",
|
||||||
|
name.to_interned_string(interner),
|
||||||
|
expr.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static {};\n",
|
||||||
|
name.to_interned_string(interner),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassElement::PrivateMethodDefinition(name, method) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}{}#{}({}) {}\n",
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(_) => "get ",
|
||||||
|
MethodDefinition::Set(_) => "set ",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ClassElement::PrivateStaticMethodDefinition(name, method) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static {}#{}({}) {}\n",
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(_) => "get ",
|
||||||
|
MethodDefinition::Set(_) => "set ",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
join_nodes(interner, expr.parameters().as_ref())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match &method {
|
||||||
|
MethodDefinition::Get(expr)
|
||||||
|
| MethodDefinition::Set(expr)
|
||||||
|
| MethodDefinition::Ordinary(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::AsyncGenerator(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
MethodDefinition::Async(expr) => {
|
||||||
|
block_to_string(expr.body(), interner, indent_n + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ClassElement::PrivateFieldDefinition(name, field) => match field {
|
||||||
|
Some(expr) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}#{} = {};\n",
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
expr.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format!(
|
||||||
|
"{indentation}#{};\n",
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassElement::PrivateStaticFieldDefinition(name, field) => match field {
|
||||||
|
Some(expr) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static #{} = {};\n",
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
expr.to_no_indent_string(interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static #{};\n",
|
||||||
|
interner.resolve_expect(name.description()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassElement::StaticBlock(statement_list) => {
|
||||||
|
format!(
|
||||||
|
"{indentation}static {}\n",
|
||||||
|
block_to_string(statement_list, interner, indent_n + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
buf.push('}');
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Class> for Expression {
|
||||||
|
fn from(expr: Class) -> Self {
|
||||||
|
Self::Class(Box::new(expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Class> for Declaration {
|
||||||
|
fn from(f: Class) -> Self {
|
||||||
|
Self::Class(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Class {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &self.super_ref {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
if let Some(func) = &self.constructor {
|
||||||
|
try_break!(visitor.visit_function(func));
|
||||||
|
}
|
||||||
|
for elem in self.elements.iter() {
|
||||||
|
try_break!(visitor.visit_class_element(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &mut self.super_ref {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
if let Some(func) = &mut self.constructor {
|
||||||
|
try_break!(visitor.visit_function_mut(func));
|
||||||
|
}
|
||||||
|
for elem in self.elements.iter_mut() {
|
||||||
|
try_break!(visitor.visit_class_element_mut(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An element that can be within a [`Class`], as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ClassElement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ClassElement {
|
||||||
|
/// A method definition, including `get` and `set` accessors.
|
||||||
|
MethodDefinition(PropertyName, MethodDefinition),
|
||||||
|
|
||||||
|
/// A static method definition, accessible from the class constructor object.
|
||||||
|
StaticMethodDefinition(PropertyName, MethodDefinition),
|
||||||
|
|
||||||
|
/// A field definition.
|
||||||
|
FieldDefinition(PropertyName, Option<Expression>),
|
||||||
|
|
||||||
|
/// A static field definition, accessible from the class constructor object
|
||||||
|
StaticFieldDefinition(PropertyName, Option<Expression>),
|
||||||
|
|
||||||
|
/// A private method definition, only accessible inside the class declaration.
|
||||||
|
PrivateMethodDefinition(PrivateName, MethodDefinition),
|
||||||
|
|
||||||
|
/// A private static method definition, only accessible from static methods and fields inside
|
||||||
|
/// the class declaration.
|
||||||
|
PrivateStaticMethodDefinition(PrivateName, MethodDefinition),
|
||||||
|
|
||||||
|
/// A private field definition, only accessible inside the class declaration.
|
||||||
|
PrivateFieldDefinition(PrivateName, Option<Expression>),
|
||||||
|
|
||||||
|
/// A private static field definition, only accessible from static methods and fields inside the
|
||||||
|
/// class declaration.
|
||||||
|
PrivateStaticFieldDefinition(PrivateName, Option<Expression>),
|
||||||
|
|
||||||
|
/// A static block, where a class can have initialization logic for its static fields.
|
||||||
|
StaticBlock(StatementList),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ClassElement {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::MethodDefinition(pn, md) | Self::StaticMethodDefinition(pn, md) => {
|
||||||
|
try_break!(visitor.visit_property_name(pn));
|
||||||
|
visitor.visit_method_definition(md)
|
||||||
|
}
|
||||||
|
Self::FieldDefinition(pn, maybe_expr) | Self::StaticFieldDefinition(pn, maybe_expr) => {
|
||||||
|
try_break!(visitor.visit_property_name(pn));
|
||||||
|
if let Some(expr) = maybe_expr {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::PrivateMethodDefinition(name, md)
|
||||||
|
| Self::PrivateStaticMethodDefinition(name, md) => {
|
||||||
|
try_break!(visitor.visit_private_name(name));
|
||||||
|
visitor.visit_method_definition(md)
|
||||||
|
}
|
||||||
|
Self::PrivateFieldDefinition(name, maybe_expr)
|
||||||
|
| Self::PrivateStaticFieldDefinition(name, maybe_expr) => {
|
||||||
|
try_break!(visitor.visit_private_name(name));
|
||||||
|
if let Some(expr) = maybe_expr {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::StaticBlock(sl) => visitor.visit_statement_list(sl),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::MethodDefinition(pn, md) | Self::StaticMethodDefinition(pn, md) => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(pn));
|
||||||
|
visitor.visit_method_definition_mut(md)
|
||||||
|
}
|
||||||
|
Self::FieldDefinition(pn, maybe_expr) | Self::StaticFieldDefinition(pn, maybe_expr) => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(pn));
|
||||||
|
if let Some(expr) = maybe_expr {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::PrivateMethodDefinition(name, md)
|
||||||
|
| Self::PrivateStaticMethodDefinition(name, md) => {
|
||||||
|
try_break!(visitor.visit_private_name_mut(name));
|
||||||
|
visitor.visit_method_definition_mut(md)
|
||||||
|
}
|
||||||
|
Self::PrivateFieldDefinition(name, maybe_expr)
|
||||||
|
| Self::PrivateStaticFieldDefinition(name, maybe_expr) => {
|
||||||
|
try_break!(visitor.visit_private_name_mut(name));
|
||||||
|
if let Some(expr) = maybe_expr {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::StaticBlock(sl) => visitor.visit_statement_list_mut(sl),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A private name as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-private-names
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PrivateName {
|
||||||
|
/// The `[[Description]]` internal slot of the private name.
|
||||||
|
description: Sym,
|
||||||
|
|
||||||
|
/// The indices of the private name are included to ensure that private names are unique.
|
||||||
|
pub(crate) indices: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrivateName {
|
||||||
|
/// Create a new private name.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(description: Sym) -> Self {
|
||||||
|
Self {
|
||||||
|
description,
|
||||||
|
indices: (0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the description of the private name.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn description(&self) -> Sym {
|
||||||
|
self.description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PrivateName {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_sym(&self.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_sym_mut(&mut self.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
132
javascript-engine/external/boa/boa_ast/src/function/generator.rs
vendored
Normal file
132
javascript-engine/external/boa/boa_ast/src/function/generator.rs
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
use crate::{
|
||||||
|
block_to_string,
|
||||||
|
expression::{Expression, Identifier},
|
||||||
|
join_nodes, Declaration, StatementList,
|
||||||
|
};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
|
||||||
|
use super::FormalParameterList;
|
||||||
|
|
||||||
|
/// A generator definition, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [Generators][mdn] are "resumable functions", which can be suspended during execution and
|
||||||
|
/// resumed at any later time. The main feature of a generator are `yield` expressions, which
|
||||||
|
/// specifies the value returned when a generator is suspended, and the point from which
|
||||||
|
/// the execution will resume.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-generator-function-definitions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Generator {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Generator {
|
||||||
|
/// Creates a new generator expression
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
has_binding_identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the generator declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the generator declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the generator declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the function expression has a binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_binding_identifier(&self) -> bool {
|
||||||
|
self.has_binding_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Generator {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = "function*".to_owned();
|
||||||
|
if let Some(name) = self.name {
|
||||||
|
buf.push_str(&format!(" {}", interner.resolve_expect(name.sym())));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"({}) {}",
|
||||||
|
join_nodes(interner, self.parameters.as_ref()),
|
||||||
|
block_to_string(&self.body, interner, indentation)
|
||||||
|
));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Generator> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: Generator) -> Self {
|
||||||
|
Self::Generator(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Generator> for Declaration {
|
||||||
|
#[inline]
|
||||||
|
fn from(f: Generator) -> Self {
|
||||||
|
Self::Generator(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Generator {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
184
javascript-engine/external/boa/boa_ast/src/function/mod.rs
vendored
Normal file
184
javascript-engine/external/boa/boa_ast/src/function/mod.rs
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
//! Functions and classes nodes, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! [Functions][func] are mainly subprograms that can be called by external code to execute a sequence of
|
||||||
|
//! statements (the *body* of the function). Javascript functions fall in several categories:
|
||||||
|
//!
|
||||||
|
//! - [`Function`]s.
|
||||||
|
//! - [`ArrowFunction`]s.
|
||||||
|
//! - [`AsyncArrowFunction`]s.
|
||||||
|
//! - [`Generator`]s.
|
||||||
|
//! - [`AsyncFunction`]s.
|
||||||
|
//! - [`AsyncGenerator`]s.
|
||||||
|
//!
|
||||||
|
//! All of them can be declared in either [declaration][decl] form or [expression][expr] form,
|
||||||
|
//! except from `ArrowFunction`s and `AsyncArrowFunction`s, which can only be declared in expression form.
|
||||||
|
//!
|
||||||
|
//! This module also contains [`Class`]es, which are templates for creating objects. Classes
|
||||||
|
//! can also be declared in either declaration or expression form.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#sec-ecmascript-language-functions-and-classes
|
||||||
|
//! [func]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
|
||||||
|
//! [decl]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function
|
||||||
|
//! [expr]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
|
||||||
|
|
||||||
|
mod arrow_function;
|
||||||
|
mod async_arrow_function;
|
||||||
|
mod async_function;
|
||||||
|
mod async_generator;
|
||||||
|
mod class;
|
||||||
|
mod generator;
|
||||||
|
mod parameters;
|
||||||
|
|
||||||
|
pub use arrow_function::ArrowFunction;
|
||||||
|
pub use async_arrow_function::AsyncArrowFunction;
|
||||||
|
pub use async_function::AsyncFunction;
|
||||||
|
pub use async_generator::AsyncGenerator;
|
||||||
|
pub use class::{Class, ClassElement, PrivateName};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
pub use generator::Generator;
|
||||||
|
pub use parameters::{FormalParameter, FormalParameterList, FormalParameterListFlags};
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{block_to_string, join_nodes, StatementList};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
|
||||||
|
use super::expression::{Expression, Identifier};
|
||||||
|
use super::Declaration;
|
||||||
|
|
||||||
|
/// A function definition, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// By default, functions return `undefined`. To return any other value, the function must have
|
||||||
|
/// a return statement that specifies the value to return.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-function-definitions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Function {
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
/// Creates a new function expression.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
has_binding_identifier: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new function expression with an expression binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new_with_binding_identifier(
|
||||||
|
name: Option<Identifier>,
|
||||||
|
parameters: FormalParameterList,
|
||||||
|
body: StatementList,
|
||||||
|
has_binding_identifier: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
has_binding_identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the name of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn name(&self) -> Option<Identifier> {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of parameters of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameters(&self) -> &FormalParameterList {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the function declaration.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the function expression has a binding identifier.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_binding_identifier(&self) -> bool {
|
||||||
|
self.has_binding_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Function {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = "function".to_owned();
|
||||||
|
if let Some(name) = self.name {
|
||||||
|
buf.push_str(&format!(" {}", interner.resolve_expect(name.sym())));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"({}) {}",
|
||||||
|
join_nodes(interner, self.parameters.as_ref()),
|
||||||
|
block_to_string(&self.body, interner, indentation)
|
||||||
|
));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Function> for Expression {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: Function) -> Self {
|
||||||
|
Self::Function(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Function> for Declaration {
|
||||||
|
#[inline]
|
||||||
|
fn from(f: Function) -> Self {
|
||||||
|
Self::Function(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Function {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &self.name {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(ident) = &mut self.name {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
}
|
||||||
|
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
287
javascript-engine/external/boa/boa_ast/src/function/parameters.rs
vendored
Normal file
287
javascript-engine/external/boa/boa_ast/src/function/parameters.rs
vendored
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
use crate::{
|
||||||
|
declaration::{Binding, Variable},
|
||||||
|
expression::Expression,
|
||||||
|
operations::bound_names,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
|
/// A list of `FormalParameter`s that describes the parameters of a function, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-FormalParameterList
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
|
pub struct FormalParameterList {
|
||||||
|
parameters: Box<[FormalParameter]>,
|
||||||
|
flags: FormalParameterListFlags,
|
||||||
|
length: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormalParameterList {
|
||||||
|
/// Creates a new empty formal parameter list.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
parameters: Box::new([]),
|
||||||
|
flags: FormalParameterListFlags::default(),
|
||||||
|
length: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `FormalParameterList` from a list of [`FormalParameter`]s.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_parameters(parameters: Vec<FormalParameter>) -> Self {
|
||||||
|
let mut flags = FormalParameterListFlags::default();
|
||||||
|
let mut length = 0;
|
||||||
|
let mut names = FxHashSet::default();
|
||||||
|
|
||||||
|
for parameter in ¶meters {
|
||||||
|
let parameter_names = bound_names(parameter);
|
||||||
|
|
||||||
|
for name in parameter_names {
|
||||||
|
if name == Sym::ARGUMENTS {
|
||||||
|
flags |= FormalParameterListFlags::HAS_ARGUMENTS;
|
||||||
|
}
|
||||||
|
if names.contains(&name) {
|
||||||
|
flags |= FormalParameterListFlags::HAS_DUPLICATES;
|
||||||
|
} else {
|
||||||
|
names.insert(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parameter.is_rest_param() {
|
||||||
|
flags |= FormalParameterListFlags::HAS_REST_PARAMETER;
|
||||||
|
}
|
||||||
|
if parameter.init().is_some() {
|
||||||
|
flags |= FormalParameterListFlags::HAS_EXPRESSIONS;
|
||||||
|
}
|
||||||
|
if parameter.is_rest_param() || parameter.init().is_some() || !parameter.is_identifier()
|
||||||
|
{
|
||||||
|
flags.remove(FormalParameterListFlags::IS_SIMPLE);
|
||||||
|
}
|
||||||
|
if !(flags.contains(FormalParameterListFlags::HAS_EXPRESSIONS)
|
||||||
|
|| parameter.is_rest_param()
|
||||||
|
|| parameter.init().is_some())
|
||||||
|
{
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
parameters: parameters.into(),
|
||||||
|
flags,
|
||||||
|
length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the length of the parameter list.
|
||||||
|
/// Note that this is not equal to the length of the parameters slice.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn length(&self) -> u32 {
|
||||||
|
self.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the parameter list flags.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn flags(&self) -> FormalParameterListFlags {
|
||||||
|
self.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if the parameter list is simple.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_simple(&self) -> bool {
|
||||||
|
self.flags.contains(FormalParameterListFlags::IS_SIMPLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if the parameter list has duplicate parameters.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_duplicates(&self) -> bool {
|
||||||
|
self.flags
|
||||||
|
.contains(FormalParameterListFlags::HAS_DUPLICATES)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if the parameter list has a rest parameter.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_rest_parameter(&self) -> bool {
|
||||||
|
self.flags
|
||||||
|
.contains(FormalParameterListFlags::HAS_REST_PARAMETER)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if the parameter list has expressions in it's parameters.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_expressions(&self) -> bool {
|
||||||
|
self.flags
|
||||||
|
.contains(FormalParameterListFlags::HAS_EXPRESSIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if the parameter list has parameters named 'arguments'.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_arguments(&self) -> bool {
|
||||||
|
self.flags.contains(FormalParameterListFlags::HAS_ARGUMENTS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<FormalParameter>> for FormalParameterList {
|
||||||
|
fn from(parameters: Vec<FormalParameter>) -> Self {
|
||||||
|
Self::from_parameters(parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FormalParameter> for FormalParameterList {
|
||||||
|
fn from(parameter: FormalParameter) -> Self {
|
||||||
|
Self::from_parameters(vec![parameter])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[FormalParameter]> for FormalParameterList {
|
||||||
|
fn as_ref(&self) -> &[FormalParameter] {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for FormalParameterList {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for parameter in self.parameters.iter() {
|
||||||
|
try_break!(visitor.visit_formal_parameter(parameter));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for parameter in self.parameters.iter_mut() {
|
||||||
|
try_break!(visitor.visit_formal_parameter_mut(parameter));
|
||||||
|
}
|
||||||
|
// TODO recompute flags
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fuzz")]
|
||||||
|
impl<'a> arbitrary::Arbitrary<'a> for FormalParameterList {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
let params: Vec<FormalParameter> = u.arbitrary()?;
|
||||||
|
Ok(Self::from(params))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Flags for a [`FormalParameterList`].
|
||||||
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct FormalParameterListFlags: u8 {
|
||||||
|
/// Has only identifier parameters with no initialization expressions.
|
||||||
|
const IS_SIMPLE = 0b0000_0001;
|
||||||
|
/// Has any duplicate parameters.
|
||||||
|
const HAS_DUPLICATES = 0b0000_0010;
|
||||||
|
/// Has a rest parameter.
|
||||||
|
const HAS_REST_PARAMETER = 0b0000_0100;
|
||||||
|
/// Has any initialization expression.
|
||||||
|
const HAS_EXPRESSIONS = 0b0000_1000;
|
||||||
|
/// Has an argument with the name `arguments`.
|
||||||
|
const HAS_ARGUMENTS = 0b0001_0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FormalParameterListFlags {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::empty().union(Self::IS_SIMPLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "Formal parameter" is a fancy way of saying "function parameter".
|
||||||
|
///
|
||||||
|
/// In the declaration of a function, the parameters must be identifiers,
|
||||||
|
/// not any value like numbers, strings, or objects.
|
||||||
|
/// ```text
|
||||||
|
/// function foo(formalParameter1, formalParameter2) {
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-FormalParameter
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Missing_formal_parameter
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct FormalParameter {
|
||||||
|
variable: Variable,
|
||||||
|
is_rest_param: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormalParameter {
|
||||||
|
/// Creates a new formal parameter.
|
||||||
|
pub fn new<D>(variable: D, is_rest_param: bool) -> Self
|
||||||
|
where
|
||||||
|
D: Into<Variable>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
variable: variable.into(),
|
||||||
|
is_rest_param,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the variable of the formal parameter
|
||||||
|
#[must_use]
|
||||||
|
pub const fn variable(&self) -> &Variable {
|
||||||
|
&self.variable
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initialization node of the formal parameter, if any.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn init(&self) -> Option<&Expression> {
|
||||||
|
self.variable.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the parameter is a rest parameter.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_rest_param(&self) -> bool {
|
||||||
|
self.is_rest_param
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the parameter is an identifier.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_identifier(&self) -> bool {
|
||||||
|
matches!(&self.variable.binding(), Binding::Identifier(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for FormalParameter {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = if self.is_rest_param {
|
||||||
|
"...".to_owned()
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
buf.push_str(&self.variable.to_interned_string(interner));
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for FormalParameter {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_variable(&self.variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_variable_mut(&mut self.variable)
|
||||||
|
}
|
||||||
|
}
|
||||||
625
javascript-engine/external/boa/boa_ast/src/keyword.rs
vendored
Normal file
625
javascript-engine/external/boa/boa_ast/src/keyword.rs
vendored
Normal file
@@ -0,0 +1,625 @@
|
|||||||
|
//! The `Keyword` AST node, which represents reserved words of the ECMAScript language.
|
||||||
|
//!
|
||||||
|
//! The [specification][spec] defines keywords as tokens that match an `IdentifierName`, but also
|
||||||
|
//! have special meaning in ECMAScript. In ECMAScript, you cannot use these reserved words as variables,
|
||||||
|
//! labels, or function names.
|
||||||
|
//!
|
||||||
|
//! The [MDN documentation][mdn] contains a more extensive explanation about keywords.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#sec-keywords-and-reserved-words
|
||||||
|
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
|
||||||
|
|
||||||
|
use crate::expression::operator::binary::{BinaryOp, RelationalOp};
|
||||||
|
use boa_interner::{Interner, Sym};
|
||||||
|
use boa_macros::utf16;
|
||||||
|
use std::{convert::TryFrom, error, fmt, str::FromStr};
|
||||||
|
|
||||||
|
/// List of keywords recognized by the JavaScript grammar.
|
||||||
|
///
|
||||||
|
/// See the [module-level documentation][self] for more details.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Keyword {
|
||||||
|
/// The `await` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
|
||||||
|
Await,
|
||||||
|
|
||||||
|
/// The `async` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
||||||
|
Async,
|
||||||
|
|
||||||
|
/// The `break` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [break `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BreakStatement
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Break
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break
|
||||||
|
Break,
|
||||||
|
|
||||||
|
/// The `case` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [switch `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-CaseClause
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Switch
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
|
||||||
|
Case,
|
||||||
|
|
||||||
|
/// The `catch` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [try `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-Catch
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Try
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
|
||||||
|
Catch,
|
||||||
|
|
||||||
|
/// The `class` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ClassDeclaration
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class
|
||||||
|
Class,
|
||||||
|
|
||||||
|
/// The `continue` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [continue `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Continue
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue
|
||||||
|
Continue,
|
||||||
|
|
||||||
|
/// The `const` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [const `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.ConstDecl
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
||||||
|
Const,
|
||||||
|
|
||||||
|
/// The `debugger` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-debugger-statement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
|
||||||
|
Debugger,
|
||||||
|
|
||||||
|
/// The `default` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [switch `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference default clause][spec-clause]
|
||||||
|
/// - [ECMAScript reference default export][spec-export]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Switch
|
||||||
|
/// [spec-clause]: https://tc39.es/ecma262/#prod-DefaultClause
|
||||||
|
/// [spec-export]: https://tc39.es/ecma262/#prod-ImportedDefaultBinding
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/default
|
||||||
|
Default,
|
||||||
|
|
||||||
|
/// The `delete` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [delete `UnaryOp` documentation][unary]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-delete-operator
|
||||||
|
/// [unary]: ../op/enum.UnaryOp.html#variant.Delete
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
|
||||||
|
Delete,
|
||||||
|
|
||||||
|
/// The `do` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-do-while-statement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
|
||||||
|
Do,
|
||||||
|
|
||||||
|
/// The `else` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [if `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.If
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-IfStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
|
||||||
|
Else,
|
||||||
|
|
||||||
|
/// The `enum` keyword.
|
||||||
|
///
|
||||||
|
/// Future reserved keyword.
|
||||||
|
Enum,
|
||||||
|
|
||||||
|
/// The `export` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-exports
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
|
||||||
|
Export,
|
||||||
|
|
||||||
|
/// The `extends` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ClassHeritage
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends
|
||||||
|
Extends,
|
||||||
|
|
||||||
|
/// The `false` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BooleanLiteral
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||||
|
False,
|
||||||
|
|
||||||
|
/// The `finally` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [try `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Try
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-Finally
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
|
||||||
|
Finally,
|
||||||
|
|
||||||
|
/// The `for` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [for loop `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.ForLoop
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForDeclaration
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
|
||||||
|
For,
|
||||||
|
|
||||||
|
/// The `function` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [function `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.FunctionDecl
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-function
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function
|
||||||
|
Function,
|
||||||
|
|
||||||
|
/// The `if` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [if `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.If
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-IfStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
|
||||||
|
If,
|
||||||
|
|
||||||
|
/// The `in` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
|
||||||
|
In,
|
||||||
|
|
||||||
|
/// The `instanceof` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-instanceofoperator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
|
||||||
|
InstanceOf,
|
||||||
|
|
||||||
|
/// The `import` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-imports
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
|
||||||
|
Import,
|
||||||
|
|
||||||
|
/// The `let` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [let `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.LetDecl
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
||||||
|
Let,
|
||||||
|
|
||||||
|
/// The `new` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [new `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.New
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-NewExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
|
||||||
|
New,
|
||||||
|
|
||||||
|
/// The `null` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-NullLiteral
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
|
||||||
|
Null,
|
||||||
|
|
||||||
|
/// The `of` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-for-in-and-for-of-statements
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
|
||||||
|
Of,
|
||||||
|
|
||||||
|
/// The `return` keyword
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [return `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Return
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
|
||||||
|
Return,
|
||||||
|
|
||||||
|
/// The `super` keyword
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-super-keyword
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
|
||||||
|
Super,
|
||||||
|
|
||||||
|
/// The `switch` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [switch `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Switch
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
|
||||||
|
Switch,
|
||||||
|
|
||||||
|
/// The `this` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [this `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.This
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-this-keyword
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
|
||||||
|
This,
|
||||||
|
|
||||||
|
/// The `throw` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [throw `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Throw
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-throw-statement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
|
||||||
|
Throw,
|
||||||
|
|
||||||
|
/// The `true` keyword
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BooleanLiteral
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||||
|
True,
|
||||||
|
|
||||||
|
/// The `try` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [try `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.Try
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-TryStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
|
||||||
|
Try,
|
||||||
|
|
||||||
|
/// The `typeof` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [typeof `UnaryOp` documentation][unary]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [unary]: ../op/enum.UnaryOp.html#variant.TypeOf
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-typeof-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
|
||||||
|
TypeOf,
|
||||||
|
|
||||||
|
/// The `var` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [var `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.VarDecl
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-VariableStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
|
||||||
|
Var,
|
||||||
|
|
||||||
|
/// The `void` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [void `UnaryOp` documentation][unary]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [unary]: ../op/enum.UnaryOp.html#variant.Void
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-void-operator
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
|
||||||
|
Void,
|
||||||
|
|
||||||
|
/// The `while` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [while `Node` documentation][node]
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [node]: ../node/enum.Node.html#variant.While
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while
|
||||||
|
While,
|
||||||
|
|
||||||
|
/// The `with` keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-WithStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
|
||||||
|
With,
|
||||||
|
|
||||||
|
/// The 'yield' keyword.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-YieldExpression
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
|
||||||
|
Yield,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keyword {
|
||||||
|
/// Gets the keyword as a binary operation, if this keyword is the `in` or the `instanceof`
|
||||||
|
/// keywords.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_binary_op(self) -> Option<BinaryOp> {
|
||||||
|
match self {
|
||||||
|
Self::In => Some(BinaryOp::Relational(RelationalOp::In)),
|
||||||
|
Self::InstanceOf => Some(BinaryOp::Relational(RelationalOp::InstanceOf)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the keyword as a tuple of strings.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_str(self) -> (&'static str, &'static [u16]) {
|
||||||
|
match self {
|
||||||
|
Self::Await => ("await", utf16!("await")),
|
||||||
|
Self::Async => ("async", utf16!("async")),
|
||||||
|
Self::Break => ("break", utf16!("break")),
|
||||||
|
Self::Case => ("case", utf16!("case")),
|
||||||
|
Self::Catch => ("catch", utf16!("catch")),
|
||||||
|
Self::Class => ("class", utf16!("class")),
|
||||||
|
Self::Continue => ("continue", utf16!("continue")),
|
||||||
|
Self::Const => ("const", utf16!("const")),
|
||||||
|
Self::Debugger => ("debugger", utf16!("debugger")),
|
||||||
|
Self::Default => ("default", utf16!("default")),
|
||||||
|
Self::Delete => ("delete", utf16!("delete")),
|
||||||
|
Self::Do => ("do", utf16!("do")),
|
||||||
|
Self::Else => ("else", utf16!("else")),
|
||||||
|
Self::Enum => ("enum", utf16!("enum")),
|
||||||
|
Self::Extends => ("extends", utf16!("extends")),
|
||||||
|
Self::Export => ("export", utf16!("export")),
|
||||||
|
Self::False => ("false", utf16!("false")),
|
||||||
|
Self::Finally => ("finally", utf16!("finally")),
|
||||||
|
Self::For => ("for", utf16!("for")),
|
||||||
|
Self::Function => ("function", utf16!("function")),
|
||||||
|
Self::If => ("if", utf16!("if")),
|
||||||
|
Self::In => ("in", utf16!("in")),
|
||||||
|
Self::InstanceOf => ("instanceof", utf16!("instanceof")),
|
||||||
|
Self::Import => ("import", utf16!("import")),
|
||||||
|
Self::Let => ("let", utf16!("let")),
|
||||||
|
Self::New => ("new", utf16!("new")),
|
||||||
|
Self::Null => ("null", utf16!("null")),
|
||||||
|
Self::Of => ("of", utf16!("of")),
|
||||||
|
Self::Return => ("return", utf16!("return")),
|
||||||
|
Self::Super => ("super", utf16!("super")),
|
||||||
|
Self::Switch => ("switch", utf16!("switch")),
|
||||||
|
Self::This => ("this", utf16!("this")),
|
||||||
|
Self::Throw => ("throw", utf16!("throw")),
|
||||||
|
Self::True => ("true", utf16!("true")),
|
||||||
|
Self::Try => ("try", utf16!("try")),
|
||||||
|
Self::TypeOf => ("typeof", utf16!("typeof")),
|
||||||
|
Self::Var => ("var", utf16!("var")),
|
||||||
|
Self::Void => ("void", utf16!("void")),
|
||||||
|
Self::While => ("while", utf16!("while")),
|
||||||
|
Self::With => ("with", utf16!("with")),
|
||||||
|
Self::Yield => ("yield", utf16!("yield")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: promote all keywords to statics inside Interner
|
||||||
|
/// Converts the keyword to a symbol in the given interner.
|
||||||
|
pub fn to_sym(self, interner: &mut Interner) -> Sym {
|
||||||
|
let (utf8, utf16) = self.as_str();
|
||||||
|
interner.get_or_intern_static(utf8, utf16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Should use a proper Error
|
||||||
|
impl TryFrom<Keyword> for BinaryOp {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: Keyword) -> Result<Self, Self::Error> {
|
||||||
|
value
|
||||||
|
.as_binary_op()
|
||||||
|
.ok_or_else(|| format!("No binary operation for {value}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The error type which is returned from parsing a [`str`] into a [`Keyword`].
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct KeywordError;
|
||||||
|
impl fmt::Display for KeywordError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "invalid token")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is important for other errors to wrap this one.
|
||||||
|
impl error::Error for KeywordError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"invalid token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromStr for Keyword {
|
||||||
|
type Err = KeywordError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"await" => Ok(Self::Await),
|
||||||
|
"async" => Ok(Self::Async),
|
||||||
|
"break" => Ok(Self::Break),
|
||||||
|
"case" => Ok(Self::Case),
|
||||||
|
"catch" => Ok(Self::Catch),
|
||||||
|
"class" => Ok(Self::Class),
|
||||||
|
"continue" => Ok(Self::Continue),
|
||||||
|
"const" => Ok(Self::Const),
|
||||||
|
"debugger" => Ok(Self::Debugger),
|
||||||
|
"default" => Ok(Self::Default),
|
||||||
|
"delete" => Ok(Self::Delete),
|
||||||
|
"do" => Ok(Self::Do),
|
||||||
|
"else" => Ok(Self::Else),
|
||||||
|
"enum" => Ok(Self::Enum),
|
||||||
|
"extends" => Ok(Self::Extends),
|
||||||
|
"export" => Ok(Self::Export),
|
||||||
|
"false" => Ok(Self::False),
|
||||||
|
"finally" => Ok(Self::Finally),
|
||||||
|
"for" => Ok(Self::For),
|
||||||
|
"function" => Ok(Self::Function),
|
||||||
|
"if" => Ok(Self::If),
|
||||||
|
"in" => Ok(Self::In),
|
||||||
|
"instanceof" => Ok(Self::InstanceOf),
|
||||||
|
"import" => Ok(Self::Import),
|
||||||
|
"let" => Ok(Self::Let),
|
||||||
|
"new" => Ok(Self::New),
|
||||||
|
"null" => Ok(Self::Null),
|
||||||
|
"of" => Ok(Self::Of),
|
||||||
|
"return" => Ok(Self::Return),
|
||||||
|
"super" => Ok(Self::Super),
|
||||||
|
"switch" => Ok(Self::Switch),
|
||||||
|
"this" => Ok(Self::This),
|
||||||
|
"throw" => Ok(Self::Throw),
|
||||||
|
"true" => Ok(Self::True),
|
||||||
|
"try" => Ok(Self::Try),
|
||||||
|
"typeof" => Ok(Self::TypeOf),
|
||||||
|
"var" => Ok(Self::Var),
|
||||||
|
"void" => Ok(Self::Void),
|
||||||
|
"while" => Ok(Self::While),
|
||||||
|
"with" => Ok(Self::With),
|
||||||
|
"yield" => Ok(Self::Yield),
|
||||||
|
_ => Err(KeywordError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Keyword {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(self.as_str().0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
174
javascript-engine/external/boa/boa_ast/src/lib.rs
vendored
Normal file
174
javascript-engine/external/boa/boa_ast/src/lib.rs
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
//! Boa's **`boa_ast`** crate implements an ECMAScript abstract syntax tree.
|
||||||
|
//!
|
||||||
|
//! # Crate Overview
|
||||||
|
//! **`boa_ast`** contains representations of [**Parse Nodes**][grammar] as defined by the ECMAScript
|
||||||
|
//! spec. Some `Parse Node`s are not represented by Boa's AST, because a lot of grammar productions
|
||||||
|
//! are only used to throw [**Early Errors**][early], and don't influence the evaluation of the AST
|
||||||
|
//! itself.
|
||||||
|
//!
|
||||||
|
//! Boa's AST is mainly split in three main components: [`Declaration`]s, [`Expression`]s and
|
||||||
|
//! [`Statement`]s, with [`StatementList`] being the primordial Parse Node that combines
|
||||||
|
//! all of them to create a proper AST.
|
||||||
|
//!
|
||||||
|
//! # About Boa
|
||||||
|
//! Boa is an open-source, experimental ECMAScript Engine written in Rust for lexing, parsing and executing ECMAScript/JavaScript. Currently, Boa
|
||||||
|
//! supports some of the [language][boa-conformance]. More information can be viewed at [Boa's website][boa-web].
|
||||||
|
//!
|
||||||
|
//! Try out the most recent release with Boa's live demo [playground][boa-playground].
|
||||||
|
//!
|
||||||
|
//! # Boa Crates
|
||||||
|
//! - **`boa_ast`** - Boa's ECMAScript Abstract Syntax Tree.
|
||||||
|
//! - **`boa_engine`** - Boa's implementation of ECMAScript builtin objects and execution.
|
||||||
|
//! - **`boa_gc`** - Boa's garbage collector.
|
||||||
|
//! - **`boa_interner`** - Boa's string interner.
|
||||||
|
//! - **`boa_parser`** - Boa's lexer and parser.
|
||||||
|
//! - **`boa_profiler`** - Boa's code profiler.
|
||||||
|
//! - **`boa_unicode`** - Boa's Unicode identifier.
|
||||||
|
//! - **`boa_icu_provider`** - Boa's ICU4X data provider.
|
||||||
|
//!
|
||||||
|
//! [grammar]: https://tc39.es/ecma262/#sec-syntactic-grammar
|
||||||
|
//! [early]: https://tc39.es/ecma262/#sec-static-semantic-rules
|
||||||
|
//! [boa-conformance]: https://boa-dev.github.io/boa/test262/
|
||||||
|
//! [boa-web]: https://boa-dev.github.io/
|
||||||
|
//! [boa-playground]: https://boa-dev.github.io/boa/playground/
|
||||||
|
|
||||||
|
#![doc(
|
||||||
|
html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg",
|
||||||
|
html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(not(test), forbid(clippy::unwrap_used))]
|
||||||
|
#![warn(missing_docs, clippy::dbg_macro)]
|
||||||
|
#![deny(
|
||||||
|
// rustc lint groups https://doc.rust-lang.org/rustc/lints/groups.html
|
||||||
|
warnings,
|
||||||
|
future_incompatible,
|
||||||
|
let_underscore,
|
||||||
|
nonstandard_style,
|
||||||
|
rust_2018_compatibility,
|
||||||
|
rust_2018_idioms,
|
||||||
|
rust_2021_compatibility,
|
||||||
|
unused,
|
||||||
|
|
||||||
|
// rustc allowed-by-default lints https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html
|
||||||
|
macro_use_extern_crate,
|
||||||
|
meta_variable_misuse,
|
||||||
|
missing_abi,
|
||||||
|
missing_copy_implementations,
|
||||||
|
missing_debug_implementations,
|
||||||
|
non_ascii_idents,
|
||||||
|
noop_method_call,
|
||||||
|
single_use_lifetimes,
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unreachable_pub,
|
||||||
|
unsafe_op_in_unsafe_fn,
|
||||||
|
unused_crate_dependencies,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_lifetimes,
|
||||||
|
unused_qualifications,
|
||||||
|
unused_tuple_struct_fields,
|
||||||
|
variant_size_differences,
|
||||||
|
|
||||||
|
// rustdoc lints https://doc.rust-lang.org/rustdoc/lints.html
|
||||||
|
rustdoc::broken_intra_doc_links,
|
||||||
|
rustdoc::private_intra_doc_links,
|
||||||
|
rustdoc::missing_crate_level_docs,
|
||||||
|
rustdoc::private_doc_tests,
|
||||||
|
rustdoc::invalid_codeblock_attributes,
|
||||||
|
rustdoc::invalid_rust_codeblocks,
|
||||||
|
rustdoc::bare_urls,
|
||||||
|
|
||||||
|
// clippy categories https://doc.rust-lang.org/clippy/
|
||||||
|
clippy::all,
|
||||||
|
clippy::correctness,
|
||||||
|
clippy::suspicious,
|
||||||
|
clippy::style,
|
||||||
|
clippy::complexity,
|
||||||
|
clippy::perf,
|
||||||
|
clippy::pedantic,
|
||||||
|
clippy::nursery,
|
||||||
|
)]
|
||||||
|
#![allow(
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::too_many_lines,
|
||||||
|
clippy::option_if_let_else,
|
||||||
|
clippy::use_self
|
||||||
|
)]
|
||||||
|
|
||||||
|
mod position;
|
||||||
|
mod punctuator;
|
||||||
|
mod statement_list;
|
||||||
|
|
||||||
|
pub mod declaration;
|
||||||
|
pub mod expression;
|
||||||
|
pub mod function;
|
||||||
|
pub mod keyword;
|
||||||
|
pub mod operations;
|
||||||
|
pub mod pattern;
|
||||||
|
pub mod property;
|
||||||
|
pub mod statement;
|
||||||
|
pub mod visitor;
|
||||||
|
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
declaration::Declaration,
|
||||||
|
expression::Expression,
|
||||||
|
keyword::Keyword,
|
||||||
|
position::{Position, Span},
|
||||||
|
punctuator::Punctuator,
|
||||||
|
statement::Statement,
|
||||||
|
statement_list::{StatementList, StatementListItem},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Utility to join multiple Nodes into a single string.
|
||||||
|
fn join_nodes<N>(interner: &Interner, nodes: &[N]) -> String
|
||||||
|
where
|
||||||
|
N: ToInternedString,
|
||||||
|
{
|
||||||
|
let mut first = true;
|
||||||
|
let mut buf = String::new();
|
||||||
|
for e in nodes {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
buf.push_str(", ");
|
||||||
|
}
|
||||||
|
buf.push_str(&e.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Displays the body of a block or statement list.
|
||||||
|
///
|
||||||
|
/// This includes the curly braces at the start and end. This will not indent the first brace,
|
||||||
|
/// but will indent the last brace.
|
||||||
|
fn block_to_string(body: &StatementList, interner: &Interner, indentation: usize) -> String {
|
||||||
|
if body.statements().is_empty() {
|
||||||
|
"{}".to_owned()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{{\n{}{}}}",
|
||||||
|
body.to_indented_string(interner, indentation + 1),
|
||||||
|
" ".repeat(indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility trait that adds a `UTF-16` escaped representation to every [`[u16]`][slice].
|
||||||
|
trait ToStringEscaped {
|
||||||
|
/// Decodes `self` as an `UTF-16` encoded string, escaping any unpaired surrogates by its
|
||||||
|
/// codepoint value.
|
||||||
|
fn to_string_escaped(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToStringEscaped for [u16] {
|
||||||
|
fn to_string_escaped(&self) -> String {
|
||||||
|
char::decode_utf16(self.iter().copied())
|
||||||
|
.map(|r| match r {
|
||||||
|
Ok(c) => String::from(c),
|
||||||
|
Err(e) => format!("\\u{:04X}", e.unpaired_surrogate()),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
769
javascript-engine/external/boa/boa_ast/src/operations.rs
vendored
Normal file
769
javascript-engine/external/boa/boa_ast/src/operations.rs
vendored
Normal file
@@ -0,0 +1,769 @@
|
|||||||
|
//! Definitions of various **Syntax-Directed Operations** used in the [spec].
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#sec-syntax-directed-operations
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
use std::convert::Infallible;
|
||||||
|
|
||||||
|
use boa_interner::Sym;
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
declaration::VarDeclaration,
|
||||||
|
expression::{access::SuperPropertyAccess, Await, Identifier, SuperCall, Yield},
|
||||||
|
function::{
|
||||||
|
ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement,
|
||||||
|
Function, Generator, PrivateName,
|
||||||
|
},
|
||||||
|
property::{MethodDefinition, PropertyDefinition},
|
||||||
|
statement::LabelledItem,
|
||||||
|
try_break,
|
||||||
|
visitor::{NodeRef, VisitWith, Visitor, VisitorMut},
|
||||||
|
Declaration, Expression, Statement, StatementList, StatementListItem,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents all the possible symbols searched for by the [`Contains`][contains] operation.
|
||||||
|
///
|
||||||
|
/// [contains]: https://tc39.es/ecma262/#sec-syntax-directed-operations-contains
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum ContainsSymbol {
|
||||||
|
/// A node with the `super` keyword (`super(args)` or `super.prop`).
|
||||||
|
Super,
|
||||||
|
/// A super property access (`super.prop`).
|
||||||
|
SuperProperty,
|
||||||
|
/// A super constructor call (`super(args)`).
|
||||||
|
SuperCall,
|
||||||
|
/// A yield expression (`yield 5`).
|
||||||
|
YieldExpression,
|
||||||
|
/// An await expression (`await 4`).
|
||||||
|
AwaitExpression,
|
||||||
|
/// The new target expression (`new.target`).
|
||||||
|
NewTarget,
|
||||||
|
/// The body of a class definition.
|
||||||
|
ClassBody,
|
||||||
|
/// The super class of a class definition.
|
||||||
|
ClassHeritage,
|
||||||
|
/// A this expression (`this`).
|
||||||
|
This,
|
||||||
|
/// A method definition.
|
||||||
|
MethodDefinition,
|
||||||
|
/// The BindingIdentifier "eval" or "arguments".
|
||||||
|
EvalOrArguments,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the node contains the given symbol.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`Contains`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-contains
|
||||||
|
#[must_use]
|
||||||
|
pub fn contains<N>(node: &N, symbol: ContainsSymbol) -> bool
|
||||||
|
where
|
||||||
|
N: VisitWith,
|
||||||
|
{
|
||||||
|
/// Visitor used by the function to search for a specific symbol in a node.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct ContainsVisitor(ContainsSymbol);
|
||||||
|
|
||||||
|
impl<'ast> Visitor<'ast> for ContainsVisitor {
|
||||||
|
type BreakTy = ();
|
||||||
|
|
||||||
|
fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if self.0 == ContainsSymbol::EvalOrArguments
|
||||||
|
&& (node.sym() == Sym::EVAL || node.sym() == Sym::ARGUMENTS)
|
||||||
|
{
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_function(&mut self, _: &'ast Function) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_function(&mut self, _: &'ast AsyncFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generator(&mut self, _: &'ast Generator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_generator(&mut self, _: &'ast AsyncGenerator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_class(&mut self, node: &'ast Class) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
// `ComputedPropertyContains`: https://tc39.es/ecma262/#sec-static-semantics-computedpropertycontains
|
||||||
|
fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match node {
|
||||||
|
ClassElement::MethodDefinition(name, _)
|
||||||
|
| ClassElement::StaticMethodDefinition(name, _)
|
||||||
|
| ClassElement::FieldDefinition(name, _)
|
||||||
|
| ClassElement::StaticFieldDefinition(name, _) => name.visit_with(self),
|
||||||
|
_ => ControlFlow::Continue(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_property_definition(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast PropertyDefinition,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let PropertyDefinition::MethodDefinition(name, _) = node {
|
||||||
|
if self.0 == ContainsSymbol::MethodDefinition {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
return name.visit_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_arrow_function(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast ArrowFunction,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if ![
|
||||||
|
ContainsSymbol::NewTarget,
|
||||||
|
ContainsSymbol::SuperProperty,
|
||||||
|
ContainsSymbol::SuperCall,
|
||||||
|
ContainsSymbol::Super,
|
||||||
|
ContainsSymbol::This,
|
||||||
|
]
|
||||||
|
.contains(&self.0)
|
||||||
|
{
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_arrow_function(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast AsyncArrowFunction,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if ![
|
||||||
|
ContainsSymbol::NewTarget,
|
||||||
|
ContainsSymbol::SuperProperty,
|
||||||
|
ContainsSymbol::SuperCall,
|
||||||
|
ContainsSymbol::Super,
|
||||||
|
ContainsSymbol::This,
|
||||||
|
]
|
||||||
|
.contains(&self.0)
|
||||||
|
{
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_super_property_access(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast SuperPropertyAccess,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if [ContainsSymbol::SuperProperty, ContainsSymbol::Super].contains(&self.0) {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_super_call(&mut self, node: &'ast SuperCall) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if [ContainsSymbol::SuperCall, ContainsSymbol::Super].contains(&self.0) {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_yield(&mut self, node: &'ast Yield) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if self.0 == ContainsSymbol::YieldExpression {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_await(&mut self, node: &'ast Await) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if self.0 == ContainsSymbol::AwaitExpression {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, node: &'ast Expression) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if node == &Expression::This && self.0 == ContainsSymbol::This {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
if node == &Expression::NewTarget && self.0 == ContainsSymbol::NewTarget {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.visit_with(&mut ContainsVisitor(symbol)).is_break()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the node contains an identifier reference with name `arguments`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`ContainsArguments`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-containsarguments
|
||||||
|
#[must_use]
|
||||||
|
pub fn contains_arguments<N>(node: &N) -> bool
|
||||||
|
where
|
||||||
|
N: VisitWith,
|
||||||
|
{
|
||||||
|
/// Visitor used by the function to search for an identifier with the name `arguments`.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct ContainsArgsVisitor;
|
||||||
|
|
||||||
|
impl<'ast> Visitor<'ast> for ContainsArgsVisitor {
|
||||||
|
type BreakTy = ();
|
||||||
|
|
||||||
|
fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if node.sym() == Sym::ARGUMENTS {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_function(&mut self, _: &'ast Function) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_function(&mut self, _: &'ast AsyncFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generator(&mut self, _: &'ast Generator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_generator(&mut self, _: &'ast AsyncGenerator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match node {
|
||||||
|
ClassElement::MethodDefinition(name, _)
|
||||||
|
| ClassElement::StaticMethodDefinition(name, _) => return name.visit_with(self),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_property_definition(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast PropertyDefinition,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let PropertyDefinition::MethodDefinition(name, _) = node {
|
||||||
|
name.visit_with(self)
|
||||||
|
} else {
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.visit_with(&mut ContainsArgsVisitor).is_break()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `method` has a super call in its parameters or body.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`HasDirectSuper`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-hasdirectsuper
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn has_direct_super(method: &MethodDefinition) -> bool {
|
||||||
|
match method {
|
||||||
|
MethodDefinition::Get(f) | MethodDefinition::Set(f) | MethodDefinition::Ordinary(f) => {
|
||||||
|
contains(f, ContainsSymbol::SuperCall)
|
||||||
|
}
|
||||||
|
MethodDefinition::Generator(f) => contains(f, ContainsSymbol::SuperCall),
|
||||||
|
MethodDefinition::AsyncGenerator(f) => contains(f, ContainsSymbol::SuperCall),
|
||||||
|
MethodDefinition::Async(f) => contains(f, ContainsSymbol::SuperCall),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A container that [`BoundNamesVisitor`] can use to push the found identifiers.
|
||||||
|
trait IdentList {
|
||||||
|
fn add(&mut self, value: Identifier, function: bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentList for Vec<Identifier> {
|
||||||
|
fn add(&mut self, value: Identifier, _function: bool) {
|
||||||
|
self.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentList for Vec<(Identifier, bool)> {
|
||||||
|
fn add(&mut self, value: Identifier, function: bool) {
|
||||||
|
self.push((value, function));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentList for FxHashSet<Identifier> {
|
||||||
|
fn add(&mut self, value: Identifier, _function: bool) {
|
||||||
|
self.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`Visitor`] used to obtain the bound names of a node.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BoundNamesVisitor<'a, T: IdentList>(&'a mut T);
|
||||||
|
|
||||||
|
impl<'ast, T: IdentList> Visitor<'ast> for BoundNamesVisitor<'_, T> {
|
||||||
|
type BreakTy = Infallible;
|
||||||
|
|
||||||
|
fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
|
||||||
|
self.0.add(*node, false);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add "*default" for module default functions without name
|
||||||
|
fn visit_function(&mut self, node: &'ast Function) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Some(ident) = node.name() {
|
||||||
|
self.0.add(ident, true);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Some(ident) = node.name() {
|
||||||
|
self.0.add(ident, false);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Some(ident) = node.name() {
|
||||||
|
self.0.add(ident, false);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Some(ident) = node.name() {
|
||||||
|
self.0.add(ident, false);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_class(&mut self, node: &'ast Class) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Some(ident) = node.name() {
|
||||||
|
self.0.add(ident, false);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list with the bound names of an AST node, which may contain duplicates.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`BoundNames`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-boundnames
|
||||||
|
#[must_use]
|
||||||
|
pub fn bound_names<'a, N>(node: &'a N) -> Vec<Identifier>
|
||||||
|
where
|
||||||
|
&'a N: Into<NodeRef<'a>>,
|
||||||
|
{
|
||||||
|
let mut names = Vec::new();
|
||||||
|
BoundNamesVisitor(&mut names).visit(node.into());
|
||||||
|
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`Visitor`] used to obtain the lexically declared names of a node.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct LexicallyDeclaredNamesVisitor<'a, T: IdentList>(&'a mut T);
|
||||||
|
|
||||||
|
impl<'ast, T: IdentList> Visitor<'ast> for LexicallyDeclaredNamesVisitor<'_, T> {
|
||||||
|
type BreakTy = Infallible;
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let Statement::Labelled(labelled) = node {
|
||||||
|
return self.visit_labelled(labelled);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_declaration(&mut self, node: &'ast Declaration) -> ControlFlow<Self::BreakTy> {
|
||||||
|
BoundNamesVisitor(self.0).visit_declaration(node)
|
||||||
|
}
|
||||||
|
fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match node {
|
||||||
|
LabelledItem::Function(f) => BoundNamesVisitor(self.0).visit_function(f),
|
||||||
|
LabelledItem::Statement(_) => ControlFlow::Continue(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_function(&mut self, node: &'ast Function) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_arrow_function(&mut self, node: &'ast ArrowFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_async_arrow_function(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast AsyncArrowFunction,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_lexicals(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ClassElement::StaticBlock(stmts) = node {
|
||||||
|
top_level_lexicals(stmts, self.0);
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ScriptBody : StatementList
|
||||||
|
// 1. Return TopLevelLexicallyDeclaredNames of StatementList.
|
||||||
|
// But we don't have that node yet. In the meantime, use `top_level_lexically_declared_names` directly.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list with the lexical bindings of a node, which may contain duplicates.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`LexicallyDeclaredNames`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
|
||||||
|
#[must_use]
|
||||||
|
pub fn lexically_declared_names<'a, N>(node: &'a N) -> Vec<Identifier>
|
||||||
|
where
|
||||||
|
&'a N: Into<NodeRef<'a>>,
|
||||||
|
{
|
||||||
|
let mut names = Vec::new();
|
||||||
|
LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list with the lexical bindings of a node, which may contain duplicates.
|
||||||
|
///
|
||||||
|
/// If a declared name originates from a function declaration it is flagged as `true` in the returned
|
||||||
|
/// list. (See [B.3.2.4 Changes to Block Static Semantics: Early Errors])
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
|
||||||
|
/// [changes]: https://tc39.es/ecma262/#sec-block-duplicates-allowed-static-semantics
|
||||||
|
#[must_use]
|
||||||
|
pub fn lexically_declared_names_legacy<'a, N>(node: &'a N) -> Vec<(Identifier, bool)>
|
||||||
|
where
|
||||||
|
&'a N: Into<NodeRef<'a>>,
|
||||||
|
{
|
||||||
|
let mut names = Vec::new();
|
||||||
|
LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`Visitor`] used to obtain the var declared names of a node.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct VarDeclaredNamesVisitor<'a>(&'a mut FxHashSet<Identifier>);
|
||||||
|
|
||||||
|
impl<'ast> Visitor<'ast> for VarDeclaredNamesVisitor<'_> {
|
||||||
|
type BreakTy = Infallible;
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_declaration(&mut self, _: &'ast Declaration) -> ControlFlow<Self::BreakTy> {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_var_declaration(&mut self, node: &'ast VarDeclaration) -> ControlFlow<Self::BreakTy> {
|
||||||
|
BoundNamesVisitor(self.0).visit_var_declaration(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match node {
|
||||||
|
LabelledItem::Function(_) => ControlFlow::Continue(()),
|
||||||
|
LabelledItem::Statement(stmt) => stmt.visit_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_function(&mut self, node: &'ast Function) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_arrow_function(&mut self, node: &'ast ArrowFunction) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_async_arrow_function(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast AsyncArrowFunction,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
top_level_vars(node.body(), self.0);
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ClassElement::StaticBlock(stmts) = node {
|
||||||
|
top_level_vars(stmts, self.0);
|
||||||
|
}
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ScriptBody : StatementList
|
||||||
|
// 1. Return TopLevelVarDeclaredNames of StatementList.
|
||||||
|
// But we don't have that node yet. In the meantime, use `top_level_var_declared_names` directly.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a set with the var bindings of a node, with no duplicates.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`VarDeclaredNames`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-vardeclarednames
|
||||||
|
#[must_use]
|
||||||
|
pub fn var_declared_names<'a, N>(node: &'a N) -> FxHashSet<Identifier>
|
||||||
|
where
|
||||||
|
&'a N: Into<NodeRef<'a>>,
|
||||||
|
{
|
||||||
|
let mut names = FxHashSet::default();
|
||||||
|
VarDeclaredNamesVisitor(&mut names).visit(node.into());
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function that collects the top level lexicals of a statement list into `names`.
|
||||||
|
fn top_level_lexicals<T: IdentList>(stmts: &StatementList, names: &mut T) {
|
||||||
|
for stmt in stmts.statements() {
|
||||||
|
if let StatementListItem::Declaration(decl) = stmt {
|
||||||
|
match decl {
|
||||||
|
// Note
|
||||||
|
// At the top level of a function, or script, function declarations are treated like
|
||||||
|
// var declarations rather than like lexical declarations.
|
||||||
|
Declaration::Function(_)
|
||||||
|
| Declaration::Generator(_)
|
||||||
|
| Declaration::AsyncFunction(_)
|
||||||
|
| Declaration::AsyncGenerator(_) => {}
|
||||||
|
Declaration::Class(class) => {
|
||||||
|
BoundNamesVisitor(names).visit_class(class);
|
||||||
|
}
|
||||||
|
Declaration::Lexical(decl) => {
|
||||||
|
BoundNamesVisitor(names).visit_lexical_declaration(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list with the lexical bindings of a top-level statement list, which may contain duplicates.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`TopLevelLexicallyDeclaredNames`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallydeclarednames
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn top_level_lexically_declared_names(stmts: &StatementList) -> Vec<Identifier> {
|
||||||
|
let mut names = Vec::new();
|
||||||
|
top_level_lexicals(stmts, &mut names);
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function that collects the top level vars of a statement list into `names`.
|
||||||
|
fn top_level_vars(stmts: &StatementList, names: &mut FxHashSet<Identifier>) {
|
||||||
|
for stmt in stmts.statements() {
|
||||||
|
match stmt {
|
||||||
|
StatementListItem::Declaration(decl) => {
|
||||||
|
match decl {
|
||||||
|
// Note
|
||||||
|
// At the top level of a function, or script, function declarations are treated like
|
||||||
|
// var declarations rather than like lexical declarations.
|
||||||
|
Declaration::Function(f) => {
|
||||||
|
BoundNamesVisitor(names).visit_function(f);
|
||||||
|
}
|
||||||
|
Declaration::Generator(f) => {
|
||||||
|
BoundNamesVisitor(names).visit_generator(f);
|
||||||
|
}
|
||||||
|
Declaration::AsyncFunction(f) => {
|
||||||
|
BoundNamesVisitor(names).visit_async_function(f);
|
||||||
|
}
|
||||||
|
Declaration::AsyncGenerator(f) => {
|
||||||
|
BoundNamesVisitor(names).visit_async_generator(f);
|
||||||
|
}
|
||||||
|
Declaration::Class(_) | Declaration::Lexical(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StatementListItem::Statement(stmt) => {
|
||||||
|
let mut stmt = Some(stmt);
|
||||||
|
while let Some(Statement::Labelled(labelled)) = stmt {
|
||||||
|
match labelled.item() {
|
||||||
|
LabelledItem::Function(f) => {
|
||||||
|
BoundNamesVisitor(names).visit_function(f);
|
||||||
|
stmt = None;
|
||||||
|
}
|
||||||
|
LabelledItem::Statement(s) => stmt = Some(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(stmt) = stmt {
|
||||||
|
VarDeclaredNamesVisitor(names).visit(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list with the var bindings of a top-level statement list, with no duplicates.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the [`TopLevelVarDeclaredNames`][spec] syntax operation in the spec.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevelvardeclarednames
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn top_level_var_declared_names(stmts: &StatementList) -> FxHashSet<Identifier> {
|
||||||
|
let mut names = FxHashSet::default();
|
||||||
|
top_level_vars(stmts, &mut names);
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the private names of a class and all of the contained classes and private identifiers.
|
||||||
|
pub fn class_private_name_resolver(node: &mut Class, top_level_class_index: usize) -> bool {
|
||||||
|
/// Visitor used by the function to search for an identifier with the name `arguments`.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct ClassPrivateNameResolver {
|
||||||
|
private_environments_stack: Vec<FxHashMap<Sym, PrivateName>>,
|
||||||
|
top_level_class_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> VisitorMut<'ast> for ClassPrivateNameResolver {
|
||||||
|
type BreakTy = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_class_mut(&mut self, node: &'ast mut Class) -> ControlFlow<Self::BreakTy> {
|
||||||
|
let mut names = FxHashMap::default();
|
||||||
|
|
||||||
|
for element in node.elements.iter_mut() {
|
||||||
|
match element {
|
||||||
|
ClassElement::PrivateMethodDefinition(name, _)
|
||||||
|
| ClassElement::PrivateStaticMethodDefinition(name, _)
|
||||||
|
| ClassElement::PrivateFieldDefinition(name, _)
|
||||||
|
| ClassElement::PrivateStaticFieldDefinition(name, _) => {
|
||||||
|
name.indices = (
|
||||||
|
self.top_level_class_index,
|
||||||
|
self.private_environments_stack.len(),
|
||||||
|
);
|
||||||
|
names.insert(name.description(), *name);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.private_environments_stack.push(names);
|
||||||
|
|
||||||
|
for element in node.elements.iter_mut() {
|
||||||
|
match element {
|
||||||
|
ClassElement::MethodDefinition(name, method)
|
||||||
|
| ClassElement::StaticMethodDefinition(name, method) => {
|
||||||
|
try_break!(self.visit_property_name_mut(name));
|
||||||
|
try_break!(self.visit_method_definition_mut(method));
|
||||||
|
}
|
||||||
|
ClassElement::PrivateMethodDefinition(_, method)
|
||||||
|
| ClassElement::PrivateStaticMethodDefinition(_, method) => {
|
||||||
|
try_break!(self.visit_method_definition_mut(method));
|
||||||
|
}
|
||||||
|
ClassElement::FieldDefinition(name, expression)
|
||||||
|
| ClassElement::StaticFieldDefinition(name, expression) => {
|
||||||
|
try_break!(self.visit_property_name_mut(name));
|
||||||
|
if let Some(expression) = expression {
|
||||||
|
try_break!(self.visit_expression_mut(expression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassElement::PrivateFieldDefinition(_, expression)
|
||||||
|
| ClassElement::PrivateStaticFieldDefinition(_, expression) => {
|
||||||
|
if let Some(expression) = expression {
|
||||||
|
try_break!(self.visit_expression_mut(expression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassElement::StaticBlock(statement_list) => {
|
||||||
|
try_break!(self.visit_statement_list_mut(statement_list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(function) = &mut node.constructor {
|
||||||
|
try_break!(self.visit_function_mut(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.private_environments_stack.pop();
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_private_name_mut(
|
||||||
|
&mut self,
|
||||||
|
node: &'ast mut PrivateName,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
for environment in self.private_environments_stack.iter().rev() {
|
||||||
|
if let Some(n) = environment.get(&node.description()) {
|
||||||
|
found = true;
|
||||||
|
node.indices = n.indices;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visitor = ClassPrivateNameResolver {
|
||||||
|
private_environments_stack: Vec::new(),
|
||||||
|
top_level_class_index,
|
||||||
|
};
|
||||||
|
|
||||||
|
visitor.visit_class_mut(node).is_continue()
|
||||||
|
}
|
||||||
787
javascript-engine/external/boa/boa_ast/src/pattern.rs
vendored
Normal file
787
javascript-engine/external/boa/boa_ast/src/pattern.rs
vendored
Normal file
@@ -0,0 +1,787 @@
|
|||||||
|
//! A pattern binding or assignment node.
|
||||||
|
//!
|
||||||
|
//! A [`Pattern`] Corresponds to the [`BindingPattern`][spec1] and the [`AssignmentPattern`][spec2]
|
||||||
|
//! nodes, each of which is used in different situations and have slightly different grammars.
|
||||||
|
//! For example, a variable declaration combined with a destructuring expression is a `BindingPattern`:
|
||||||
|
//!
|
||||||
|
//! ```Javascript
|
||||||
|
//! const obj = { a: 1, b: 2 };
|
||||||
|
//! const { a, b } = obj; // BindingPattern
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! On the other hand, a simple destructuring expression with already declared variables is called
|
||||||
|
//! an `AssignmentPattern`:
|
||||||
|
//!
|
||||||
|
//! ```Javascript
|
||||||
|
//! let a = 1;
|
||||||
|
//! let b = 3;
|
||||||
|
//! [a, b] = [b, a]; // AssignmentPattern
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [spec1]: https://tc39.es/ecma262/#prod-BindingPattern
|
||||||
|
//! [spec2]: https://tc39.es/ecma262/#prod-AssignmentPattern
|
||||||
|
//! [destr]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expression::{access::PropertyAccess, Identifier},
|
||||||
|
property::PropertyName,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
Expression,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// An object or array pattern binding or assignment.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Pattern {
|
||||||
|
/// An object pattern (`let {a, b, c} = object`).
|
||||||
|
Object(ObjectPattern),
|
||||||
|
/// An array pattern (`[a, b, c] = array`).
|
||||||
|
Array(ArrayPattern),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ObjectPattern> for Pattern {
|
||||||
|
fn from(obj: ObjectPattern) -> Self {
|
||||||
|
Self::Object(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArrayPattern> for Pattern {
|
||||||
|
fn from(obj: ArrayPattern) -> Self {
|
||||||
|
Self::Array(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<ObjectPatternElement>> for Pattern {
|
||||||
|
fn from(elements: Vec<ObjectPatternElement>) -> Self {
|
||||||
|
ObjectPattern::new(elements.into()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Vec<ArrayPatternElement>> for Pattern {
|
||||||
|
fn from(elements: Vec<ArrayPatternElement>) -> Self {
|
||||||
|
ArrayPattern::new(elements.into()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Pattern {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match &self {
|
||||||
|
Self::Object(o) => o.to_interned_string(interner),
|
||||||
|
Self::Array(a) => a.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Pattern {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Object(op) => visitor.visit_object_pattern(op),
|
||||||
|
Self::Array(ap) => visitor.visit_array_pattern(ap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Object(op) => visitor.visit_object_pattern_mut(op),
|
||||||
|
Self::Array(ap) => visitor.visit_array_pattern_mut(ap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An object binding or assignment pattern.
|
||||||
|
///
|
||||||
|
/// Corresponds to the [`ObjectBindingPattern`][spec1] and the [`ObjectAssignmentPattern`][spec2]
|
||||||
|
/// Parse Nodes.
|
||||||
|
///
|
||||||
|
/// For more information on what is a valid binding in an object pattern, see [`ObjectPatternElement`].
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-ObjectBindingPattern
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-ObjectAssignmentPattern
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ObjectPattern(Box<[ObjectPatternElement]>);
|
||||||
|
|
||||||
|
impl From<Vec<ObjectPatternElement>> for ObjectPattern {
|
||||||
|
fn from(elements: Vec<ObjectPatternElement>) -> Self {
|
||||||
|
Self(elements.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ObjectPattern {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = "{".to_owned();
|
||||||
|
for (i, binding) in self.0.iter().enumerate() {
|
||||||
|
let binding = binding.to_interned_string(interner);
|
||||||
|
let str = if i == self.0.len() - 1 {
|
||||||
|
format!("{binding} ")
|
||||||
|
} else {
|
||||||
|
format!("{binding},")
|
||||||
|
};
|
||||||
|
|
||||||
|
buf.push_str(&str);
|
||||||
|
}
|
||||||
|
if self.0.is_empty() {
|
||||||
|
buf.push(' ');
|
||||||
|
}
|
||||||
|
buf.push('}');
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectPattern {
|
||||||
|
/// Creates a new object binding pattern.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(bindings: Box<[ObjectPatternElement]>) -> Self {
|
||||||
|
Self(bindings)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the bindings for the object binding pattern.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn bindings(&self) -> &[ObjectPatternElement] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the object binding pattern has a rest element.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn has_rest(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.0.last(),
|
||||||
|
Some(ObjectPatternElement::RestProperty { .. })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ObjectPattern {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for elem in self.0.iter() {
|
||||||
|
try_break!(visitor.visit_object_pattern_element(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for elem in self.0.iter_mut() {
|
||||||
|
try_break!(visitor.visit_object_pattern_element_mut(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An array binding or assignment pattern.
|
||||||
|
///
|
||||||
|
/// Corresponds to the [`ArrayBindingPattern`][spec1] and the [`ArrayAssignmentPattern`][spec2]
|
||||||
|
/// Parse Nodes.
|
||||||
|
///
|
||||||
|
/// For more information on what is a valid binding in an array pattern, see [`ArrayPatternElement`].
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-ArrayBindingPattern
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-ArrayAssignmentPattern
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ArrayPattern(Box<[ArrayPatternElement]>);
|
||||||
|
|
||||||
|
impl From<Vec<ArrayPatternElement>> for ArrayPattern {
|
||||||
|
fn from(elements: Vec<ArrayPatternElement>) -> Self {
|
||||||
|
Self(elements.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ArrayPattern {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let mut buf = "[".to_owned();
|
||||||
|
for (i, binding) in self.0.iter().enumerate() {
|
||||||
|
if i == self.0.len() - 1 {
|
||||||
|
match binding {
|
||||||
|
ArrayPatternElement::Elision => {
|
||||||
|
buf.push_str(&format!("{}, ", binding.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
_ => buf.push_str(&format!("{} ", binding.to_interned_string(interner))),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.push_str(&format!("{},", binding.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.push(']');
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayPattern {
|
||||||
|
/// Creates a new array binding pattern.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(bindings: Box<[ArrayPatternElement]>) -> Self {
|
||||||
|
Self(bindings)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the bindings for the array binding pattern.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn bindings(&self) -> &[ArrayPatternElement] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ArrayPattern {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for elem in self.0.iter() {
|
||||||
|
try_break!(visitor.visit_array_pattern_element(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for elem in self.0.iter_mut() {
|
||||||
|
try_break!(visitor.visit_array_pattern_element_mut(elem));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The different types of bindings that an [`ObjectPattern`] may contain.
|
||||||
|
///
|
||||||
|
/// Corresponds to the [`BindingProperty`][spec1] and the [`AssignmentProperty`][spec2] nodes.
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingProperty
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-AssignmentProperty
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ObjectPatternElement {
|
||||||
|
/// SingleName represents one of the following properties:
|
||||||
|
///
|
||||||
|
/// - `SingleName` with an identifier and an optional default initializer.
|
||||||
|
/// - `BindingProperty` with an property name and a `SingleNameBinding` as the `BindingElement`.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - SingleNameBinding][spec1]
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingProperty][spec2]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-SingleNameBinding
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-BindingProperty
|
||||||
|
SingleName {
|
||||||
|
/// The identifier name of the property to be destructured.
|
||||||
|
name: PropertyName,
|
||||||
|
/// The variable name where the property value will be stored.
|
||||||
|
ident: Identifier,
|
||||||
|
/// An optional default value for the variable, in case the property doesn't exist.
|
||||||
|
default_init: Option<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// RestProperty represents a `BindingRestProperty` with an identifier.
|
||||||
|
///
|
||||||
|
/// It also includes a list of the property keys that should be excluded from the rest,
|
||||||
|
/// because they where already assigned.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingRestProperty][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingRestProperty
|
||||||
|
RestProperty {
|
||||||
|
/// The variable name where the unassigned properties will be stored.
|
||||||
|
ident: Identifier,
|
||||||
|
/// A list of the excluded property keys that were already destructured.
|
||||||
|
excluded_keys: Vec<Identifier>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// AssignmentGetField represents an AssignmentProperty with an expression field member expression AssignmentElement.
|
||||||
|
///
|
||||||
|
/// Note: According to the spec this is not part of an ObjectBindingPattern.
|
||||||
|
/// This is only used when a object literal is used to cover an AssignmentPattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentProperty
|
||||||
|
AssignmentPropertyAccess {
|
||||||
|
/// The identifier name of the property to be destructured.
|
||||||
|
name: PropertyName,
|
||||||
|
/// The property access where the property value will be destructured.
|
||||||
|
access: PropertyAccess,
|
||||||
|
/// An optional default value for the variable, in case the property doesn't exist.
|
||||||
|
default_init: Option<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// AssignmentRestProperty represents a rest property with a DestructuringAssignmentTarget.
|
||||||
|
///
|
||||||
|
/// Note: According to the spec this is not part of an ObjectBindingPattern.
|
||||||
|
/// This is only used when a object literal is used to cover an AssignmentPattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentRestProperty
|
||||||
|
AssignmentRestPropertyAccess {
|
||||||
|
/// The property access where the unassigned properties will be stored.
|
||||||
|
access: PropertyAccess,
|
||||||
|
/// A list of the excluded property keys that were already destructured.
|
||||||
|
excluded_keys: Vec<Identifier>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Pattern represents a property with a `Pattern` as the element.
|
||||||
|
///
|
||||||
|
/// Additionally to the identifier of the new property and the nested pattern,
|
||||||
|
/// this may also include an optional default initializer.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingProperty][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingProperty
|
||||||
|
Pattern {
|
||||||
|
/// The identifier name of the property to be destructured.
|
||||||
|
name: PropertyName,
|
||||||
|
/// The pattern where the property value will be destructured.
|
||||||
|
pattern: Pattern,
|
||||||
|
/// An optional default value for the variable, in case the property doesn't exist.
|
||||||
|
default_init: Option<Expression>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ObjectPatternElement {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::SingleName {
|
||||||
|
ident,
|
||||||
|
name,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
let mut buf = match name {
|
||||||
|
PropertyName::Literal(name) if name == ident => {
|
||||||
|
format!(" {}", interner.resolve_expect(ident.sym()))
|
||||||
|
}
|
||||||
|
PropertyName::Literal(name) => {
|
||||||
|
format!(
|
||||||
|
" {} : {}",
|
||||||
|
interner.resolve_expect(*name),
|
||||||
|
interner.resolve_expect(ident.sym())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PropertyName::Computed(node) => {
|
||||||
|
format!(
|
||||||
|
" [{}] : {}",
|
||||||
|
node.to_interned_string(interner),
|
||||||
|
interner.resolve_expect(ident.sym())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(ref init) = default_init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
Self::RestProperty {
|
||||||
|
ident,
|
||||||
|
excluded_keys: _,
|
||||||
|
} => {
|
||||||
|
format!(" ... {}", interner.resolve_expect(ident.sym()))
|
||||||
|
}
|
||||||
|
Self::AssignmentRestPropertyAccess { access, .. } => {
|
||||||
|
format!(" ... {}", access.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
Self::AssignmentPropertyAccess {
|
||||||
|
name,
|
||||||
|
access,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
let mut buf = match name {
|
||||||
|
PropertyName::Literal(name) => {
|
||||||
|
format!(
|
||||||
|
" {} : {}",
|
||||||
|
interner.resolve_expect(*name),
|
||||||
|
access.to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PropertyName::Computed(node) => {
|
||||||
|
format!(
|
||||||
|
" [{}] : {}",
|
||||||
|
node.to_interned_string(interner),
|
||||||
|
access.to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(init) = &default_init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
name,
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
let mut buf = match name {
|
||||||
|
PropertyName::Literal(name) => {
|
||||||
|
format!(
|
||||||
|
" {} : {}",
|
||||||
|
interner.resolve_expect(*name),
|
||||||
|
pattern.to_interned_string(interner),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PropertyName::Computed(node) => {
|
||||||
|
format!(
|
||||||
|
" [{}] : {}",
|
||||||
|
node.to_interned_string(interner),
|
||||||
|
pattern.to_interned_string(interner),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(ref init) = default_init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ObjectPatternElement {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SingleName {
|
||||||
|
name,
|
||||||
|
ident,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name(name));
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::RestProperty { ident, .. } => visitor.visit_identifier(ident),
|
||||||
|
Self::AssignmentPropertyAccess {
|
||||||
|
name,
|
||||||
|
access,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name(name));
|
||||||
|
try_break!(visitor.visit_property_access(access));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::AssignmentRestPropertyAccess { access, .. } => {
|
||||||
|
visitor.visit_property_access(access)
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
name,
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name(name));
|
||||||
|
try_break!(visitor.visit_pattern(pattern));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SingleName {
|
||||||
|
name,
|
||||||
|
ident,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(name));
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::RestProperty { ident, .. } => visitor.visit_identifier_mut(ident),
|
||||||
|
Self::AssignmentPropertyAccess {
|
||||||
|
name,
|
||||||
|
access,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(name));
|
||||||
|
try_break!(visitor.visit_property_access_mut(access));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::AssignmentRestPropertyAccess { access, .. } => {
|
||||||
|
visitor.visit_property_access_mut(access)
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
name,
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(name));
|
||||||
|
try_break!(visitor.visit_pattern_mut(pattern));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The different types of bindings that an array binding pattern may contain.
|
||||||
|
///
|
||||||
|
/// Corresponds to the [`BindingElement`][spec1] and the [`AssignmentElement`][spec2] nodes.
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingElement
|
||||||
|
/// [spec2]: https://tc39.es/ecma262/#prod-AssignmentElement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ArrayPatternElement {
|
||||||
|
/// Elision represents the elision of an item in the array binding pattern.
|
||||||
|
///
|
||||||
|
/// An `Elision` may occur at multiple points in the pattern and may be multiple elisions.
|
||||||
|
/// This variant strictly represents one elision. If there are multiple, this should be used multiple times.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 13.2.4 Array Initializer - Elision][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-Elision
|
||||||
|
Elision,
|
||||||
|
|
||||||
|
/// SingleName represents a `SingleName` with an identifier and an optional default initializer.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - SingleNameBinding][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-SingleNameBinding
|
||||||
|
SingleName {
|
||||||
|
/// The variable name where the index element will be stored.
|
||||||
|
ident: Identifier,
|
||||||
|
/// An optional default value for the variable, in case the index element doesn't exist.
|
||||||
|
default_init: Option<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// PropertyAccess represents a binding with a property accessor.
|
||||||
|
///
|
||||||
|
/// Note: According to the spec this is not part of an ArrayBindingPattern.
|
||||||
|
/// This is only used when a array literal is used as the left-hand-side of an assignment expression.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
PropertyAccess {
|
||||||
|
/// The property access where the index element will be stored.
|
||||||
|
access: PropertyAccess,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Pattern represents a `Pattern` in an `Element` of an array pattern.
|
||||||
|
///
|
||||||
|
/// The pattern and the optional default initializer are both stored in the DeclarationPattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingElement][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingElement
|
||||||
|
Pattern {
|
||||||
|
/// The pattern where the index element will be stored.
|
||||||
|
pattern: Pattern,
|
||||||
|
/// An optional default value for the pattern, in case the index element doesn't exist.
|
||||||
|
default_init: Option<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// SingleNameRest represents a `BindingIdentifier` in a `BindingRestElement` of an array pattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingRestElement][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingRestElement
|
||||||
|
SingleNameRest {
|
||||||
|
/// The variable where the unassigned index elements will be stored.
|
||||||
|
ident: Identifier,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// PropertyAccess represents a rest (spread operator) with a property accessor.
|
||||||
|
///
|
||||||
|
/// Note: According to the spec this is not part of an ArrayBindingPattern.
|
||||||
|
/// This is only used when a array literal is used as the left-hand-side of an assignment expression.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentExpression
|
||||||
|
PropertyAccessRest {
|
||||||
|
/// The property access where the unassigned index elements will be stored.
|
||||||
|
access: PropertyAccess,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// PatternRest represents a `Pattern` in a `RestElement` of an array pattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingRestElement][spec1]
|
||||||
|
///
|
||||||
|
/// [spec1]: https://tc39.es/ecma262/#prod-BindingRestElement
|
||||||
|
PatternRest {
|
||||||
|
/// The pattern where the unassigned index elements will be stored.
|
||||||
|
pattern: Pattern,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ArrayPatternElement {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Elision => " ".to_owned(),
|
||||||
|
Self::SingleName {
|
||||||
|
ident,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
let mut buf = format!(" {}", interner.resolve_expect(ident.sym()));
|
||||||
|
if let Some(ref init) = default_init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
Self::PropertyAccess { access } => {
|
||||||
|
format!(" {}", access.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
let mut buf = format!(" {}", pattern.to_interned_string(interner));
|
||||||
|
if let Some(init) = default_init {
|
||||||
|
buf.push_str(&format!(" = {}", init.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
Self::SingleNameRest { ident } => {
|
||||||
|
format!(" ... {}", interner.resolve_expect(ident.sym()))
|
||||||
|
}
|
||||||
|
Self::PropertyAccessRest { access } => {
|
||||||
|
format!(" ... {}", access.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
Self::PatternRest { pattern } => {
|
||||||
|
format!(" ... {}", pattern.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ArrayPatternElement {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SingleName {
|
||||||
|
ident,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_identifier(ident));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::PropertyAccess { access } | Self::PropertyAccessRest { access } => {
|
||||||
|
visitor.visit_property_access(access)
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_pattern(pattern));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::SingleNameRest { ident } => visitor.visit_identifier(ident),
|
||||||
|
Self::PatternRest { pattern } => visitor.visit_pattern(pattern),
|
||||||
|
Self::Elision => {
|
||||||
|
// special case to be handled by user
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::SingleName {
|
||||||
|
ident,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_identifier_mut(ident));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::PropertyAccess { access } | Self::PropertyAccessRest { access } => {
|
||||||
|
visitor.visit_property_access_mut(access)
|
||||||
|
}
|
||||||
|
Self::Pattern {
|
||||||
|
pattern,
|
||||||
|
default_init,
|
||||||
|
} => {
|
||||||
|
try_break!(visitor.visit_pattern_mut(pattern));
|
||||||
|
if let Some(expr) = default_init {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::SingleNameRest { ident } => visitor.visit_identifier_mut(ident),
|
||||||
|
Self::PatternRest { pattern } => visitor.visit_pattern_mut(pattern),
|
||||||
|
Self::Elision => {
|
||||||
|
// special case to be handled by user
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
302
javascript-engine/external/boa/boa_ast/src/position.rs
vendored
Normal file
302
javascript-engine/external/boa/boa_ast/src/position.rs
vendored
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
use std::{cmp::Ordering, fmt, num::NonZeroU32};
|
||||||
|
|
||||||
|
/// A position in the ECMAScript source code.
|
||||||
|
///
|
||||||
|
/// Stores both the column number and the line number.
|
||||||
|
///
|
||||||
|
/// ## Similar Implementations
|
||||||
|
/// [V8: Location](https://cs.chromium.org/chromium/src/v8/src/parsing/scanner.h?type=cs&q=isValid+Location&g=0&l=216)
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Position {
|
||||||
|
/// Line number.
|
||||||
|
line_number: NonZeroU32,
|
||||||
|
/// Column number.
|
||||||
|
column_number: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
/// Creates a new `Position`.
|
||||||
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(line_number: u32, column_number: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
line_number: NonZeroU32::new(line_number).expect("line number cannot be 0"),
|
||||||
|
column_number: NonZeroU32::new(column_number).expect("column number cannot be 0"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the line number of the position.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn line_number(self) -> u32 {
|
||||||
|
self.line_number.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the column number of the position.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn column_number(self) -> u32 {
|
||||||
|
self.column_number.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Position {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}:{}", self.line_number, self.column_number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A span in the ECMAScript source code.
|
||||||
|
///
|
||||||
|
/// Stores a start position and an end position.
|
||||||
|
///
|
||||||
|
/// Note that spans are of the form [start, end) i.e. that the start position is inclusive
|
||||||
|
/// and the end position is exclusive.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Span {
|
||||||
|
start: Position,
|
||||||
|
end: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Span {
|
||||||
|
/// Creates a new `Span`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the start position is bigger than the end position.
|
||||||
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(start: Position, end: Position) -> Self {
|
||||||
|
assert!(start <= end, "a span cannot start after its end");
|
||||||
|
|
||||||
|
Self { start, end }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the starting position of the span.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn start(self) -> Position {
|
||||||
|
self.start
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the final position of the span.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn end(self) -> Position {
|
||||||
|
self.end
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if this span inclusively contains another span or position.
|
||||||
|
pub fn contains<S>(self, other: S) -> bool
|
||||||
|
where
|
||||||
|
S: Into<Self>,
|
||||||
|
{
|
||||||
|
let other = other.into();
|
||||||
|
self.start <= other.start && self.end >= other.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Position> for Span {
|
||||||
|
fn from(pos: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
start: pos,
|
||||||
|
end: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Span {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
if self == other {
|
||||||
|
Some(Ordering::Equal)
|
||||||
|
} else if self.end < other.start {
|
||||||
|
Some(Ordering::Less)
|
||||||
|
} else if self.start > other.end {
|
||||||
|
Some(Ordering::Greater)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Span {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "[{}..{}]", self.start, self.end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#![allow(clippy::similar_names)]
|
||||||
|
#![allow(unused_must_use)]
|
||||||
|
use super::{Position, Span};
|
||||||
|
|
||||||
|
/// Checks that we cannot create a position with 0 as the column.
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn invalid_position_column() {
|
||||||
|
Position::new(10, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that we cannot create a position with 0 as the line.
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn invalid_position_line() {
|
||||||
|
Position::new(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the `PartialEq` implementation of `Position` is consistent.
|
||||||
|
#[test]
|
||||||
|
fn position_equality() {
|
||||||
|
assert_eq!(Position::new(10, 50), Position::new(10, 50));
|
||||||
|
assert_ne!(Position::new(10, 50), Position::new(10, 51));
|
||||||
|
assert_ne!(Position::new(10, 50), Position::new(11, 50));
|
||||||
|
assert_ne!(Position::new(10, 50), Position::new(11, 51));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the `PartialOrd` implementation of `Position` is consistent.
|
||||||
|
#[test]
|
||||||
|
fn position_order() {
|
||||||
|
assert!(Position::new(10, 50) < Position::new(10, 51));
|
||||||
|
assert!(Position::new(9, 50) < Position::new(10, 50));
|
||||||
|
assert!(Position::new(10, 50) < Position::new(11, 51));
|
||||||
|
assert!(Position::new(10, 50) < Position::new(11, 49));
|
||||||
|
|
||||||
|
assert!(Position::new(10, 51) > Position::new(10, 50));
|
||||||
|
assert!(Position::new(10, 50) > Position::new(9, 50));
|
||||||
|
assert!(Position::new(11, 51) > Position::new(10, 50));
|
||||||
|
assert!(Position::new(11, 49) > Position::new(10, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the position getters actually retrieve correct values.
|
||||||
|
#[test]
|
||||||
|
fn position_getters() {
|
||||||
|
let pos = Position::new(10, 50);
|
||||||
|
assert_eq!(pos.line_number(), 10);
|
||||||
|
assert_eq!(pos.column_number(), 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the string representation of a position is correct.
|
||||||
|
#[test]
|
||||||
|
fn position_to_string() {
|
||||||
|
let pos = Position::new(10, 50);
|
||||||
|
|
||||||
|
assert_eq!("10:50", pos.to_string());
|
||||||
|
assert_eq!("10:50", pos.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that we cannot create an invalid span.
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn invalid_span() {
|
||||||
|
let a = Position::new(10, 30);
|
||||||
|
let b = Position::new(10, 50);
|
||||||
|
Span::new(b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that we can create valid spans.
|
||||||
|
#[test]
|
||||||
|
fn span_creation() {
|
||||||
|
let a = Position::new(10, 30);
|
||||||
|
let b = Position::new(10, 50);
|
||||||
|
|
||||||
|
let _ = Span::new(a, b);
|
||||||
|
let _ = Span::new(a, a);
|
||||||
|
let _ = Span::from(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the `PartialEq` implementation of `Span` is consistent.
|
||||||
|
#[test]
|
||||||
|
fn span_equality() {
|
||||||
|
let a = Position::new(10, 50);
|
||||||
|
let b = Position::new(10, 52);
|
||||||
|
let c = Position::new(11, 20);
|
||||||
|
|
||||||
|
let span_ab = Span::new(a, b);
|
||||||
|
let span_ab_2 = Span::new(a, b);
|
||||||
|
let span_ac = Span::new(a, c);
|
||||||
|
let span_bc = Span::new(b, c);
|
||||||
|
|
||||||
|
assert_eq!(span_ab, span_ab_2);
|
||||||
|
assert_ne!(span_ab, span_ac);
|
||||||
|
assert_ne!(span_ab, span_bc);
|
||||||
|
assert_ne!(span_bc, span_ac);
|
||||||
|
|
||||||
|
let span_a = Span::from(a);
|
||||||
|
let span_aa = Span::new(a, a);
|
||||||
|
|
||||||
|
assert_eq!(span_a, span_aa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the getters retrieve the correct value.
|
||||||
|
#[test]
|
||||||
|
fn span_getters() {
|
||||||
|
let a = Position::new(10, 50);
|
||||||
|
let b = Position::new(10, 52);
|
||||||
|
|
||||||
|
let span = Span::new(a, b);
|
||||||
|
|
||||||
|
assert_eq!(span.start(), a);
|
||||||
|
assert_eq!(span.end(), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the `Span::contains()` method works properly.
|
||||||
|
#[test]
|
||||||
|
fn span_contains() {
|
||||||
|
let a = Position::new(10, 50);
|
||||||
|
let b = Position::new(10, 52);
|
||||||
|
let c = Position::new(11, 20);
|
||||||
|
let d = Position::new(12, 5);
|
||||||
|
|
||||||
|
let span_ac = Span::new(a, c);
|
||||||
|
assert!(span_ac.contains(b));
|
||||||
|
|
||||||
|
let span_ab = Span::new(a, b);
|
||||||
|
let span_cd = Span::new(c, d);
|
||||||
|
|
||||||
|
assert!(!span_ab.contains(span_cd));
|
||||||
|
assert!(span_ab.contains(b));
|
||||||
|
|
||||||
|
let span_ad = Span::new(a, d);
|
||||||
|
let span_bc = Span::new(b, c);
|
||||||
|
|
||||||
|
assert!(span_ad.contains(span_bc));
|
||||||
|
assert!(!span_bc.contains(span_ad));
|
||||||
|
|
||||||
|
let span_ac = Span::new(a, c);
|
||||||
|
let span_bd = Span::new(b, d);
|
||||||
|
|
||||||
|
assert!(!span_ac.contains(span_bd));
|
||||||
|
assert!(!span_bd.contains(span_ac));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the string representation of a span is correct.
|
||||||
|
#[test]
|
||||||
|
fn span_to_string() {
|
||||||
|
let a = Position::new(10, 50);
|
||||||
|
let b = Position::new(11, 20);
|
||||||
|
let span = Span::new(a, b);
|
||||||
|
|
||||||
|
assert_eq!("[10:50..11:20]", span.to_string());
|
||||||
|
assert_eq!("[10:50..11:20]", span.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the ordering of spans is correct.
|
||||||
|
#[test]
|
||||||
|
fn span_ordering() {
|
||||||
|
let a = Position::new(10, 50);
|
||||||
|
let b = Position::new(10, 52);
|
||||||
|
let c = Position::new(11, 20);
|
||||||
|
let d = Position::new(12, 5);
|
||||||
|
|
||||||
|
let span_ab = Span::new(a, b);
|
||||||
|
let span_cd = Span::new(c, d);
|
||||||
|
|
||||||
|
assert!(span_ab < span_cd);
|
||||||
|
assert!(span_cd > span_ab);
|
||||||
|
}
|
||||||
|
}
|
||||||
371
javascript-engine/external/boa/boa_ast/src/property.rs
vendored
Normal file
371
javascript-engine/external/boa/boa_ast/src/property.rs
vendored
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
//! Property definition related types, used in object literals and class definitions.
|
||||||
|
|
||||||
|
use crate::function::PrivateName;
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
expression::{literal::Literal, Identifier},
|
||||||
|
function::{AsyncFunction, AsyncGenerator, Function, Generator},
|
||||||
|
Expression,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Describes the definition of a property within an object literal.
|
||||||
|
///
|
||||||
|
/// A property has a name (a string) and a value (primitive, method, or object reference).
|
||||||
|
/// Note that when we say that "a property holds an object", that is shorthand for "a property holds an object reference".
|
||||||
|
/// This distinction matters because the original referenced object remains unchanged when you change the property's value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript
|
||||||
|
// TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PropertyDefinition {
|
||||||
|
/// Puts a variable into an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-IdentifierReference
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions
|
||||||
|
IdentifierReference(Identifier),
|
||||||
|
|
||||||
|
/// Binds a property name to a JavaScript value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions
|
||||||
|
Property(PropertyName, Expression),
|
||||||
|
|
||||||
|
/// A property of an object can also refer to a function or a getter or setter method.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions
|
||||||
|
MethodDefinition(PropertyName, MethodDefinition),
|
||||||
|
|
||||||
|
/// The Rest/Spread Properties for ECMAScript proposal (stage 4) adds spread properties to object literals.
|
||||||
|
/// It copies own enumerable properties from a provided object onto a new object.
|
||||||
|
///
|
||||||
|
/// Shallow-cloning (excluding `prototype`) or merging objects is now possible using a shorter syntax than `Object.assign()`.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Spread_properties
|
||||||
|
SpreadObject(Expression),
|
||||||
|
|
||||||
|
/// Cover grammar for when an object literal is used as an object binding pattern.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-CoverInitializedName
|
||||||
|
CoverInitializedName(Identifier, Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PropertyDefinition {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::IdentifierReference(id) => visitor.visit_identifier(id),
|
||||||
|
Self::Property(pn, expr) => {
|
||||||
|
try_break!(visitor.visit_property_name(pn));
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
}
|
||||||
|
Self::MethodDefinition(pn, md) => {
|
||||||
|
try_break!(visitor.visit_property_name(pn));
|
||||||
|
visitor.visit_method_definition(md)
|
||||||
|
}
|
||||||
|
Self::SpreadObject(expr) => visitor.visit_expression(expr),
|
||||||
|
Self::CoverInitializedName(id, expr) => {
|
||||||
|
try_break!(visitor.visit_identifier(id));
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::IdentifierReference(id) => visitor.visit_identifier_mut(id),
|
||||||
|
Self::Property(pn, expr) => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(pn));
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
}
|
||||||
|
Self::MethodDefinition(pn, md) => {
|
||||||
|
try_break!(visitor.visit_property_name_mut(pn));
|
||||||
|
visitor.visit_method_definition_mut(md)
|
||||||
|
}
|
||||||
|
Self::SpreadObject(expr) => visitor.visit_expression_mut(expr),
|
||||||
|
Self::CoverInitializedName(id, expr) => {
|
||||||
|
try_break!(visitor.visit_identifier_mut(id));
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method definition.
|
||||||
|
///
|
||||||
|
/// Starting with ECMAScript 2015, a shorter syntax for method definitions on objects initializers is introduced.
|
||||||
|
/// It is a shorthand for a function assigned to the method's name.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum MethodDefinition {
|
||||||
|
/// The `get` syntax binds an object property to a function that will be called when that property is looked up.
|
||||||
|
///
|
||||||
|
/// Sometimes it is desirable to allow access to a property that returns a dynamically computed value,
|
||||||
|
/// or you may want to reflect the status of an internal variable without requiring the use of explicit method calls.
|
||||||
|
/// In JavaScript, this can be accomplished with the use of a getter.
|
||||||
|
///
|
||||||
|
/// It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value,
|
||||||
|
/// although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
|
||||||
|
Get(Function),
|
||||||
|
|
||||||
|
/// The `set` syntax binds an object property to a function to be called when there is an attempt to set that property.
|
||||||
|
///
|
||||||
|
/// In JavaScript, a setter can be used to execute a function whenever a specified property is attempted to be changed.
|
||||||
|
/// Setters are most often used in conjunction with getters to create a type of pseudo-property.
|
||||||
|
/// It is not possible to simultaneously have a setter on a property that holds an actual value.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set
|
||||||
|
Set(Function),
|
||||||
|
|
||||||
|
/// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Method_definition_syntax
|
||||||
|
Ordinary(Function),
|
||||||
|
|
||||||
|
/// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#generator_methods
|
||||||
|
Generator(Generator),
|
||||||
|
|
||||||
|
/// Async generators can be used to define a method
|
||||||
|
///
|
||||||
|
/// More information
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorMethod
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_generator_methods
|
||||||
|
AsyncGenerator(AsyncGenerator),
|
||||||
|
|
||||||
|
/// Async function can be used to define a method
|
||||||
|
///
|
||||||
|
/// More information
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_methods
|
||||||
|
Async(AsyncFunction),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for MethodDefinition {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function(f),
|
||||||
|
Self::Generator(g) => visitor.visit_generator(g),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag),
|
||||||
|
Self::Async(af) => visitor.visit_async_function(af),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function_mut(f),
|
||||||
|
Self::Generator(g) => visitor.visit_generator_mut(g),
|
||||||
|
Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag),
|
||||||
|
Self::Async(af) => visitor.visit_async_function_mut(af),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `PropertyName` can be either a literal or computed.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-PropertyName
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PropertyName {
|
||||||
|
/// A `Literal` property name can be either an identifier, a string or a numeric literal.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-LiteralPropertyName
|
||||||
|
Literal(Sym),
|
||||||
|
|
||||||
|
/// A `Computed` property name is an expression that gets evaluated and converted into a property name.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ComputedPropertyName
|
||||||
|
Computed(Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropertyName {
|
||||||
|
/// Returns the literal property name if it exists.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn literal(&self) -> Option<Sym> {
|
||||||
|
if let Self::Literal(sym) = self {
|
||||||
|
Some(*sym)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the expression if the property name is computed.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn computed(&self) -> Option<&Expression> {
|
||||||
|
if let Self::Computed(expr) = self {
|
||||||
|
Some(expr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns either the literal property name or the computed const string property name.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn prop_name(&self) -> Option<Sym> {
|
||||||
|
match self {
|
||||||
|
Self::Literal(sym) | Self::Computed(Expression::Literal(Literal::String(sym))) => {
|
||||||
|
Some(*sym)
|
||||||
|
}
|
||||||
|
Self::Computed(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for PropertyName {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Literal(key) => interner.resolve_expect(*key).to_string(),
|
||||||
|
Self::Computed(key) => key.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sym> for PropertyName {
|
||||||
|
fn from(name: Sym) -> Self {
|
||||||
|
Self::Literal(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Expression> for PropertyName {
|
||||||
|
fn from(name: Expression) -> Self {
|
||||||
|
Self::Computed(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for PropertyName {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Literal(sym) => visitor.visit_sym(sym),
|
||||||
|
Self::Computed(expr) => visitor.visit_expression(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Literal(sym) => visitor.visit_sym_mut(sym),
|
||||||
|
Self::Computed(expr) => visitor.visit_expression_mut(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ClassElementName` can be either a property name or a private identifier.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ClassElementName
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ClassElementName {
|
||||||
|
/// A public property.
|
||||||
|
PropertyName(PropertyName),
|
||||||
|
/// A private property.
|
||||||
|
PrivateIdentifier(PrivateName),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassElementName {
|
||||||
|
/// Returns the property name if it exists.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn literal(&self) -> Option<Sym> {
|
||||||
|
if let Self::PropertyName(name) = self {
|
||||||
|
name.literal()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
285
javascript-engine/external/boa/boa_ast/src/punctuator.rs
vendored
Normal file
285
javascript-engine/external/boa/boa_ast/src/punctuator.rs
vendored
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
//! The `Punctuator` enum, which contains all punctuators used in ECMAScript.
|
||||||
|
//!
|
||||||
|
//! More information:
|
||||||
|
//! - [ECMAScript Reference][spec]
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#prod-Punctuator
|
||||||
|
|
||||||
|
use crate::expression::operator::{
|
||||||
|
assign::AssignOp,
|
||||||
|
binary::{ArithmeticOp, BinaryOp, BitwiseOp, LogicalOp, RelationalOp},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
convert::TryInto,
|
||||||
|
fmt::{Display, Error, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// All of the punctuators used in ECMAScript.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript Reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-Punctuator
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
|
pub enum Punctuator {
|
||||||
|
/// `+`
|
||||||
|
Add,
|
||||||
|
/// `&`
|
||||||
|
And,
|
||||||
|
/// `=>`
|
||||||
|
Arrow,
|
||||||
|
/// `=`
|
||||||
|
Assign,
|
||||||
|
/// `+=`
|
||||||
|
AssignAdd,
|
||||||
|
/// `&=`
|
||||||
|
AssignAnd,
|
||||||
|
/// `&&=`
|
||||||
|
AssignBoolAnd,
|
||||||
|
/// `||=`
|
||||||
|
AssignBoolOr,
|
||||||
|
/// `??=`,
|
||||||
|
AssignCoalesce,
|
||||||
|
/// `/=`
|
||||||
|
AssignDiv,
|
||||||
|
/// `<<=`
|
||||||
|
AssignLeftSh,
|
||||||
|
/// `%=`
|
||||||
|
AssignMod,
|
||||||
|
/// `*=`
|
||||||
|
AssignMul,
|
||||||
|
/// `|=`
|
||||||
|
AssignOr,
|
||||||
|
/// `**=`
|
||||||
|
AssignPow,
|
||||||
|
/// `>>=`
|
||||||
|
AssignRightSh,
|
||||||
|
/// `-=`
|
||||||
|
AssignSub,
|
||||||
|
/// `>>>=`
|
||||||
|
AssignURightSh,
|
||||||
|
/// `^=`
|
||||||
|
AssignXor,
|
||||||
|
/// `&&`
|
||||||
|
BoolAnd,
|
||||||
|
/// `||`
|
||||||
|
BoolOr,
|
||||||
|
/// `}`
|
||||||
|
CloseBlock,
|
||||||
|
/// `]`
|
||||||
|
CloseBracket,
|
||||||
|
/// `)`
|
||||||
|
CloseParen,
|
||||||
|
/// `??`
|
||||||
|
Coalesce,
|
||||||
|
/// `:`
|
||||||
|
Colon,
|
||||||
|
/// `,`
|
||||||
|
Comma,
|
||||||
|
/// `--`
|
||||||
|
Dec,
|
||||||
|
/// `/`
|
||||||
|
Div,
|
||||||
|
/// `.`
|
||||||
|
Dot,
|
||||||
|
/// `==`
|
||||||
|
Eq,
|
||||||
|
/// `>`
|
||||||
|
GreaterThan,
|
||||||
|
/// `>=`
|
||||||
|
GreaterThanOrEq,
|
||||||
|
/// `++`
|
||||||
|
Inc,
|
||||||
|
/// `<<`
|
||||||
|
LeftSh,
|
||||||
|
/// `<`
|
||||||
|
LessThan,
|
||||||
|
/// `<=`
|
||||||
|
LessThanOrEq,
|
||||||
|
/// `%`
|
||||||
|
Mod,
|
||||||
|
/// `*`
|
||||||
|
Mul,
|
||||||
|
/// `~`
|
||||||
|
Neg,
|
||||||
|
/// `!`
|
||||||
|
Not,
|
||||||
|
/// `!=`
|
||||||
|
NotEq,
|
||||||
|
/// `{`
|
||||||
|
OpenBlock,
|
||||||
|
/// `[`
|
||||||
|
OpenBracket,
|
||||||
|
/// `(`
|
||||||
|
OpenParen,
|
||||||
|
/// `?.`
|
||||||
|
Optional,
|
||||||
|
/// `|`
|
||||||
|
Or,
|
||||||
|
/// `**`
|
||||||
|
Exp,
|
||||||
|
/// `?`
|
||||||
|
Question,
|
||||||
|
/// `>>`
|
||||||
|
RightSh,
|
||||||
|
/// `;`
|
||||||
|
Semicolon,
|
||||||
|
/// `...`
|
||||||
|
Spread,
|
||||||
|
/// `===`
|
||||||
|
StrictEq,
|
||||||
|
/// `!==`
|
||||||
|
StrictNotEq,
|
||||||
|
/// `-`
|
||||||
|
Sub,
|
||||||
|
/// `>>>`
|
||||||
|
URightSh,
|
||||||
|
/// `^`
|
||||||
|
Xor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Punctuator {
|
||||||
|
/// Attempts to convert a punctuator (`+`, `=`...) to an Assign Operator
|
||||||
|
///
|
||||||
|
/// If there is no match, `None` will be returned.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_assign_op(self) -> Option<AssignOp> {
|
||||||
|
match self {
|
||||||
|
Self::Assign => Some(AssignOp::Assign),
|
||||||
|
Self::AssignAdd => Some(AssignOp::Add),
|
||||||
|
Self::AssignAnd => Some(AssignOp::And),
|
||||||
|
Self::AssignBoolAnd => Some(AssignOp::BoolAnd),
|
||||||
|
Self::AssignBoolOr => Some(AssignOp::BoolOr),
|
||||||
|
Self::AssignCoalesce => Some(AssignOp::Coalesce),
|
||||||
|
Self::AssignDiv => Some(AssignOp::Div),
|
||||||
|
Self::AssignLeftSh => Some(AssignOp::Shl),
|
||||||
|
Self::AssignMod => Some(AssignOp::Mod),
|
||||||
|
Self::AssignMul => Some(AssignOp::Mul),
|
||||||
|
Self::AssignOr => Some(AssignOp::Or),
|
||||||
|
Self::AssignPow => Some(AssignOp::Exp),
|
||||||
|
Self::AssignRightSh => Some(AssignOp::Shr),
|
||||||
|
Self::AssignSub => Some(AssignOp::Sub),
|
||||||
|
Self::AssignURightSh => Some(AssignOp::Ushr),
|
||||||
|
Self::AssignXor => Some(AssignOp::Xor),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to convert a punctuator (`+`, `=`...) to a Binary Operator
|
||||||
|
///
|
||||||
|
/// If there is no match, `None` will be returned.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_binary_op(self) -> Option<BinaryOp> {
|
||||||
|
match self {
|
||||||
|
Self::Add => Some(BinaryOp::Arithmetic(ArithmeticOp::Add)),
|
||||||
|
Self::Sub => Some(BinaryOp::Arithmetic(ArithmeticOp::Sub)),
|
||||||
|
Self::Mul => Some(BinaryOp::Arithmetic(ArithmeticOp::Mul)),
|
||||||
|
Self::Div => Some(BinaryOp::Arithmetic(ArithmeticOp::Div)),
|
||||||
|
Self::Mod => Some(BinaryOp::Arithmetic(ArithmeticOp::Mod)),
|
||||||
|
Self::And => Some(BinaryOp::Bitwise(BitwiseOp::And)),
|
||||||
|
Self::Or => Some(BinaryOp::Bitwise(BitwiseOp::Or)),
|
||||||
|
Self::Xor => Some(BinaryOp::Bitwise(BitwiseOp::Xor)),
|
||||||
|
Self::BoolAnd => Some(BinaryOp::Logical(LogicalOp::And)),
|
||||||
|
Self::BoolOr => Some(BinaryOp::Logical(LogicalOp::Or)),
|
||||||
|
Self::Coalesce => Some(BinaryOp::Logical(LogicalOp::Coalesce)),
|
||||||
|
Self::Eq => Some(BinaryOp::Relational(RelationalOp::Equal)),
|
||||||
|
Self::NotEq => Some(BinaryOp::Relational(RelationalOp::NotEqual)),
|
||||||
|
Self::StrictEq => Some(BinaryOp::Relational(RelationalOp::StrictEqual)),
|
||||||
|
Self::StrictNotEq => Some(BinaryOp::Relational(RelationalOp::StrictNotEqual)),
|
||||||
|
Self::LessThan => Some(BinaryOp::Relational(RelationalOp::LessThan)),
|
||||||
|
Self::GreaterThan => Some(BinaryOp::Relational(RelationalOp::GreaterThan)),
|
||||||
|
Self::GreaterThanOrEq => Some(BinaryOp::Relational(RelationalOp::GreaterThanOrEqual)),
|
||||||
|
Self::LessThanOrEq => Some(BinaryOp::Relational(RelationalOp::LessThanOrEqual)),
|
||||||
|
Self::LeftSh => Some(BinaryOp::Bitwise(BitwiseOp::Shl)),
|
||||||
|
Self::RightSh => Some(BinaryOp::Bitwise(BitwiseOp::Shr)),
|
||||||
|
Self::URightSh => Some(BinaryOp::Bitwise(BitwiseOp::UShr)),
|
||||||
|
Self::Comma => Some(BinaryOp::Comma),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the punctuator as a static string.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Add => "+",
|
||||||
|
Self::And => "&",
|
||||||
|
Self::Arrow => "=>",
|
||||||
|
Self::Assign => "=",
|
||||||
|
Self::AssignAdd => "+=",
|
||||||
|
Self::AssignAnd => "&=",
|
||||||
|
Self::AssignBoolAnd => "&&=",
|
||||||
|
Self::AssignBoolOr => "||=",
|
||||||
|
Self::AssignCoalesce => "??=",
|
||||||
|
Self::AssignDiv => "/=",
|
||||||
|
Self::AssignLeftSh => "<<=",
|
||||||
|
Self::AssignMod => "%=",
|
||||||
|
Self::AssignMul => "*=",
|
||||||
|
Self::AssignOr => "|=",
|
||||||
|
Self::AssignPow => "**=",
|
||||||
|
Self::AssignRightSh => ">>=",
|
||||||
|
Self::AssignSub => "-=",
|
||||||
|
Self::AssignURightSh => ">>>=",
|
||||||
|
Self::AssignXor => "^=",
|
||||||
|
Self::BoolAnd => "&&",
|
||||||
|
Self::BoolOr => "||",
|
||||||
|
Self::Coalesce => "??",
|
||||||
|
Self::CloseBlock => "}",
|
||||||
|
Self::CloseBracket => "]",
|
||||||
|
Self::CloseParen => ")",
|
||||||
|
Self::Colon => ":",
|
||||||
|
Self::Comma => ",",
|
||||||
|
Self::Dec => "--",
|
||||||
|
Self::Div => "/",
|
||||||
|
Self::Dot => ".",
|
||||||
|
Self::Eq => "==",
|
||||||
|
Self::GreaterThan => ">",
|
||||||
|
Self::GreaterThanOrEq => ">=",
|
||||||
|
Self::Inc => "++",
|
||||||
|
Self::LeftSh => "<<",
|
||||||
|
Self::LessThan => "<",
|
||||||
|
Self::LessThanOrEq => "<=",
|
||||||
|
Self::Mod => "%",
|
||||||
|
Self::Mul => "*",
|
||||||
|
Self::Neg => "~",
|
||||||
|
Self::Not => "!",
|
||||||
|
Self::NotEq => "!=",
|
||||||
|
Self::OpenBlock => "{",
|
||||||
|
Self::OpenBracket => "[",
|
||||||
|
Self::OpenParen => "(",
|
||||||
|
Self::Optional => "?.",
|
||||||
|
Self::Or => "|",
|
||||||
|
Self::Exp => "**",
|
||||||
|
Self::Question => "?",
|
||||||
|
Self::RightSh => ">>",
|
||||||
|
Self::Semicolon => ";",
|
||||||
|
Self::Spread => "...",
|
||||||
|
Self::StrictEq => "===",
|
||||||
|
Self::StrictNotEq => "!==",
|
||||||
|
Self::Sub => "-",
|
||||||
|
Self::URightSh => ">>>",
|
||||||
|
Self::Xor => "^",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<BinaryOp> for Punctuator {
|
||||||
|
type Error = String;
|
||||||
|
fn try_into(self) -> Result<BinaryOp, Self::Error> {
|
||||||
|
self.as_binary_op()
|
||||||
|
.ok_or_else(|| format!("No binary operation for {self}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Punctuator {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Punctuator> for Box<str> {
|
||||||
|
fn from(p: Punctuator) -> Self {
|
||||||
|
p.as_str().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
85
javascript-engine/external/boa/boa_ast/src/statement/block.rs
vendored
Normal file
85
javascript-engine/external/boa/boa_ast/src/statement/block.rs
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
//! Block AST node.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
Statement, StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// A `block` statement (or compound statement in other languages) is used to group zero or
|
||||||
|
/// more statements.
|
||||||
|
///
|
||||||
|
/// The block statement is often called compound statement in other languages.
|
||||||
|
/// It allows you to use multiple statements where ECMAScript expects only one statement.
|
||||||
|
/// Combining statements into blocks is a common practice in ECMAScript. The opposite behavior
|
||||||
|
/// is possible using an empty statement, where you provide no statement, although one is
|
||||||
|
/// required.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BlockStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
|
pub struct Block {
|
||||||
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
|
statements: StatementList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block {
|
||||||
|
/// Gets the list of statements and declarations in this block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn statement_list(&self) -> &StatementList {
|
||||||
|
&self.statements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Block
|
||||||
|
where
|
||||||
|
T: Into<StatementList>,
|
||||||
|
{
|
||||||
|
fn from(list: T) -> Self {
|
||||||
|
Self {
|
||||||
|
statements: list.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Block {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"{{\n{}{}}}",
|
||||||
|
self.statements
|
||||||
|
.to_indented_string(interner, indentation + 1),
|
||||||
|
" ".repeat(indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Block> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(block: Block) -> Self {
|
||||||
|
Self::Block(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Block {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_statement_list(&self.statements)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_statement_list_mut(&mut self.statements)
|
||||||
|
}
|
||||||
|
}
|
||||||
119
javascript-engine/external/boa/boa_ast/src/statement/if.rs
vendored
Normal file
119
javascript-engine/external/boa/boa_ast/src/statement/if.rs
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//! If statement
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::Statement,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `if` statement executes a statement if a specified condition is [`truthy`][truthy]. If
|
||||||
|
/// the condition is [`falsy`][falsy], another statement can be executed.
|
||||||
|
///
|
||||||
|
/// Multiple `if...else` statements can be nested to create an else if clause.
|
||||||
|
///
|
||||||
|
/// Note that there is no elseif (in one word) keyword in JavaScript.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-IfStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
|
||||||
|
/// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/truthy
|
||||||
|
/// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy
|
||||||
|
/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct If {
|
||||||
|
condition: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
else_node: Option<Box<Statement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl If {
|
||||||
|
/// Gets the condition of the if statement.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cond(&self) -> &Expression {
|
||||||
|
&self.condition
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body to execute if the condition is true.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `else` node, if it has one.
|
||||||
|
#[inline]
|
||||||
|
pub fn else_node(&self) -> Option<&Statement> {
|
||||||
|
self.else_node.as_ref().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an `If` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(condition: Expression, body: Statement, else_node: Option<Statement>) -> Self {
|
||||||
|
Self {
|
||||||
|
condition,
|
||||||
|
body: body.into(),
|
||||||
|
else_node: else_node.map(Box::new),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for If {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indent: usize) -> String {
|
||||||
|
let mut buf = format!("if ({}) ", self.cond().to_interned_string(interner));
|
||||||
|
match self.else_node() {
|
||||||
|
Some(else_e) => {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"{} else {}",
|
||||||
|
self.body().to_indented_string(interner, indent),
|
||||||
|
else_e.to_indented_string(interner, indent)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
buf.push_str(&self.body().to_indented_string(interner, indent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<If> for Statement {
|
||||||
|
fn from(if_stm: If) -> Self {
|
||||||
|
Self::If(if_stm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for If {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.condition));
|
||||||
|
try_break!(visitor.visit_statement(&self.body));
|
||||||
|
if let Some(stmt) = &self.else_node {
|
||||||
|
try_break!(visitor.visit_statement(stmt));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.condition));
|
||||||
|
try_break!(visitor.visit_statement_mut(&mut self.body));
|
||||||
|
if let Some(stmt) = &mut self.else_node {
|
||||||
|
try_break!(visitor.visit_statement_mut(stmt));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
79
javascript-engine/external/boa/boa_ast/src/statement/iteration/break.rs
vendored
Normal file
79
javascript-engine/external/boa/boa_ast/src/statement/iteration/break.rs
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::Statement;
|
||||||
|
|
||||||
|
/// The `break` statement terminates the current loop, switch, or label statement and transfers
|
||||||
|
/// program control to the statement following the terminated statement.
|
||||||
|
///
|
||||||
|
/// The break statement includes an optional label that allows the program to break out of a
|
||||||
|
/// labeled statement. The break statement needs to be nested within the referenced label. The
|
||||||
|
/// labeled statement can be any block statement; it does not have to be preceded by a loop
|
||||||
|
/// statement.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-BreakStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Break {
|
||||||
|
label: Option<Sym>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Break {
|
||||||
|
/// Creates a `Break` AST node.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(label: Option<Sym>) -> Self {
|
||||||
|
Self { label }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the label of the break statement, if any.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn label(&self) -> Option<Sym> {
|
||||||
|
self.label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Break {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
self.label.map_or_else(
|
||||||
|
|| "break".to_owned(),
|
||||||
|
|label| format!("break {}", interner.resolve_expect(label)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Break> for Statement {
|
||||||
|
fn from(break_smt: Break) -> Self {
|
||||||
|
Self::Break(break_smt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Break {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(sym) = &self.label {
|
||||||
|
visitor.visit_sym(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(sym) = &mut self.label {
|
||||||
|
visitor.visit_sym_mut(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
javascript-engine/external/boa/boa_ast/src/statement/iteration/continue.rs
vendored
Normal file
77
javascript-engine/external/boa/boa_ast/src/statement/iteration/continue.rs
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use crate::statement::Statement;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, Sym, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `continue` statement terminates execution of the statements in the current iteration of
|
||||||
|
/// the current or labeled loop, and continues execution of the loop with the next iteration.
|
||||||
|
///
|
||||||
|
/// The continue statement can include an optional label that allows the program to jump to the
|
||||||
|
/// next iteration of a labeled loop statement instead of the current loop. In this case, the
|
||||||
|
/// continue statement needs to be nested within this labeled statement.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Continue {
|
||||||
|
label: Option<Sym>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Continue {
|
||||||
|
/// Creates a `Continue` AST node.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(label: Option<Sym>) -> Self {
|
||||||
|
Self { label }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the label of this `Continue` statement.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn label(&self) -> Option<Sym> {
|
||||||
|
self.label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Continue {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
self.label.map_or_else(
|
||||||
|
|| "continue".to_owned(),
|
||||||
|
|label| format!("continue {}", interner.resolve_expect(label)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Continue> for Statement {
|
||||||
|
fn from(cont: Continue) -> Self {
|
||||||
|
Self::Continue(cont)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Continue {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(sym) = &self.label {
|
||||||
|
visitor.visit_sym(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(sym) = &mut self.label {
|
||||||
|
visitor.visit_sym_mut(sym)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
javascript-engine/external/boa/boa_ast/src/statement/iteration/do_while_loop.rs
vendored
Normal file
87
javascript-engine/external/boa/boa_ast/src/statement/iteration/do_while_loop.rs
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::Statement,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `do...while` statement creates a loop that executes a specified statement until the
|
||||||
|
/// test condition evaluates to false.
|
||||||
|
///
|
||||||
|
/// The condition is evaluated after executing the statement, resulting in the specified
|
||||||
|
/// statement executing at least once.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-do-while-statement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct DoWhileLoop {
|
||||||
|
body: Box<Statement>,
|
||||||
|
condition: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DoWhileLoop {
|
||||||
|
/// Gets the body of the do-while loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the condition of the do-while loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cond(&self) -> &Expression {
|
||||||
|
&self.condition
|
||||||
|
}
|
||||||
|
/// Creates a `DoWhileLoop` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(body: Statement, condition: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
body: body.into(),
|
||||||
|
condition,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for DoWhileLoop {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"do {} while ({})",
|
||||||
|
self.body().to_indented_string(interner, indentation),
|
||||||
|
self.cond().to_interned_string(interner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DoWhileLoop> for Statement {
|
||||||
|
fn from(do_while: DoWhileLoop) -> Self {
|
||||||
|
Self::DoWhileLoop(do_while)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for DoWhileLoop {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_statement(&self.body));
|
||||||
|
visitor.visit_expression(&self.condition)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_statement_mut(&mut self.body));
|
||||||
|
visitor.visit_expression_mut(&mut self.condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
98
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_in_loop.rs
vendored
Normal file
98
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_in_loop.rs
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::{iteration::IterableLoopInitializer, Statement},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// A `for...in` loop statement, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [`for...in`][forin] statements loop over all enumerable string properties of an object, including
|
||||||
|
/// inherited properties.
|
||||||
|
///
|
||||||
|
/// [forin]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ForInLoop {
|
||||||
|
initializer: IterableLoopInitializer,
|
||||||
|
target: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForInLoop {
|
||||||
|
/// Creates a new `ForInLoop`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(initializer: IterableLoopInitializer, target: Expression, body: Statement) -> Self {
|
||||||
|
Self {
|
||||||
|
initializer,
|
||||||
|
target,
|
||||||
|
body: body.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initializer of the for...in loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn initializer(&self) -> &IterableLoopInitializer {
|
||||||
|
&self.initializer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the target object of the for...in loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the for...in loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for ForInLoop {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = format!(
|
||||||
|
"for ({} in {}) ",
|
||||||
|
self.initializer.to_interned_string(interner),
|
||||||
|
self.target.to_interned_string(interner)
|
||||||
|
);
|
||||||
|
buf.push_str(&self.body().to_indented_string(interner, indentation));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ForInLoop> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(for_in: ForInLoop) -> Self {
|
||||||
|
Self::ForInLoop(for_in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ForInLoop {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_iterable_loop_initializer(&self.initializer));
|
||||||
|
try_break!(visitor.visit_expression(&self.target));
|
||||||
|
visitor.visit_statement(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_iterable_loop_initializer_mut(&mut self.initializer));
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.target));
|
||||||
|
visitor.visit_statement_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
263
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_loop.rs
vendored
Normal file
263
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_loop.rs
vendored
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
declaration::{LexicalDeclaration, VarDeclaration},
|
||||||
|
statement::Statement,
|
||||||
|
Expression,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `for` statement creates a loop that consists of three optional expressions.
|
||||||
|
///
|
||||||
|
/// A [`for`][mdn] loop repeats until a specified condition evaluates to `false`.
|
||||||
|
/// The JavaScript for loop is similar to the Java and C for loop.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForDeclaration
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ForLoop {
|
||||||
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
|
inner: Box<InnerForLoop>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForLoop {
|
||||||
|
/// Creates a new for loop AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
init: Option<ForLoopInitializer>,
|
||||||
|
condition: Option<Expression>,
|
||||||
|
final_expr: Option<Expression>,
|
||||||
|
body: Statement,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initialization node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn init(&self) -> Option<&ForLoopInitializer> {
|
||||||
|
self.inner.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the loop condition node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn condition(&self) -> Option<&Expression> {
|
||||||
|
self.inner.condition()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the final expression node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn final_expr(&self) -> Option<&Expression> {
|
||||||
|
self.inner.final_expr()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the for loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
self.inner.body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for ForLoop {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = String::from("for (");
|
||||||
|
if let Some(init) = self.init() {
|
||||||
|
buf.push_str(&init.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
buf.push_str("; ");
|
||||||
|
if let Some(condition) = self.condition() {
|
||||||
|
buf.push_str(&condition.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
buf.push_str("; ");
|
||||||
|
if let Some(final_expr) = self.final_expr() {
|
||||||
|
buf.push_str(&final_expr.to_interned_string(interner));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
") {}",
|
||||||
|
self.inner.body().to_indented_string(interner, indentation)
|
||||||
|
));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ForLoop> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(for_loop: ForLoop) -> Self {
|
||||||
|
Self::ForLoop(for_loop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ForLoop {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(fli) = &self.inner.init {
|
||||||
|
try_break!(visitor.visit_for_loop_initializer(fli));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &self.inner.condition {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &self.inner.final_expr {
|
||||||
|
try_break!(visitor.visit_expression(expr));
|
||||||
|
}
|
||||||
|
visitor.visit_statement(&self.inner.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(fli) = &mut self.inner.init {
|
||||||
|
try_break!(visitor.visit_for_loop_initializer_mut(fli));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &mut self.inner.condition {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
if let Some(expr) = &mut self.inner.final_expr {
|
||||||
|
try_break!(visitor.visit_expression_mut(expr));
|
||||||
|
}
|
||||||
|
visitor.visit_statement_mut(&mut self.inner.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inner structure to avoid multiple indirections in the heap.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
struct InnerForLoop {
|
||||||
|
init: Option<ForLoopInitializer>,
|
||||||
|
condition: Option<Expression>,
|
||||||
|
final_expr: Option<Expression>,
|
||||||
|
body: Statement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InnerForLoop {
|
||||||
|
/// Creates a new inner for loop.
|
||||||
|
#[inline]
|
||||||
|
const fn new(
|
||||||
|
init: Option<ForLoopInitializer>,
|
||||||
|
condition: Option<Expression>,
|
||||||
|
final_expr: Option<Expression>,
|
||||||
|
body: Statement,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
init,
|
||||||
|
condition,
|
||||||
|
final_expr,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initialization node.
|
||||||
|
#[inline]
|
||||||
|
const fn init(&self) -> Option<&ForLoopInitializer> {
|
||||||
|
self.init.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the loop condition node.
|
||||||
|
#[inline]
|
||||||
|
const fn condition(&self) -> Option<&Expression> {
|
||||||
|
self.condition.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the final expression node.
|
||||||
|
#[inline]
|
||||||
|
const fn final_expr(&self) -> Option<&Expression> {
|
||||||
|
self.final_expr.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the for loop.
|
||||||
|
#[inline]
|
||||||
|
const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`ForLoop`] initializer, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// A `ForLoop` initializer differs a lot from an
|
||||||
|
/// [`IterableLoopInitializer`][super::IterableLoopInitializer], since it can contain any arbitrary
|
||||||
|
/// expression instead of only accessors and patterns. Additionally, it can also contain many variable
|
||||||
|
/// declarations instead of only one.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForStatement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ForLoopInitializer {
|
||||||
|
/// An expression initializer.
|
||||||
|
Expression(Expression),
|
||||||
|
/// A var declaration initializer.
|
||||||
|
Var(VarDeclaration),
|
||||||
|
/// A lexical declaration initializer.
|
||||||
|
Lexical(LexicalDeclaration),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for ForLoopInitializer {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Var(var) => var.to_interned_string(interner),
|
||||||
|
Self::Lexical(lex) => lex.to_interned_string(interner),
|
||||||
|
Self::Expression(expr) => expr.to_interned_string(interner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Expression> for ForLoopInitializer {
|
||||||
|
#[inline]
|
||||||
|
fn from(expr: Expression) -> Self {
|
||||||
|
Self::Expression(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LexicalDeclaration> for ForLoopInitializer {
|
||||||
|
#[inline]
|
||||||
|
fn from(list: LexicalDeclaration) -> Self {
|
||||||
|
Self::Lexical(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VarDeclaration> for ForLoopInitializer {
|
||||||
|
#[inline]
|
||||||
|
fn from(list: VarDeclaration) -> Self {
|
||||||
|
Self::Var(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ForLoopInitializer {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Expression(expr) => visitor.visit_expression(expr),
|
||||||
|
Self::Var(vd) => visitor.visit_var_declaration(vd),
|
||||||
|
Self::Lexical(ld) => visitor.visit_lexical_declaration(ld),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Expression(expr) => visitor.visit_expression_mut(expr),
|
||||||
|
Self::Var(vd) => visitor.visit_var_declaration_mut(vd),
|
||||||
|
Self::Lexical(ld) => visitor.visit_lexical_declaration_mut(ld),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
115
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_of_loop.rs
vendored
Normal file
115
javascript-engine/external/boa/boa_ast/src/statement/iteration/for_of_loop.rs
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::{iteration::IterableLoopInitializer, Statement},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// A `for...of` loop statement, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// [`for..of`][forof] statements loop over a sequence of values obtained from an iterable object (Array,
|
||||||
|
/// String, Map, generators).
|
||||||
|
///
|
||||||
|
/// This type combines `for..of` and [`for await...of`][forawait] statements in a single structure,
|
||||||
|
/// since `for await...of` is essentially the same statement but with async iterable objects
|
||||||
|
/// as the source of iteration.
|
||||||
|
///
|
||||||
|
/// [forof]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
|
||||||
|
/// [forawait]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ForOfLoop {
|
||||||
|
init: IterableLoopInitializer,
|
||||||
|
iterable: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
r#await: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForOfLoop {
|
||||||
|
/// Creates a new "for of" loop AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
init: IterableLoopInitializer,
|
||||||
|
iterable: Expression,
|
||||||
|
body: Statement,
|
||||||
|
r#await: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
init,
|
||||||
|
iterable,
|
||||||
|
body: body.into(),
|
||||||
|
r#await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the initializer of the for...of loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn initializer(&self) -> &IterableLoopInitializer {
|
||||||
|
&self.init
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the iterable expression of the for...of loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn iterable(&self) -> &Expression {
|
||||||
|
&self.iterable
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body to execute in the for...of loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this "for...of" loop is an "for await...of" loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn r#await(&self) -> bool {
|
||||||
|
self.r#await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for ForOfLoop {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"for ({} of {}) {}",
|
||||||
|
self.init.to_interned_string(interner),
|
||||||
|
self.iterable.to_interned_string(interner),
|
||||||
|
self.body().to_indented_string(interner, indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ForOfLoop> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(for_of: ForOfLoop) -> Self {
|
||||||
|
Self::ForOfLoop(for_of)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for ForOfLoop {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_iterable_loop_initializer(&self.init));
|
||||||
|
try_break!(visitor.visit_expression(&self.iterable));
|
||||||
|
visitor.visit_statement(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_iterable_loop_initializer_mut(&mut self.init));
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.iterable));
|
||||||
|
visitor.visit_statement_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
94
javascript-engine/external/boa/boa_ast/src/statement/iteration/mod.rs
vendored
Normal file
94
javascript-engine/external/boa/boa_ast/src/statement/iteration/mod.rs
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//! Iteration nodes
|
||||||
|
|
||||||
|
mod r#break;
|
||||||
|
mod r#continue;
|
||||||
|
mod do_while_loop;
|
||||||
|
mod for_in_loop;
|
||||||
|
mod for_loop;
|
||||||
|
mod for_of_loop;
|
||||||
|
mod while_loop;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
declaration::Binding,
|
||||||
|
expression::{access::PropertyAccess, Identifier},
|
||||||
|
pattern::Pattern,
|
||||||
|
};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
do_while_loop::DoWhileLoop,
|
||||||
|
for_in_loop::ForInLoop,
|
||||||
|
for_loop::{ForLoop, ForLoopInitializer},
|
||||||
|
for_of_loop::ForOfLoop,
|
||||||
|
r#break::Break,
|
||||||
|
r#continue::Continue,
|
||||||
|
while_loop::WhileLoop,
|
||||||
|
};
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
|
||||||
|
/// A `for-in`, `for-of` and `for-await-of` loop initializer.
|
||||||
|
///
|
||||||
|
/// The [spec] specifies only single bindings for the listed types of loops, which makes us
|
||||||
|
/// unable to use plain `LexicalDeclaration`s or `VarStatement`s as initializers, since those
|
||||||
|
/// can have more than one binding.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum IterableLoopInitializer {
|
||||||
|
/// An already declared variable.
|
||||||
|
Identifier(Identifier),
|
||||||
|
/// A property access.
|
||||||
|
Access(PropertyAccess),
|
||||||
|
/// A new var declaration.
|
||||||
|
Var(Binding),
|
||||||
|
/// A new let declaration.
|
||||||
|
Let(Binding),
|
||||||
|
/// A new const declaration.
|
||||||
|
Const(Binding),
|
||||||
|
/// A pattern with already declared variables.
|
||||||
|
Pattern(Pattern),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for IterableLoopInitializer {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
let (binding, pre) = match self {
|
||||||
|
Self::Identifier(ident) => return ident.to_interned_string(interner),
|
||||||
|
Self::Pattern(pattern) => return pattern.to_interned_string(interner),
|
||||||
|
Self::Access(access) => return access.to_interned_string(interner),
|
||||||
|
Self::Var(binding) => (binding, "var"),
|
||||||
|
Self::Let(binding) => (binding, "let"),
|
||||||
|
Self::Const(binding) => (binding, "const"),
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("{pre} {}", binding.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for IterableLoopInitializer {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier(id),
|
||||||
|
Self::Access(pa) => visitor.visit_property_access(pa),
|
||||||
|
Self::Var(b) | Self::Let(b) | Self::Const(b) => visitor.visit_binding(b),
|
||||||
|
Self::Pattern(p) => visitor.visit_pattern(p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Identifier(id) => visitor.visit_identifier_mut(id),
|
||||||
|
Self::Access(pa) => visitor.visit_property_access_mut(pa),
|
||||||
|
Self::Var(b) | Self::Let(b) | Self::Const(b) => visitor.visit_binding_mut(b),
|
||||||
|
Self::Pattern(p) => visitor.visit_pattern_mut(p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
88
javascript-engine/external/boa/boa_ast/src/statement/iteration/while_loop.rs
vendored
Normal file
88
javascript-engine/external/boa/boa_ast/src/statement/iteration/while_loop.rs
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::Statement,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `while` statement creates a loop that executes a specified statement as long as the
|
||||||
|
/// test condition evaluates to `true`.
|
||||||
|
///
|
||||||
|
/// The condition is evaluated before executing the statement.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct WhileLoop {
|
||||||
|
condition: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WhileLoop {
|
||||||
|
/// Creates a `WhileLoop` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(condition: Expression, body: Statement) -> Self {
|
||||||
|
Self {
|
||||||
|
condition,
|
||||||
|
body: body.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the condition of the while loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn condition(&self) -> &Expression {
|
||||||
|
&self.condition
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the body of the while loop.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &Statement {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for WhileLoop {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"while ({}) {}",
|
||||||
|
self.condition().to_interned_string(interner),
|
||||||
|
self.body().to_indented_string(interner, indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WhileLoop> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(while_loop: WhileLoop) -> Self {
|
||||||
|
Self::WhileLoop(while_loop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for WhileLoop {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.condition));
|
||||||
|
visitor.visit_statement(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.condition));
|
||||||
|
visitor.visit_statement_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
154
javascript-engine/external/boa/boa_ast/src/statement/labelled.rs
vendored
Normal file
154
javascript-engine/external/boa/boa_ast/src/statement/labelled.rs
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
use crate::{
|
||||||
|
function::Function,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
Statement,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The set of Parse Nodes that can be preceded by a label, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// Semantically, a [`Labelled`] statement should only wrap [`Statement`] nodes. However,
|
||||||
|
/// old ECMAScript implementations supported [labelled function declarations][label-fn] as an extension
|
||||||
|
/// of the grammar. In the ECMAScript 2015 spec, the production of `LabelledStatement` was
|
||||||
|
/// modified to include labelled [`Function`]s as a valid node.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-LabelledItem
|
||||||
|
/// [label-fn]: https://tc39.es/ecma262/#sec-labelled-function-declarations
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum LabelledItem {
|
||||||
|
/// A labelled [`Function`].
|
||||||
|
Function(Function),
|
||||||
|
/// A labelled [`Statement`].
|
||||||
|
Statement(Statement),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LabelledItem {
|
||||||
|
pub(crate) fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => f.to_indented_string(interner, indentation),
|
||||||
|
Self::Statement(stmt) => stmt.to_indented_string(interner, indentation),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for LabelledItem {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
self.to_indented_string(interner, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Function> for LabelledItem {
|
||||||
|
fn from(f: Function) -> Self {
|
||||||
|
Self::Function(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Statement> for LabelledItem {
|
||||||
|
fn from(stmt: Statement) -> Self {
|
||||||
|
Self::Statement(stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for LabelledItem {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => visitor.visit_function(f),
|
||||||
|
Self::Statement(s) => visitor.visit_statement(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Function(f) => visitor.visit_function_mut(f),
|
||||||
|
Self::Statement(s) => visitor.visit_statement_mut(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Labelled statement nodes, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// The method [`Labelled::item`] doesn't return a [`Statement`] for compatibility reasons.
|
||||||
|
/// See [`LabelledItem`] for more information.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-labelled-statements
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Labelled {
|
||||||
|
item: Box<LabelledItem>,
|
||||||
|
label: Sym,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Labelled {
|
||||||
|
/// Creates a new `Labelled` statement.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(item: LabelledItem, label: Sym) -> Self {
|
||||||
|
Self {
|
||||||
|
item: Box::new(item),
|
||||||
|
label,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the labelled item.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn item(&self) -> &LabelledItem {
|
||||||
|
&self.item
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the label name.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn label(&self) -> Sym {
|
||||||
|
self.label
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"{}: {}",
|
||||||
|
interner.resolve_expect(self.label),
|
||||||
|
self.item.to_indented_string(interner, indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Labelled {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
self.to_indented_string(interner, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Labelled> for Statement {
|
||||||
|
fn from(labelled: Labelled) -> Self {
|
||||||
|
Self::Labelled(labelled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Labelled {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_labelled_item(&self.item));
|
||||||
|
visitor.visit_sym(&self.label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_labelled_item_mut(&mut self.item));
|
||||||
|
visitor.visit_sym_mut(&mut self.label)
|
||||||
|
}
|
||||||
|
}
|
||||||
241
javascript-engine/external/boa/boa_ast/src/statement/mod.rs
vendored
Normal file
241
javascript-engine/external/boa/boa_ast/src/statement/mod.rs
vendored
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
//! The [`Statement`] Parse Node, as defined by the [spec].
|
||||||
|
//!
|
||||||
|
//! ECMAScript [statements] are mainly composed of control flow operations, such as [`If`],
|
||||||
|
//! [`WhileLoop`], and [`Break`]. However, it also contains statements such as [`VarDeclaration`],
|
||||||
|
//! [`Block`] or [`Expression`] which are not strictly used for control flow.
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#prod-Statement
|
||||||
|
//! [statements]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements
|
||||||
|
|
||||||
|
mod block;
|
||||||
|
mod r#if;
|
||||||
|
mod labelled;
|
||||||
|
mod r#return;
|
||||||
|
mod switch;
|
||||||
|
mod throw;
|
||||||
|
mod r#try;
|
||||||
|
|
||||||
|
pub mod iteration;
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
block::Block,
|
||||||
|
iteration::{Break, Continue, DoWhileLoop, ForInLoop, ForLoop, ForOfLoop, WhileLoop},
|
||||||
|
labelled::{Labelled, LabelledItem},
|
||||||
|
r#if::If,
|
||||||
|
r#return::Return,
|
||||||
|
r#try::{Catch, ErrorHandler, Finally, Try},
|
||||||
|
switch::{Case, Switch},
|
||||||
|
throw::Throw,
|
||||||
|
};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
|
||||||
|
use super::{declaration::VarDeclaration, expression::Expression};
|
||||||
|
|
||||||
|
/// The `Statement` Parse Node.
|
||||||
|
///
|
||||||
|
/// See the [module level documentation][self] for more information.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Statement {
|
||||||
|
/// See [`Block`].
|
||||||
|
Block(Block),
|
||||||
|
|
||||||
|
/// See [`VarDeclaration`]
|
||||||
|
Var(VarDeclaration),
|
||||||
|
|
||||||
|
/// An empty statement.
|
||||||
|
///
|
||||||
|
/// Empty statements do nothing, just return undefined.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-EmptyStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/Empty
|
||||||
|
Empty,
|
||||||
|
|
||||||
|
/// See [`Expression`].
|
||||||
|
Expression(Expression),
|
||||||
|
|
||||||
|
/// See [`If`].
|
||||||
|
If(If),
|
||||||
|
|
||||||
|
/// See [`DoWhileLoop`].
|
||||||
|
DoWhileLoop(DoWhileLoop),
|
||||||
|
|
||||||
|
/// See [`WhileLoop`].
|
||||||
|
WhileLoop(WhileLoop),
|
||||||
|
|
||||||
|
/// See [`ForLoop`].
|
||||||
|
ForLoop(ForLoop),
|
||||||
|
|
||||||
|
/// See [`ForInLoop`].
|
||||||
|
ForInLoop(ForInLoop),
|
||||||
|
|
||||||
|
/// See [`ForOfLoop`].
|
||||||
|
ForOfLoop(ForOfLoop),
|
||||||
|
|
||||||
|
/// See[`Switch`].
|
||||||
|
Switch(Switch),
|
||||||
|
|
||||||
|
/// See [`Continue`].
|
||||||
|
Continue(Continue),
|
||||||
|
|
||||||
|
/// See [`Break`].
|
||||||
|
Break(Break),
|
||||||
|
|
||||||
|
/// See [`Return`].
|
||||||
|
Return(Return),
|
||||||
|
|
||||||
|
// TODO: Possibly add `with` statements.
|
||||||
|
/// See [`Labelled`].
|
||||||
|
Labelled(Labelled),
|
||||||
|
|
||||||
|
/// See [`Throw`].
|
||||||
|
Throw(Throw),
|
||||||
|
|
||||||
|
/// See [`Try`].
|
||||||
|
Try(Try),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
/// Implements the display formatting with indentation.
|
||||||
|
///
|
||||||
|
/// This will not prefix the value with any indentation. If you want to prefix this with proper
|
||||||
|
/// indents, use [`to_indented_string()`](Self::to_indented_string).
|
||||||
|
pub(super) fn to_no_indent_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut s = match self {
|
||||||
|
Self::Block(block) => return block.to_indented_string(interner, indentation),
|
||||||
|
Self::Var(var) => var.to_interned_string(interner),
|
||||||
|
Self::Empty => return ";".to_owned(),
|
||||||
|
Self::Expression(expr) => expr.to_indented_string(interner, indentation),
|
||||||
|
Self::If(if_smt) => return if_smt.to_indented_string(interner, indentation),
|
||||||
|
Self::DoWhileLoop(do_while) => do_while.to_indented_string(interner, indentation),
|
||||||
|
Self::WhileLoop(while_loop) => {
|
||||||
|
return while_loop.to_indented_string(interner, indentation)
|
||||||
|
}
|
||||||
|
Self::ForLoop(for_loop) => return for_loop.to_indented_string(interner, indentation),
|
||||||
|
Self::ForInLoop(for_in) => return for_in.to_indented_string(interner, indentation),
|
||||||
|
Self::ForOfLoop(for_of) => return for_of.to_indented_string(interner, indentation),
|
||||||
|
Self::Switch(switch) => return switch.to_indented_string(interner, indentation),
|
||||||
|
Self::Continue(cont) => cont.to_interned_string(interner),
|
||||||
|
Self::Break(break_smt) => break_smt.to_interned_string(interner),
|
||||||
|
Self::Return(ret) => ret.to_interned_string(interner),
|
||||||
|
Self::Labelled(labelled) => return labelled.to_interned_string(interner),
|
||||||
|
Self::Throw(throw) => throw.to_interned_string(interner),
|
||||||
|
Self::Try(try_catch) => return try_catch.to_indented_string(interner, indentation),
|
||||||
|
};
|
||||||
|
s.push(';');
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Abstract operation [`IsLabelledFunction`][spec].
|
||||||
|
///
|
||||||
|
/// This recursively checks if this `Statement` is a labelled function, since adding
|
||||||
|
/// several labels in a function should not change the return value of the abstract operation:
|
||||||
|
///
|
||||||
|
/// ```Javascript
|
||||||
|
/// l1: l2: l3: l4: function f(){ }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This should return `true` for that snippet.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-islabelledfunction
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_labelled_function(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Labelled(stmt) => match stmt.item() {
|
||||||
|
LabelledItem::Function(_) => true,
|
||||||
|
LabelledItem::Statement(stmt) => stmt.is_labelled_function(),
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Statement {
|
||||||
|
/// Creates a string of the value of the node with the given indentation. For example, an
|
||||||
|
/// indent level of 2 would produce this:
|
||||||
|
///
|
||||||
|
/// ```js
|
||||||
|
/// function hello() {
|
||||||
|
/// console.log("hello");
|
||||||
|
/// }
|
||||||
|
/// hello();
|
||||||
|
/// a = 2;
|
||||||
|
/// ```
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = match *self {
|
||||||
|
Self::Block(_) => String::new(),
|
||||||
|
_ => " ".repeat(indentation),
|
||||||
|
};
|
||||||
|
|
||||||
|
buf.push_str(&self.to_no_indent_string(interner, indentation));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Statement {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Block(b) => visitor.visit_block(b),
|
||||||
|
Self::Var(v) => visitor.visit_var_declaration(v),
|
||||||
|
Self::Empty => {
|
||||||
|
// do nothing; there is nothing to visit here
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
Self::Expression(e) => visitor.visit_expression(e),
|
||||||
|
Self::If(i) => visitor.visit_if(i),
|
||||||
|
Self::DoWhileLoop(dw) => visitor.visit_do_while_loop(dw),
|
||||||
|
Self::WhileLoop(w) => visitor.visit_while_loop(w),
|
||||||
|
Self::ForLoop(f) => visitor.visit_for_loop(f),
|
||||||
|
Self::ForInLoop(fi) => visitor.visit_for_in_loop(fi),
|
||||||
|
Self::ForOfLoop(fo) => visitor.visit_for_of_loop(fo),
|
||||||
|
Self::Switch(s) => visitor.visit_switch(s),
|
||||||
|
Self::Continue(c) => visitor.visit_continue(c),
|
||||||
|
Self::Break(b) => visitor.visit_break(b),
|
||||||
|
Self::Return(r) => visitor.visit_return(r),
|
||||||
|
Self::Labelled(l) => visitor.visit_labelled(l),
|
||||||
|
Self::Throw(th) => visitor.visit_throw(th),
|
||||||
|
Self::Try(tr) => visitor.visit_try(tr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Block(b) => visitor.visit_block_mut(b),
|
||||||
|
Self::Var(v) => visitor.visit_var_declaration_mut(v),
|
||||||
|
Self::Empty => {
|
||||||
|
// do nothing; there is nothing to visit here
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
Self::Expression(e) => visitor.visit_expression_mut(e),
|
||||||
|
Self::If(i) => visitor.visit_if_mut(i),
|
||||||
|
Self::DoWhileLoop(dw) => visitor.visit_do_while_loop_mut(dw),
|
||||||
|
Self::WhileLoop(w) => visitor.visit_while_loop_mut(w),
|
||||||
|
Self::ForLoop(f) => visitor.visit_for_loop_mut(f),
|
||||||
|
Self::ForInLoop(fi) => visitor.visit_for_in_loop_mut(fi),
|
||||||
|
Self::ForOfLoop(fo) => visitor.visit_for_of_loop_mut(fo),
|
||||||
|
Self::Switch(s) => visitor.visit_switch_mut(s),
|
||||||
|
Self::Continue(c) => visitor.visit_continue_mut(c),
|
||||||
|
Self::Break(b) => visitor.visit_break_mut(b),
|
||||||
|
Self::Return(r) => visitor.visit_return_mut(r),
|
||||||
|
Self::Labelled(l) => visitor.visit_labelled_mut(l),
|
||||||
|
Self::Throw(th) => visitor.visit_throw_mut(th),
|
||||||
|
Self::Try(tr) => visitor.visit_try_mut(tr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
javascript-engine/external/boa/boa_ast/src/statement/return.rs
vendored
Normal file
84
javascript-engine/external/boa/boa_ast/src/statement/return.rs
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::Statement,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `return` statement ends function execution and specifies a value to be returned to the
|
||||||
|
/// function caller.
|
||||||
|
///
|
||||||
|
/// Syntax: `return [expression];`
|
||||||
|
///
|
||||||
|
/// `expression`:
|
||||||
|
/// > The expression whose value is to be returned. If omitted, `undefined` is returned instead.
|
||||||
|
///
|
||||||
|
/// When a `return` statement is used in a function body, the execution of the function is
|
||||||
|
/// stopped. If specified, a given value is returned to the function caller.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Return {
|
||||||
|
target: Option<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Return {
|
||||||
|
/// Gets the target expression value of this `Return` statement.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> Option<&Expression> {
|
||||||
|
self.target.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `Return` AST node.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(expression: Option<Expression>) -> Self {
|
||||||
|
Self { target: expression }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Return> for Statement {
|
||||||
|
fn from(return_smt: Return) -> Self {
|
||||||
|
Self::Return(return_smt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Return {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
self.target().map_or_else(
|
||||||
|
|| "return".to_owned(),
|
||||||
|
|ex| format!("return {}", ex.to_interned_string(interner)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Return {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(expr) = &self.target {
|
||||||
|
visitor.visit_expression(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(expr) = &mut self.target {
|
||||||
|
visitor.visit_expression_mut(expr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
189
javascript-engine/external/boa/boa_ast/src/statement/switch.rs
vendored
Normal file
189
javascript-engine/external/boa/boa_ast/src/statement/switch.rs
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
//! Switch node.
|
||||||
|
//!
|
||||||
|
use crate::{
|
||||||
|
expression::Expression,
|
||||||
|
statement::Statement,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
StatementList,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// A case clause inside a [`Switch`] statement, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// Even though every [`Case`] body is a [`StatementList`], it doesn't create a new lexical
|
||||||
|
/// environment. This means any variable declared in a `Case` will be considered as part of the
|
||||||
|
/// lexical environment of the parent [`Switch`] block.
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-CaseClause
|
||||||
|
/// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Case {
|
||||||
|
condition: Expression,
|
||||||
|
body: StatementList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Case {
|
||||||
|
/// Creates a `Case` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(condition: Expression, body: StatementList) -> Self {
|
||||||
|
Self { condition, body }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the condition of the case.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn condition(&self) -> &Expression {
|
||||||
|
&self.condition
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the statement listin the body of the case.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn body(&self) -> &StatementList {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Case {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.condition));
|
||||||
|
visitor.visit_statement_list(&self.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.condition));
|
||||||
|
visitor.visit_statement_list_mut(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `switch` statement evaluates an expression, matching the expression's value to a case
|
||||||
|
/// clause, and executes statements associated with that case, as well as statements in cases
|
||||||
|
/// that follow the matching case.
|
||||||
|
///
|
||||||
|
/// A `switch` statement first evaluates its expression. It then looks for the first case
|
||||||
|
/// clause whose expression evaluates to the same value as the result of the input expression
|
||||||
|
/// (using the strict comparison, `===`) and transfers control to that clause, executing the
|
||||||
|
/// associated statements. (If multiple cases match the provided value, the first case that
|
||||||
|
/// matches is selected, even if the cases are not equal to each other.)
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Switch {
|
||||||
|
val: Expression,
|
||||||
|
cases: Box<[Case]>,
|
||||||
|
default: Option<StatementList>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Switch {
|
||||||
|
/// Creates a `Switch` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(val: Expression, cases: Box<[Case]>, default: Option<StatementList>) -> Self {
|
||||||
|
Self {
|
||||||
|
val,
|
||||||
|
cases,
|
||||||
|
default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the value to switch.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn val(&self) -> &Expression {
|
||||||
|
&self.val
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of cases for the switch statement.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cases(&self) -> &[Case] {
|
||||||
|
&self.cases
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the default statement list, if any.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn default(&self) -> Option<&StatementList> {
|
||||||
|
self.default.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Switch {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let indent = " ".repeat(indentation);
|
||||||
|
let mut buf = format!("switch ({}) {{\n", self.val().to_interned_string(interner));
|
||||||
|
for e in self.cases().iter() {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"{} case {}:\n{}",
|
||||||
|
indent,
|
||||||
|
e.condition().to_interned_string(interner),
|
||||||
|
e.body().to_indented_string(interner, indentation + 2)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref default) = self.default {
|
||||||
|
buf.push_str(&format!(
|
||||||
|
"{indent} default:\n{}",
|
||||||
|
default.to_indented_string(interner, indentation + 2)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!("{indent}}}"));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Switch> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(switch: Switch) -> Self {
|
||||||
|
Self::Switch(switch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Switch {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression(&self.val));
|
||||||
|
for case in self.cases.iter() {
|
||||||
|
try_break!(visitor.visit_case(case));
|
||||||
|
}
|
||||||
|
if let Some(sl) = &self.default {
|
||||||
|
try_break!(visitor.visit_statement_list(sl));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_expression_mut(&mut self.val));
|
||||||
|
for case in self.cases.iter_mut() {
|
||||||
|
try_break!(visitor.visit_case_mut(case));
|
||||||
|
}
|
||||||
|
if let Some(sl) = &mut self.default {
|
||||||
|
try_break!(visitor.visit_statement_list_mut(sl));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
70
javascript-engine/external/boa/boa_ast/src/statement/throw.rs
vendored
Normal file
70
javascript-engine/external/boa/boa_ast/src/statement/throw.rs
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
use crate::{
|
||||||
|
statement::Statement,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
Expression,
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `throw` statement throws a user-defined exception.
|
||||||
|
///
|
||||||
|
/// Syntax: `throw expression;`
|
||||||
|
///
|
||||||
|
/// Execution of the current function will stop (the statements after throw won't be executed),
|
||||||
|
/// and control will be passed to the first catch block in the call stack. If no catch block
|
||||||
|
/// exists among caller functions, the program will terminate.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-ThrowStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Throw {
|
||||||
|
target: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Throw {
|
||||||
|
/// Gets the target expression of this `Throw` statement.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn target(&self) -> &Expression {
|
||||||
|
&self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `Throw` AST node.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(target: Expression) -> Self {
|
||||||
|
Self { target }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToInternedString for Throw {
|
||||||
|
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||||
|
format!("throw {}", self.target.to_interned_string(interner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Throw> for Statement {
|
||||||
|
fn from(trw: Throw) -> Self {
|
||||||
|
Self::Throw(trw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Throw {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression(&self.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_expression_mut(&mut self.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
256
javascript-engine/external/boa/boa_ast/src/statement/try.rs
vendored
Normal file
256
javascript-engine/external/boa/boa_ast/src/statement/try.rs
vendored
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
//! Error handling statements
|
||||||
|
|
||||||
|
use crate::try_break;
|
||||||
|
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||||
|
use crate::{
|
||||||
|
declaration::Binding,
|
||||||
|
statement::{Block, Statement},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString, ToInternedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
/// The `try...catch` statement marks a block of statements to try and specifies a response
|
||||||
|
/// should an exception be thrown.
|
||||||
|
///
|
||||||
|
/// The `try` statement consists of a `try`-block, which contains one or more statements. `{}`
|
||||||
|
/// must always be used, even for single statements. At least one `catch`-block, or a
|
||||||
|
/// `finally`-block, must be present.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-TryStatement
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Try {
|
||||||
|
block: Block,
|
||||||
|
handler: ErrorHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of error handler in a [`Try`] statement.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ErrorHandler {
|
||||||
|
/// A [`Catch`] error handler.
|
||||||
|
Catch(Catch),
|
||||||
|
/// A [`Finally`] error handler.
|
||||||
|
Finally(Finally),
|
||||||
|
/// A [`Catch`] and [`Finally`] error handler.
|
||||||
|
Full(Catch, Finally),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Try {
|
||||||
|
/// Creates a new `Try` AST node.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(block: Block, handler: ErrorHandler) -> Self {
|
||||||
|
Self { block, handler }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `try` block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn block(&self) -> &Block {
|
||||||
|
&self.block
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `catch` block, if any.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn catch(&self) -> Option<&Catch> {
|
||||||
|
match &self.handler {
|
||||||
|
ErrorHandler::Catch(c) | ErrorHandler::Full(c, _) => Some(c),
|
||||||
|
ErrorHandler::Finally(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `finally` block, if any.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn finally(&self) -> Option<&Finally> {
|
||||||
|
match &self.handler {
|
||||||
|
ErrorHandler::Finally(f) | ErrorHandler::Full(_, f) => Some(f),
|
||||||
|
ErrorHandler::Catch(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Try {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = format!(
|
||||||
|
"{}try {}",
|
||||||
|
" ".repeat(indentation),
|
||||||
|
self.block.to_indented_string(interner, indentation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(catch) = self.catch() {
|
||||||
|
buf.push_str(&catch.to_indented_string(interner, indentation));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(finally) = self.finally() {
|
||||||
|
buf.push_str(&finally.to_indented_string(interner, indentation));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Try> for Statement {
|
||||||
|
#[inline]
|
||||||
|
fn from(try_catch: Try) -> Self {
|
||||||
|
Self::Try(try_catch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Try {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_block(&self.block));
|
||||||
|
if let Some(catch) = &self.catch() {
|
||||||
|
try_break!(visitor.visit_catch(catch));
|
||||||
|
}
|
||||||
|
if let Some(finally) = &self.finally() {
|
||||||
|
try_break!(visitor.visit_finally(finally));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
try_break!(visitor.visit_block_mut(&mut self.block));
|
||||||
|
match &mut self.handler {
|
||||||
|
ErrorHandler::Catch(c) => try_break!(visitor.visit_catch_mut(c)),
|
||||||
|
ErrorHandler::Finally(f) => try_break!(visitor.visit_finally_mut(f)),
|
||||||
|
ErrorHandler::Full(c, f) => {
|
||||||
|
try_break!(visitor.visit_catch_mut(c));
|
||||||
|
try_break!(visitor.visit_finally_mut(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Catch block.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Catch {
|
||||||
|
parameter: Option<Binding>,
|
||||||
|
block: Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Catch {
|
||||||
|
/// Creates a new catch block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(parameter: Option<Binding>, block: Block) -> Self {
|
||||||
|
Self { parameter, block }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the parameter of the catch block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parameter(&self) -> Option<&Binding> {
|
||||||
|
self.parameter.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the catch execution block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn block(&self) -> &Block {
|
||||||
|
&self.block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Catch {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = " catch".to_owned();
|
||||||
|
if let Some(ref param) = self.parameter {
|
||||||
|
buf.push_str(&format!("({})", param.to_interned_string(interner)));
|
||||||
|
}
|
||||||
|
buf.push_str(&format!(
|
||||||
|
" {}",
|
||||||
|
self.block.to_indented_string(interner, indentation)
|
||||||
|
));
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Catch {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
if let Some(binding) = &self.parameter {
|
||||||
|
try_break!(visitor.visit_binding(binding));
|
||||||
|
}
|
||||||
|
visitor.visit_block(&self.block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
if let Some(binding) = &mut self.parameter {
|
||||||
|
try_break!(visitor.visit_binding_mut(binding));
|
||||||
|
}
|
||||||
|
visitor.visit_block_mut(&mut self.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finally block.
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Finally {
|
||||||
|
block: Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Finally {
|
||||||
|
/// Gets the finally block.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn block(&self) -> &Block {
|
||||||
|
&self.block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for Finally {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
format!(
|
||||||
|
" finally {}",
|
||||||
|
self.block.to_indented_string(interner, indentation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Block> for Finally {
|
||||||
|
#[inline]
|
||||||
|
fn from(block: Block) -> Self {
|
||||||
|
Self { block }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for Finally {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_block(&self.block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
visitor.visit_block_mut(&mut self.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
215
javascript-engine/external/boa/boa_ast/src/statement_list.rs
vendored
Normal file
215
javascript-engine/external/boa/boa_ast/src/statement_list.rs
vendored
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
//! Statement list node.
|
||||||
|
|
||||||
|
use super::Declaration;
|
||||||
|
use crate::{
|
||||||
|
statement::Statement,
|
||||||
|
try_break,
|
||||||
|
visitor::{VisitWith, Visitor, VisitorMut},
|
||||||
|
};
|
||||||
|
use boa_interner::{Interner, ToIndentedString};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
/// An item inside a [`StatementList`] Parse Node, as defined by the [spec].
|
||||||
|
///
|
||||||
|
/// Items in a `StatementList` can be either [`Declaration`]s (functions, classes, let/const declarations)
|
||||||
|
/// or [`Statement`]s (if, while, var statement).
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-StatementListItem
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum StatementListItem {
|
||||||
|
/// See [`Statement`].
|
||||||
|
Statement(Statement),
|
||||||
|
/// See [`Declaration`].
|
||||||
|
Declaration(Declaration),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatementListItem {
|
||||||
|
/// Returns a node ordering based on the hoistability of each statement.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn hoistable_order(a: &Self, b: &Self) -> Ordering {
|
||||||
|
match (a, b) {
|
||||||
|
(
|
||||||
|
Self::Declaration(Declaration::Function(_)),
|
||||||
|
Self::Declaration(Declaration::Function(_)),
|
||||||
|
) => Ordering::Equal,
|
||||||
|
(_, Self::Declaration(Declaration::Function(_))) => Ordering::Greater,
|
||||||
|
(Self::Declaration(Declaration::Function(_)), _) => Ordering::Less,
|
||||||
|
|
||||||
|
(_, _) => Ordering::Equal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for StatementListItem {
|
||||||
|
/// Creates a string of the value of the node with the given indentation. For example, an
|
||||||
|
/// indent level of 2 would produce this:
|
||||||
|
///
|
||||||
|
/// ```js
|
||||||
|
/// function hello() {
|
||||||
|
/// console.log("hello");
|
||||||
|
/// }
|
||||||
|
/// hello();
|
||||||
|
/// a = 2;
|
||||||
|
/// ```
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = " ".repeat(indentation);
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Self::Statement(stmt) => {
|
||||||
|
buf.push_str(&stmt.to_no_indent_string(interner, indentation));
|
||||||
|
}
|
||||||
|
Self::Declaration(decl) => {
|
||||||
|
buf.push_str(&decl.to_indented_string(interner, indentation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Statement> for StatementListItem {
|
||||||
|
#[inline]
|
||||||
|
fn from(stmt: Statement) -> Self {
|
||||||
|
Self::Statement(stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Declaration> for StatementListItem {
|
||||||
|
#[inline]
|
||||||
|
fn from(decl: Declaration) -> Self {
|
||||||
|
Self::Declaration(decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for StatementListItem {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Statement(statement) => visitor.visit_statement(statement),
|
||||||
|
Self::Declaration(declaration) => visitor.visit_declaration(declaration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Statement(statement) => visitor.visit_statement_mut(statement),
|
||||||
|
Self::Declaration(declaration) => visitor.visit_declaration_mut(declaration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of statements.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#prod-StatementList
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
|
pub struct StatementList {
|
||||||
|
statements: Box<[StatementListItem]>,
|
||||||
|
strict: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatementList {
|
||||||
|
/// Creates a new `StatementList` AST node.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new<S>(statements: S, strict: bool) -> Self
|
||||||
|
where
|
||||||
|
S: Into<Box<[StatementListItem]>>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
statements: statements.into(),
|
||||||
|
strict,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list of statements.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn statements(&self) -> &[StatementListItem] {
|
||||||
|
&self.statements
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the strict mode.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn strict(&self) -> bool {
|
||||||
|
self.strict
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<[StatementListItem]>> for StatementList {
|
||||||
|
#[inline]
|
||||||
|
fn from(stm: Box<[StatementListItem]>) -> Self {
|
||||||
|
Self {
|
||||||
|
statements: stm,
|
||||||
|
strict: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<StatementListItem>> for StatementList {
|
||||||
|
#[inline]
|
||||||
|
fn from(stm: Vec<StatementListItem>) -> Self {
|
||||||
|
Self {
|
||||||
|
statements: stm.into(),
|
||||||
|
strict: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIndentedString for StatementList {
|
||||||
|
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
|
||||||
|
let mut buf = String::new();
|
||||||
|
// Print statements
|
||||||
|
for item in self.statements.iter() {
|
||||||
|
// We rely on the node to add the correct indent.
|
||||||
|
buf.push_str(&item.to_indented_string(interner, indentation));
|
||||||
|
|
||||||
|
buf.push('\n');
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitWith for StatementList {
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
for statement in self.statements.iter() {
|
||||||
|
try_break!(visitor.visit_statement_list_item(statement));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
for statement in self.statements.iter_mut() {
|
||||||
|
try_break!(visitor.visit_statement_list_item_mut(statement));
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fuzz")]
|
||||||
|
impl<'a> arbitrary::Arbitrary<'a> for StatementList {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
statements: u.arbitrary()?,
|
||||||
|
strict: false, // disable strictness; this is *not* in source data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
569
javascript-engine/external/boa/boa_ast/src/visitor.rs
vendored
Normal file
569
javascript-engine/external/boa/boa_ast/src/visitor.rs
vendored
Normal file
@@ -0,0 +1,569 @@
|
|||||||
|
//! ECMAScript Abstract Syntax Tree visitors.
|
||||||
|
//!
|
||||||
|
//! This module contains visitors which can be used to inspect or modify AST nodes. This allows for
|
||||||
|
//! fine-grained manipulation of ASTs for analysis, rewriting, or instrumentation.
|
||||||
|
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
declaration::{
|
||||||
|
Binding, Declaration, LexicalDeclaration, VarDeclaration, Variable, VariableList,
|
||||||
|
},
|
||||||
|
expression::{
|
||||||
|
access::{
|
||||||
|
PrivatePropertyAccess, PropertyAccess, PropertyAccessField, SimplePropertyAccess,
|
||||||
|
SuperPropertyAccess,
|
||||||
|
},
|
||||||
|
literal::{ArrayLiteral, Literal, ObjectLiteral, TemplateElement, TemplateLiteral},
|
||||||
|
operator::{
|
||||||
|
assign::{Assign, AssignTarget},
|
||||||
|
Binary, Conditional, Unary,
|
||||||
|
},
|
||||||
|
Await, Call, Expression, Identifier, New, Optional, OptionalOperation,
|
||||||
|
OptionalOperationKind, Spread, SuperCall, TaggedTemplate, Yield,
|
||||||
|
},
|
||||||
|
function::{
|
||||||
|
ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement,
|
||||||
|
FormalParameter, FormalParameterList, Function, Generator, PrivateName,
|
||||||
|
},
|
||||||
|
pattern::{ArrayPattern, ArrayPatternElement, ObjectPattern, ObjectPatternElement, Pattern},
|
||||||
|
property::{MethodDefinition, PropertyDefinition, PropertyName},
|
||||||
|
statement::{
|
||||||
|
iteration::{
|
||||||
|
Break, Continue, DoWhileLoop, ForInLoop, ForLoop, ForLoopInitializer, ForOfLoop,
|
||||||
|
IterableLoopInitializer, WhileLoop,
|
||||||
|
},
|
||||||
|
Block, Case, Catch, Finally, If, Labelled, LabelledItem, Return, Statement, Switch, Throw,
|
||||||
|
Try,
|
||||||
|
},
|
||||||
|
StatementList, StatementListItem,
|
||||||
|
};
|
||||||
|
use boa_interner::Sym;
|
||||||
|
|
||||||
|
/// `Try`-like conditional unwrapping of `ControlFlow`.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try_break {
|
||||||
|
($expr:expr) => {
|
||||||
|
match $expr {
|
||||||
|
core::ops::ControlFlow::Continue(c) => c,
|
||||||
|
core::ops::ControlFlow::Break(b) => return core::ops::ControlFlow::Break(b),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the default visit function implementation for a particular type
|
||||||
|
macro_rules! define_visit {
|
||||||
|
($fn_name:ident, $type_name:ident) => {
|
||||||
|
#[doc = concat!("Visits a `", stringify!($type_name), "` with this visitor")]
|
||||||
|
fn $fn_name(&mut self, node: &'ast $type_name) -> ControlFlow<Self::BreakTy> {
|
||||||
|
node.visit_with(self)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the default mutable visit function implementation for a particular type
|
||||||
|
macro_rules! define_visit_mut {
|
||||||
|
($fn_name:ident, $type_name:ident) => {
|
||||||
|
#[doc = concat!("Visits a `", stringify!($type_name), "` with this visitor, mutably")]
|
||||||
|
fn $fn_name(&mut self, node: &'ast mut $type_name) -> ControlFlow<Self::BreakTy> {
|
||||||
|
node.visit_with_mut(self)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates the `NodeRef` and `NodeMutRef` enums from a list of variants.
|
||||||
|
macro_rules! node_ref {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
$Variant:ident
|
||||||
|
),*
|
||||||
|
$(,)?
|
||||||
|
) => {
|
||||||
|
/// A reference to a node visitable by a [`Visitor`].
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum NodeRef<'a> {
|
||||||
|
$(
|
||||||
|
$Variant(&'a $Variant)
|
||||||
|
),*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl<'a> From<&'a $Variant> for NodeRef<'a> {
|
||||||
|
fn from(node: &'a $Variant) -> NodeRef<'a> {
|
||||||
|
Self::$Variant(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
/// A mutable reference to a node visitable by a [`VisitorMut`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum NodeRefMut<'a> {
|
||||||
|
$(
|
||||||
|
$Variant(&'a mut $Variant)
|
||||||
|
),*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl<'a> From<&'a mut $Variant> for NodeRefMut<'a> {
|
||||||
|
fn from(node: &'a mut $Variant) -> NodeRefMut<'a> {
|
||||||
|
Self::$Variant(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref! {
|
||||||
|
StatementList,
|
||||||
|
StatementListItem,
|
||||||
|
Statement,
|
||||||
|
Declaration,
|
||||||
|
Function,
|
||||||
|
Generator,
|
||||||
|
AsyncFunction,
|
||||||
|
AsyncGenerator,
|
||||||
|
Class,
|
||||||
|
LexicalDeclaration,
|
||||||
|
Block,
|
||||||
|
VarDeclaration,
|
||||||
|
Expression,
|
||||||
|
If,
|
||||||
|
DoWhileLoop,
|
||||||
|
WhileLoop,
|
||||||
|
ForLoop,
|
||||||
|
ForInLoop,
|
||||||
|
ForOfLoop,
|
||||||
|
Switch,
|
||||||
|
Continue,
|
||||||
|
Break,
|
||||||
|
Return,
|
||||||
|
Labelled,
|
||||||
|
Throw,
|
||||||
|
Try,
|
||||||
|
Identifier,
|
||||||
|
FormalParameterList,
|
||||||
|
ClassElement,
|
||||||
|
PrivateName,
|
||||||
|
VariableList,
|
||||||
|
Variable,
|
||||||
|
Binding,
|
||||||
|
Pattern,
|
||||||
|
Literal,
|
||||||
|
ArrayLiteral,
|
||||||
|
ObjectLiteral,
|
||||||
|
Spread,
|
||||||
|
ArrowFunction,
|
||||||
|
AsyncArrowFunction,
|
||||||
|
TemplateLiteral,
|
||||||
|
PropertyAccess,
|
||||||
|
New,
|
||||||
|
Call,
|
||||||
|
SuperCall,
|
||||||
|
Optional,
|
||||||
|
TaggedTemplate,
|
||||||
|
Assign,
|
||||||
|
Unary,
|
||||||
|
Binary,
|
||||||
|
Conditional,
|
||||||
|
Await,
|
||||||
|
Yield,
|
||||||
|
ForLoopInitializer,
|
||||||
|
IterableLoopInitializer,
|
||||||
|
Case,
|
||||||
|
Sym,
|
||||||
|
LabelledItem,
|
||||||
|
Catch,
|
||||||
|
Finally,
|
||||||
|
FormalParameter,
|
||||||
|
PropertyName,
|
||||||
|
MethodDefinition,
|
||||||
|
ObjectPattern,
|
||||||
|
ArrayPattern,
|
||||||
|
PropertyDefinition,
|
||||||
|
TemplateElement,
|
||||||
|
SimplePropertyAccess,
|
||||||
|
PrivatePropertyAccess,
|
||||||
|
SuperPropertyAccess,
|
||||||
|
OptionalOperation,
|
||||||
|
AssignTarget,
|
||||||
|
ObjectPatternElement,
|
||||||
|
ArrayPatternElement,
|
||||||
|
PropertyAccessField,
|
||||||
|
OptionalOperationKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents an AST visitor.
|
||||||
|
///
|
||||||
|
/// This implementation is based largely on [chalk](https://github.com/rust-lang/chalk/blob/23d39c90ceb9242fbd4c43e9368e813e7c2179f7/chalk-ir/src/visit.rs)'s
|
||||||
|
/// visitor pattern.
|
||||||
|
pub trait Visitor<'ast>: Sized {
|
||||||
|
/// Type which will be propagated from the visitor if completing early.
|
||||||
|
type BreakTy;
|
||||||
|
|
||||||
|
define_visit!(visit_statement_list, StatementList);
|
||||||
|
define_visit!(visit_statement_list_item, StatementListItem);
|
||||||
|
define_visit!(visit_statement, Statement);
|
||||||
|
define_visit!(visit_declaration, Declaration);
|
||||||
|
define_visit!(visit_function, Function);
|
||||||
|
define_visit!(visit_generator, Generator);
|
||||||
|
define_visit!(visit_async_function, AsyncFunction);
|
||||||
|
define_visit!(visit_async_generator, AsyncGenerator);
|
||||||
|
define_visit!(visit_class, Class);
|
||||||
|
define_visit!(visit_lexical_declaration, LexicalDeclaration);
|
||||||
|
define_visit!(visit_block, Block);
|
||||||
|
define_visit!(visit_var_declaration, VarDeclaration);
|
||||||
|
define_visit!(visit_expression, Expression);
|
||||||
|
define_visit!(visit_if, If);
|
||||||
|
define_visit!(visit_do_while_loop, DoWhileLoop);
|
||||||
|
define_visit!(visit_while_loop, WhileLoop);
|
||||||
|
define_visit!(visit_for_loop, ForLoop);
|
||||||
|
define_visit!(visit_for_in_loop, ForInLoop);
|
||||||
|
define_visit!(visit_for_of_loop, ForOfLoop);
|
||||||
|
define_visit!(visit_switch, Switch);
|
||||||
|
define_visit!(visit_continue, Continue);
|
||||||
|
define_visit!(visit_break, Break);
|
||||||
|
define_visit!(visit_return, Return);
|
||||||
|
define_visit!(visit_labelled, Labelled);
|
||||||
|
define_visit!(visit_throw, Throw);
|
||||||
|
define_visit!(visit_try, Try);
|
||||||
|
define_visit!(visit_identifier, Identifier);
|
||||||
|
define_visit!(visit_formal_parameter_list, FormalParameterList);
|
||||||
|
define_visit!(visit_class_element, ClassElement);
|
||||||
|
define_visit!(visit_private_name, PrivateName);
|
||||||
|
define_visit!(visit_variable_list, VariableList);
|
||||||
|
define_visit!(visit_variable, Variable);
|
||||||
|
define_visit!(visit_binding, Binding);
|
||||||
|
define_visit!(visit_pattern, Pattern);
|
||||||
|
define_visit!(visit_literal, Literal);
|
||||||
|
define_visit!(visit_array_literal, ArrayLiteral);
|
||||||
|
define_visit!(visit_object_literal, ObjectLiteral);
|
||||||
|
define_visit!(visit_spread, Spread);
|
||||||
|
define_visit!(visit_arrow_function, ArrowFunction);
|
||||||
|
define_visit!(visit_async_arrow_function, AsyncArrowFunction);
|
||||||
|
define_visit!(visit_template_literal, TemplateLiteral);
|
||||||
|
define_visit!(visit_property_access, PropertyAccess);
|
||||||
|
define_visit!(visit_new, New);
|
||||||
|
define_visit!(visit_call, Call);
|
||||||
|
define_visit!(visit_super_call, SuperCall);
|
||||||
|
define_visit!(visit_optional, Optional);
|
||||||
|
define_visit!(visit_tagged_template, TaggedTemplate);
|
||||||
|
define_visit!(visit_assign, Assign);
|
||||||
|
define_visit!(visit_unary, Unary);
|
||||||
|
define_visit!(visit_binary, Binary);
|
||||||
|
define_visit!(visit_conditional, Conditional);
|
||||||
|
define_visit!(visit_await, Await);
|
||||||
|
define_visit!(visit_yield, Yield);
|
||||||
|
define_visit!(visit_for_loop_initializer, ForLoopInitializer);
|
||||||
|
define_visit!(visit_iterable_loop_initializer, IterableLoopInitializer);
|
||||||
|
define_visit!(visit_case, Case);
|
||||||
|
define_visit!(visit_sym, Sym);
|
||||||
|
define_visit!(visit_labelled_item, LabelledItem);
|
||||||
|
define_visit!(visit_catch, Catch);
|
||||||
|
define_visit!(visit_finally, Finally);
|
||||||
|
define_visit!(visit_formal_parameter, FormalParameter);
|
||||||
|
define_visit!(visit_property_name, PropertyName);
|
||||||
|
define_visit!(visit_method_definition, MethodDefinition);
|
||||||
|
define_visit!(visit_object_pattern, ObjectPattern);
|
||||||
|
define_visit!(visit_array_pattern, ArrayPattern);
|
||||||
|
define_visit!(visit_property_definition, PropertyDefinition);
|
||||||
|
define_visit!(visit_template_element, TemplateElement);
|
||||||
|
define_visit!(visit_simple_property_access, SimplePropertyAccess);
|
||||||
|
define_visit!(visit_private_property_access, PrivatePropertyAccess);
|
||||||
|
define_visit!(visit_super_property_access, SuperPropertyAccess);
|
||||||
|
define_visit!(visit_optional_operation, OptionalOperation);
|
||||||
|
define_visit!(visit_assign_target, AssignTarget);
|
||||||
|
define_visit!(visit_object_pattern_element, ObjectPatternElement);
|
||||||
|
define_visit!(visit_array_pattern_element, ArrayPatternElement);
|
||||||
|
define_visit!(visit_property_access_field, PropertyAccessField);
|
||||||
|
define_visit!(visit_optional_operation_kind, OptionalOperationKind);
|
||||||
|
|
||||||
|
/// Generic entry point for a node that is visitable by a `Visitor`.
|
||||||
|
///
|
||||||
|
/// This is usually used for generic functions that need to visit an unnamed AST node.
|
||||||
|
fn visit<N: Into<NodeRef<'ast>>>(&mut self, node: N) -> ControlFlow<Self::BreakTy> {
|
||||||
|
let node = node.into();
|
||||||
|
match node {
|
||||||
|
NodeRef::StatementList(n) => self.visit_statement_list(n),
|
||||||
|
NodeRef::StatementListItem(n) => self.visit_statement_list_item(n),
|
||||||
|
NodeRef::Statement(n) => self.visit_statement(n),
|
||||||
|
NodeRef::Declaration(n) => self.visit_declaration(n),
|
||||||
|
NodeRef::Function(n) => self.visit_function(n),
|
||||||
|
NodeRef::Generator(n) => self.visit_generator(n),
|
||||||
|
NodeRef::AsyncFunction(n) => self.visit_async_function(n),
|
||||||
|
NodeRef::AsyncGenerator(n) => self.visit_async_generator(n),
|
||||||
|
NodeRef::Class(n) => self.visit_class(n),
|
||||||
|
NodeRef::LexicalDeclaration(n) => self.visit_lexical_declaration(n),
|
||||||
|
NodeRef::Block(n) => self.visit_block(n),
|
||||||
|
NodeRef::VarDeclaration(n) => self.visit_var_declaration(n),
|
||||||
|
NodeRef::Expression(n) => self.visit_expression(n),
|
||||||
|
NodeRef::If(n) => self.visit_if(n),
|
||||||
|
NodeRef::DoWhileLoop(n) => self.visit_do_while_loop(n),
|
||||||
|
NodeRef::WhileLoop(n) => self.visit_while_loop(n),
|
||||||
|
NodeRef::ForLoop(n) => self.visit_for_loop(n),
|
||||||
|
NodeRef::ForInLoop(n) => self.visit_for_in_loop(n),
|
||||||
|
NodeRef::ForOfLoop(n) => self.visit_for_of_loop(n),
|
||||||
|
NodeRef::Switch(n) => self.visit_switch(n),
|
||||||
|
NodeRef::Continue(n) => self.visit_continue(n),
|
||||||
|
NodeRef::Break(n) => self.visit_break(n),
|
||||||
|
NodeRef::Return(n) => self.visit_return(n),
|
||||||
|
NodeRef::Labelled(n) => self.visit_labelled(n),
|
||||||
|
NodeRef::Throw(n) => self.visit_throw(n),
|
||||||
|
NodeRef::Try(n) => self.visit_try(n),
|
||||||
|
NodeRef::Identifier(n) => self.visit_identifier(n),
|
||||||
|
NodeRef::FormalParameterList(n) => self.visit_formal_parameter_list(n),
|
||||||
|
NodeRef::ClassElement(n) => self.visit_class_element(n),
|
||||||
|
NodeRef::PrivateName(n) => self.visit_private_name(n),
|
||||||
|
NodeRef::VariableList(n) => self.visit_variable_list(n),
|
||||||
|
NodeRef::Variable(n) => self.visit_variable(n),
|
||||||
|
NodeRef::Binding(n) => self.visit_binding(n),
|
||||||
|
NodeRef::Pattern(n) => self.visit_pattern(n),
|
||||||
|
NodeRef::Literal(n) => self.visit_literal(n),
|
||||||
|
NodeRef::ArrayLiteral(n) => self.visit_array_literal(n),
|
||||||
|
NodeRef::ObjectLiteral(n) => self.visit_object_literal(n),
|
||||||
|
NodeRef::Spread(n) => self.visit_spread(n),
|
||||||
|
NodeRef::ArrowFunction(n) => self.visit_arrow_function(n),
|
||||||
|
NodeRef::AsyncArrowFunction(n) => self.visit_async_arrow_function(n),
|
||||||
|
NodeRef::TemplateLiteral(n) => self.visit_template_literal(n),
|
||||||
|
NodeRef::PropertyAccess(n) => self.visit_property_access(n),
|
||||||
|
NodeRef::New(n) => self.visit_new(n),
|
||||||
|
NodeRef::Call(n) => self.visit_call(n),
|
||||||
|
NodeRef::SuperCall(n) => self.visit_super_call(n),
|
||||||
|
NodeRef::Optional(n) => self.visit_optional(n),
|
||||||
|
NodeRef::TaggedTemplate(n) => self.visit_tagged_template(n),
|
||||||
|
NodeRef::Assign(n) => self.visit_assign(n),
|
||||||
|
NodeRef::Unary(n) => self.visit_unary(n),
|
||||||
|
NodeRef::Binary(n) => self.visit_binary(n),
|
||||||
|
NodeRef::Conditional(n) => self.visit_conditional(n),
|
||||||
|
NodeRef::Await(n) => self.visit_await(n),
|
||||||
|
NodeRef::Yield(n) => self.visit_yield(n),
|
||||||
|
NodeRef::ForLoopInitializer(n) => self.visit_for_loop_initializer(n),
|
||||||
|
NodeRef::IterableLoopInitializer(n) => self.visit_iterable_loop_initializer(n),
|
||||||
|
NodeRef::Case(n) => self.visit_case(n),
|
||||||
|
NodeRef::Sym(n) => self.visit_sym(n),
|
||||||
|
NodeRef::LabelledItem(n) => self.visit_labelled_item(n),
|
||||||
|
NodeRef::Catch(n) => self.visit_catch(n),
|
||||||
|
NodeRef::Finally(n) => self.visit_finally(n),
|
||||||
|
NodeRef::FormalParameter(n) => self.visit_formal_parameter(n),
|
||||||
|
NodeRef::PropertyName(n) => self.visit_property_name(n),
|
||||||
|
NodeRef::MethodDefinition(n) => self.visit_method_definition(n),
|
||||||
|
NodeRef::ObjectPattern(n) => self.visit_object_pattern(n),
|
||||||
|
NodeRef::ArrayPattern(n) => self.visit_array_pattern(n),
|
||||||
|
NodeRef::PropertyDefinition(n) => self.visit_property_definition(n),
|
||||||
|
NodeRef::TemplateElement(n) => self.visit_template_element(n),
|
||||||
|
NodeRef::SimplePropertyAccess(n) => self.visit_simple_property_access(n),
|
||||||
|
NodeRef::PrivatePropertyAccess(n) => self.visit_private_property_access(n),
|
||||||
|
NodeRef::SuperPropertyAccess(n) => self.visit_super_property_access(n),
|
||||||
|
NodeRef::OptionalOperation(n) => self.visit_optional_operation(n),
|
||||||
|
NodeRef::AssignTarget(n) => self.visit_assign_target(n),
|
||||||
|
NodeRef::ObjectPatternElement(n) => self.visit_object_pattern_element(n),
|
||||||
|
NodeRef::ArrayPatternElement(n) => self.visit_array_pattern_element(n),
|
||||||
|
NodeRef::PropertyAccessField(n) => self.visit_property_access_field(n),
|
||||||
|
NodeRef::OptionalOperationKind(n) => self.visit_optional_operation_kind(n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents an AST visitor which can modify AST content.
|
||||||
|
///
|
||||||
|
/// This implementation is based largely on [chalk](https://github.com/rust-lang/chalk/blob/23d39c90ceb9242fbd4c43e9368e813e7c2179f7/chalk-ir/src/visit.rs)'s
|
||||||
|
/// visitor pattern.
|
||||||
|
pub trait VisitorMut<'ast>: Sized {
|
||||||
|
/// Type which will be propagated from the visitor if completing early.
|
||||||
|
type BreakTy;
|
||||||
|
|
||||||
|
define_visit_mut!(visit_statement_list_mut, StatementList);
|
||||||
|
define_visit_mut!(visit_statement_list_item_mut, StatementListItem);
|
||||||
|
define_visit_mut!(visit_statement_mut, Statement);
|
||||||
|
define_visit_mut!(visit_declaration_mut, Declaration);
|
||||||
|
define_visit_mut!(visit_function_mut, Function);
|
||||||
|
define_visit_mut!(visit_generator_mut, Generator);
|
||||||
|
define_visit_mut!(visit_async_function_mut, AsyncFunction);
|
||||||
|
define_visit_mut!(visit_async_generator_mut, AsyncGenerator);
|
||||||
|
define_visit_mut!(visit_class_mut, Class);
|
||||||
|
define_visit_mut!(visit_lexical_declaration_mut, LexicalDeclaration);
|
||||||
|
define_visit_mut!(visit_block_mut, Block);
|
||||||
|
define_visit_mut!(visit_var_declaration_mut, VarDeclaration);
|
||||||
|
define_visit_mut!(visit_expression_mut, Expression);
|
||||||
|
define_visit_mut!(visit_if_mut, If);
|
||||||
|
define_visit_mut!(visit_do_while_loop_mut, DoWhileLoop);
|
||||||
|
define_visit_mut!(visit_while_loop_mut, WhileLoop);
|
||||||
|
define_visit_mut!(visit_for_loop_mut, ForLoop);
|
||||||
|
define_visit_mut!(visit_for_in_loop_mut, ForInLoop);
|
||||||
|
define_visit_mut!(visit_for_of_loop_mut, ForOfLoop);
|
||||||
|
define_visit_mut!(visit_switch_mut, Switch);
|
||||||
|
define_visit_mut!(visit_continue_mut, Continue);
|
||||||
|
define_visit_mut!(visit_break_mut, Break);
|
||||||
|
define_visit_mut!(visit_return_mut, Return);
|
||||||
|
define_visit_mut!(visit_labelled_mut, Labelled);
|
||||||
|
define_visit_mut!(visit_throw_mut, Throw);
|
||||||
|
define_visit_mut!(visit_try_mut, Try);
|
||||||
|
define_visit_mut!(visit_identifier_mut, Identifier);
|
||||||
|
define_visit_mut!(visit_formal_parameter_list_mut, FormalParameterList);
|
||||||
|
define_visit_mut!(visit_class_element_mut, ClassElement);
|
||||||
|
define_visit_mut!(visit_private_name_mut, PrivateName);
|
||||||
|
define_visit_mut!(visit_variable_list_mut, VariableList);
|
||||||
|
define_visit_mut!(visit_variable_mut, Variable);
|
||||||
|
define_visit_mut!(visit_binding_mut, Binding);
|
||||||
|
define_visit_mut!(visit_pattern_mut, Pattern);
|
||||||
|
define_visit_mut!(visit_literal_mut, Literal);
|
||||||
|
define_visit_mut!(visit_array_literal_mut, ArrayLiteral);
|
||||||
|
define_visit_mut!(visit_object_literal_mut, ObjectLiteral);
|
||||||
|
define_visit_mut!(visit_spread_mut, Spread);
|
||||||
|
define_visit_mut!(visit_arrow_function_mut, ArrowFunction);
|
||||||
|
define_visit_mut!(visit_async_arrow_function_mut, AsyncArrowFunction);
|
||||||
|
define_visit_mut!(visit_template_literal_mut, TemplateLiteral);
|
||||||
|
define_visit_mut!(visit_property_access_mut, PropertyAccess);
|
||||||
|
define_visit_mut!(visit_new_mut, New);
|
||||||
|
define_visit_mut!(visit_call_mut, Call);
|
||||||
|
define_visit_mut!(visit_super_call_mut, SuperCall);
|
||||||
|
define_visit_mut!(visit_optional_mut, Optional);
|
||||||
|
define_visit_mut!(visit_tagged_template_mut, TaggedTemplate);
|
||||||
|
define_visit_mut!(visit_assign_mut, Assign);
|
||||||
|
define_visit_mut!(visit_unary_mut, Unary);
|
||||||
|
define_visit_mut!(visit_binary_mut, Binary);
|
||||||
|
define_visit_mut!(visit_conditional_mut, Conditional);
|
||||||
|
define_visit_mut!(visit_await_mut, Await);
|
||||||
|
define_visit_mut!(visit_yield_mut, Yield);
|
||||||
|
define_visit_mut!(visit_for_loop_initializer_mut, ForLoopInitializer);
|
||||||
|
define_visit_mut!(visit_iterable_loop_initializer_mut, IterableLoopInitializer);
|
||||||
|
define_visit_mut!(visit_case_mut, Case);
|
||||||
|
define_visit_mut!(visit_sym_mut, Sym);
|
||||||
|
define_visit_mut!(visit_labelled_item_mut, LabelledItem);
|
||||||
|
define_visit_mut!(visit_catch_mut, Catch);
|
||||||
|
define_visit_mut!(visit_finally_mut, Finally);
|
||||||
|
define_visit_mut!(visit_formal_parameter_mut, FormalParameter);
|
||||||
|
define_visit_mut!(visit_property_name_mut, PropertyName);
|
||||||
|
define_visit_mut!(visit_method_definition_mut, MethodDefinition);
|
||||||
|
define_visit_mut!(visit_object_pattern_mut, ObjectPattern);
|
||||||
|
define_visit_mut!(visit_array_pattern_mut, ArrayPattern);
|
||||||
|
define_visit_mut!(visit_property_definition_mut, PropertyDefinition);
|
||||||
|
define_visit_mut!(visit_template_element_mut, TemplateElement);
|
||||||
|
define_visit_mut!(visit_simple_property_access_mut, SimplePropertyAccess);
|
||||||
|
define_visit_mut!(visit_private_property_access_mut, PrivatePropertyAccess);
|
||||||
|
define_visit_mut!(visit_super_property_access_mut, SuperPropertyAccess);
|
||||||
|
define_visit_mut!(visit_optional_operation_mut, OptionalOperation);
|
||||||
|
define_visit_mut!(visit_assign_target_mut, AssignTarget);
|
||||||
|
define_visit_mut!(visit_object_pattern_element_mut, ObjectPatternElement);
|
||||||
|
define_visit_mut!(visit_array_pattern_element_mut, ArrayPatternElement);
|
||||||
|
define_visit_mut!(visit_property_access_field_mut, PropertyAccessField);
|
||||||
|
define_visit_mut!(visit_optional_operation_kind_mut, OptionalOperationKind);
|
||||||
|
|
||||||
|
/// Generic entry point for a node that is visitable by a `VisitorMut`.
|
||||||
|
///
|
||||||
|
/// This is usually used for generic functions that need to visit an unnamed AST node.
|
||||||
|
fn visit<N: Into<NodeRefMut<'ast>>>(&mut self, node: N) -> ControlFlow<Self::BreakTy> {
|
||||||
|
let node = node.into();
|
||||||
|
match node {
|
||||||
|
NodeRefMut::StatementList(n) => self.visit_statement_list_mut(n),
|
||||||
|
NodeRefMut::StatementListItem(n) => self.visit_statement_list_item_mut(n),
|
||||||
|
NodeRefMut::Statement(n) => self.visit_statement_mut(n),
|
||||||
|
NodeRefMut::Declaration(n) => self.visit_declaration_mut(n),
|
||||||
|
NodeRefMut::Function(n) => self.visit_function_mut(n),
|
||||||
|
NodeRefMut::Generator(n) => self.visit_generator_mut(n),
|
||||||
|
NodeRefMut::AsyncFunction(n) => self.visit_async_function_mut(n),
|
||||||
|
NodeRefMut::AsyncGenerator(n) => self.visit_async_generator_mut(n),
|
||||||
|
NodeRefMut::Class(n) => self.visit_class_mut(n),
|
||||||
|
NodeRefMut::LexicalDeclaration(n) => self.visit_lexical_declaration_mut(n),
|
||||||
|
NodeRefMut::Block(n) => self.visit_block_mut(n),
|
||||||
|
NodeRefMut::VarDeclaration(n) => self.visit_var_declaration_mut(n),
|
||||||
|
NodeRefMut::Expression(n) => self.visit_expression_mut(n),
|
||||||
|
NodeRefMut::If(n) => self.visit_if_mut(n),
|
||||||
|
NodeRefMut::DoWhileLoop(n) => self.visit_do_while_loop_mut(n),
|
||||||
|
NodeRefMut::WhileLoop(n) => self.visit_while_loop_mut(n),
|
||||||
|
NodeRefMut::ForLoop(n) => self.visit_for_loop_mut(n),
|
||||||
|
NodeRefMut::ForInLoop(n) => self.visit_for_in_loop_mut(n),
|
||||||
|
NodeRefMut::ForOfLoop(n) => self.visit_for_of_loop_mut(n),
|
||||||
|
NodeRefMut::Switch(n) => self.visit_switch_mut(n),
|
||||||
|
NodeRefMut::Continue(n) => self.visit_continue_mut(n),
|
||||||
|
NodeRefMut::Break(n) => self.visit_break_mut(n),
|
||||||
|
NodeRefMut::Return(n) => self.visit_return_mut(n),
|
||||||
|
NodeRefMut::Labelled(n) => self.visit_labelled_mut(n),
|
||||||
|
NodeRefMut::Throw(n) => self.visit_throw_mut(n),
|
||||||
|
NodeRefMut::Try(n) => self.visit_try_mut(n),
|
||||||
|
NodeRefMut::Identifier(n) => self.visit_identifier_mut(n),
|
||||||
|
NodeRefMut::FormalParameterList(n) => self.visit_formal_parameter_list_mut(n),
|
||||||
|
NodeRefMut::ClassElement(n) => self.visit_class_element_mut(n),
|
||||||
|
NodeRefMut::PrivateName(n) => self.visit_private_name_mut(n),
|
||||||
|
NodeRefMut::VariableList(n) => self.visit_variable_list_mut(n),
|
||||||
|
NodeRefMut::Variable(n) => self.visit_variable_mut(n),
|
||||||
|
NodeRefMut::Binding(n) => self.visit_binding_mut(n),
|
||||||
|
NodeRefMut::Pattern(n) => self.visit_pattern_mut(n),
|
||||||
|
NodeRefMut::Literal(n) => self.visit_literal_mut(n),
|
||||||
|
NodeRefMut::ArrayLiteral(n) => self.visit_array_literal_mut(n),
|
||||||
|
NodeRefMut::ObjectLiteral(n) => self.visit_object_literal_mut(n),
|
||||||
|
NodeRefMut::Spread(n) => self.visit_spread_mut(n),
|
||||||
|
NodeRefMut::ArrowFunction(n) => self.visit_arrow_function_mut(n),
|
||||||
|
NodeRefMut::AsyncArrowFunction(n) => self.visit_async_arrow_function_mut(n),
|
||||||
|
NodeRefMut::TemplateLiteral(n) => self.visit_template_literal_mut(n),
|
||||||
|
NodeRefMut::PropertyAccess(n) => self.visit_property_access_mut(n),
|
||||||
|
NodeRefMut::New(n) => self.visit_new_mut(n),
|
||||||
|
NodeRefMut::Call(n) => self.visit_call_mut(n),
|
||||||
|
NodeRefMut::SuperCall(n) => self.visit_super_call_mut(n),
|
||||||
|
NodeRefMut::Optional(n) => self.visit_optional_mut(n),
|
||||||
|
NodeRefMut::TaggedTemplate(n) => self.visit_tagged_template_mut(n),
|
||||||
|
NodeRefMut::Assign(n) => self.visit_assign_mut(n),
|
||||||
|
NodeRefMut::Unary(n) => self.visit_unary_mut(n),
|
||||||
|
NodeRefMut::Binary(n) => self.visit_binary_mut(n),
|
||||||
|
NodeRefMut::Conditional(n) => self.visit_conditional_mut(n),
|
||||||
|
NodeRefMut::Await(n) => self.visit_await_mut(n),
|
||||||
|
NodeRefMut::Yield(n) => self.visit_yield_mut(n),
|
||||||
|
NodeRefMut::ForLoopInitializer(n) => self.visit_for_loop_initializer_mut(n),
|
||||||
|
NodeRefMut::IterableLoopInitializer(n) => self.visit_iterable_loop_initializer_mut(n),
|
||||||
|
NodeRefMut::Case(n) => self.visit_case_mut(n),
|
||||||
|
NodeRefMut::Sym(n) => self.visit_sym_mut(n),
|
||||||
|
NodeRefMut::LabelledItem(n) => self.visit_labelled_item_mut(n),
|
||||||
|
NodeRefMut::Catch(n) => self.visit_catch_mut(n),
|
||||||
|
NodeRefMut::Finally(n) => self.visit_finally_mut(n),
|
||||||
|
NodeRefMut::FormalParameter(n) => self.visit_formal_parameter_mut(n),
|
||||||
|
NodeRefMut::PropertyName(n) => self.visit_property_name_mut(n),
|
||||||
|
NodeRefMut::MethodDefinition(n) => self.visit_method_definition_mut(n),
|
||||||
|
NodeRefMut::ObjectPattern(n) => self.visit_object_pattern_mut(n),
|
||||||
|
NodeRefMut::ArrayPattern(n) => self.visit_array_pattern_mut(n),
|
||||||
|
NodeRefMut::PropertyDefinition(n) => self.visit_property_definition_mut(n),
|
||||||
|
NodeRefMut::TemplateElement(n) => self.visit_template_element_mut(n),
|
||||||
|
NodeRefMut::SimplePropertyAccess(n) => self.visit_simple_property_access_mut(n),
|
||||||
|
NodeRefMut::PrivatePropertyAccess(n) => self.visit_private_property_access_mut(n),
|
||||||
|
NodeRefMut::SuperPropertyAccess(n) => self.visit_super_property_access_mut(n),
|
||||||
|
NodeRefMut::OptionalOperation(n) => self.visit_optional_operation_mut(n),
|
||||||
|
NodeRefMut::AssignTarget(n) => self.visit_assign_target_mut(n),
|
||||||
|
NodeRefMut::ObjectPatternElement(n) => self.visit_object_pattern_element_mut(n),
|
||||||
|
NodeRefMut::ArrayPatternElement(n) => self.visit_array_pattern_element_mut(n),
|
||||||
|
NodeRefMut::PropertyAccessField(n) => self.visit_property_access_field_mut(n),
|
||||||
|
NodeRefMut::OptionalOperationKind(n) => self.visit_optional_operation_kind_mut(n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Denotes that a type may be visited, providing a method which allows a visitor to traverse its
|
||||||
|
/// private fields.
|
||||||
|
pub trait VisitWith {
|
||||||
|
/// Visit this node with the provided visitor.
|
||||||
|
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>;
|
||||||
|
|
||||||
|
/// Visit this node with the provided visitor mutably, allowing the visitor to modify private
|
||||||
|
/// fields.
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementation for Sym as it is out-of-crate
|
||||||
|
impl VisitWith for Sym {
|
||||||
|
fn visit_with<'a, V>(&'a self, _visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: Visitor<'a>,
|
||||||
|
{
|
||||||
|
core::ops::ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_with_mut<'a, V>(&'a mut self, _visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||||
|
where
|
||||||
|
V: VisitorMut<'a>,
|
||||||
|
{
|
||||||
|
core::ops::ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
36
javascript-engine/external/boa/boa_cli/Cargo.toml
vendored
Normal file
36
javascript-engine/external/boa/boa_cli/Cargo.toml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
[package]
|
||||||
|
name = "boa_cli"
|
||||||
|
keywords = ["javascript", "compiler", "js", "cli"]
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
default-run = "boa"
|
||||||
|
description.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
boa_engine = { workspace = true, features = ["deser", "console", "flowgraph"] }
|
||||||
|
boa_ast = { workspace = true, features = ["serde"]}
|
||||||
|
boa_parser.workspace = true
|
||||||
|
rustyline = "10.1.1"
|
||||||
|
rustyline-derive = "0.7.0"
|
||||||
|
clap = { version = "4.1.1", features = ["derive"] }
|
||||||
|
serde_json = "1.0.91"
|
||||||
|
colored = "2.0.0"
|
||||||
|
regex = "1.7.1"
|
||||||
|
phf = { version = "0.11.1", features = ["macros"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["intl"]
|
||||||
|
intl = ["boa_engine/intl"]
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu.dependencies]
|
||||||
|
jemallocator = "0.5.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "boa"
|
||||||
|
doc = false
|
||||||
|
path = "src/main.rs"
|
||||||
172
javascript-engine/external/boa/boa_cli/src/helper.rs
vendored
Normal file
172
javascript-engine/external/boa/boa_cli/src/helper.rs
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
use colored::{Color, Colorize};
|
||||||
|
use phf::{phf_set, Set};
|
||||||
|
use regex::{Captures, Regex};
|
||||||
|
use rustyline::{
|
||||||
|
error::ReadlineError,
|
||||||
|
highlight::Highlighter,
|
||||||
|
validate::{MatchingBracketValidator, ValidationContext, ValidationResult, Validator},
|
||||||
|
};
|
||||||
|
use rustyline_derive::{Completer, Helper, Hinter};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
const STRING_COLOR: Color = Color::Green;
|
||||||
|
const KEYWORD_COLOR: Color = Color::Yellow;
|
||||||
|
const PROPERTY_COLOR: Color = Color::Magenta;
|
||||||
|
const OPERATOR_COLOR: Color = Color::TrueColor {
|
||||||
|
r: 214,
|
||||||
|
g: 95,
|
||||||
|
b: 26,
|
||||||
|
};
|
||||||
|
const UNDEFINED_COLOR: Color = Color::TrueColor {
|
||||||
|
r: 100,
|
||||||
|
g: 100,
|
||||||
|
b: 100,
|
||||||
|
};
|
||||||
|
const NUMBER_COLOR: Color = Color::TrueColor {
|
||||||
|
r: 26,
|
||||||
|
g: 214,
|
||||||
|
b: 175,
|
||||||
|
};
|
||||||
|
const IDENTIFIER_COLOR: Color = Color::TrueColor {
|
||||||
|
r: 26,
|
||||||
|
g: 160,
|
||||||
|
b: 214,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
#[derive(Completer, Helper, Hinter)]
|
||||||
|
pub(crate) struct RLHelper {
|
||||||
|
highlighter: LineHighlighter,
|
||||||
|
validator: MatchingBracketValidator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RLHelper {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
highlighter: LineHighlighter,
|
||||||
|
validator: MatchingBracketValidator::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Validator for RLHelper {
|
||||||
|
fn validate(
|
||||||
|
&self,
|
||||||
|
context: &mut ValidationContext<'_>,
|
||||||
|
) -> Result<ValidationResult, ReadlineError> {
|
||||||
|
self.validator.validate(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_while_typing(&self) -> bool {
|
||||||
|
self.validator.validate_while_typing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Highlighter for RLHelper {
|
||||||
|
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
||||||
|
hint.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
|
||||||
|
self.highlighter.highlight(line, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_candidate<'c>(
|
||||||
|
&self,
|
||||||
|
candidate: &'c str,
|
||||||
|
_completion: rustyline::CompletionType,
|
||||||
|
) -> Cow<'c, str> {
|
||||||
|
self.highlighter.highlight(candidate, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_char(&self, line: &str, _: usize) -> bool {
|
||||||
|
!line.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static KEYWORDS: Set<&'static str> = phf_set! {
|
||||||
|
"break",
|
||||||
|
"case",
|
||||||
|
"catch",
|
||||||
|
"class",
|
||||||
|
"const",
|
||||||
|
"continue",
|
||||||
|
"default",
|
||||||
|
"delete",
|
||||||
|
"do",
|
||||||
|
"else",
|
||||||
|
"export",
|
||||||
|
"extends",
|
||||||
|
"finally",
|
||||||
|
"for",
|
||||||
|
"function",
|
||||||
|
"if",
|
||||||
|
"import",
|
||||||
|
"instanceof",
|
||||||
|
"new",
|
||||||
|
"return",
|
||||||
|
"super",
|
||||||
|
"switch",
|
||||||
|
"this",
|
||||||
|
"throw",
|
||||||
|
"try",
|
||||||
|
"typeof",
|
||||||
|
"var",
|
||||||
|
"void",
|
||||||
|
"while",
|
||||||
|
"with",
|
||||||
|
"yield",
|
||||||
|
"await",
|
||||||
|
"enum",
|
||||||
|
"let",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LineHighlighter;
|
||||||
|
|
||||||
|
impl Highlighter for LineHighlighter {
|
||||||
|
fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> {
|
||||||
|
let mut coloured = line.to_string();
|
||||||
|
|
||||||
|
let reg = Regex::new(
|
||||||
|
r#"(?x)
|
||||||
|
(?P<identifier>\b[$_\p{ID_Start}][$_\p{ID_Continue}\u{200C}\u{200D}]*\b) |
|
||||||
|
(?P<string_double_quote>"([^"\\]|\\.)*") |
|
||||||
|
(?P<string_single_quote>'([^'\\]|\\.)*') |
|
||||||
|
(?P<template_literal>`([^`\\]|\\.)*`) |
|
||||||
|
(?P<op>[+\-/*%~^!&|=<>;:]) |
|
||||||
|
(?P<number>0[bB][01](_?[01])*n?|0[oO][0-7](_?[0-7])*n?|0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?|(([0-9](_?[0-9])*\.([0-9](_?[0-9])*)?)|(([0-9](_?[0-9])*)?\.[0-9](_?[0-9])*)|([0-9](_?[0-9])*))([eE][+-]?[0-9](_?[0-9])*)?n?)"#,
|
||||||
|
)
|
||||||
|
.expect("could not compile regular expression");
|
||||||
|
|
||||||
|
coloured = reg
|
||||||
|
.replace_all(&coloured, |caps: &Captures<'_>| {
|
||||||
|
if let Some(cap) = caps.name("identifier") {
|
||||||
|
match cap.as_str() {
|
||||||
|
"true" | "false" | "null" | "Infinity" | "globalThis" => {
|
||||||
|
cap.as_str().color(PROPERTY_COLOR).to_string()
|
||||||
|
}
|
||||||
|
"undefined" => cap.as_str().color(UNDEFINED_COLOR).to_string(),
|
||||||
|
identifier if KEYWORDS.contains(identifier) => {
|
||||||
|
cap.as_str().color(KEYWORD_COLOR).bold().to_string()
|
||||||
|
}
|
||||||
|
_ => cap.as_str().color(IDENTIFIER_COLOR).to_string(),
|
||||||
|
}
|
||||||
|
} else if let Some(cap) = caps.name("string_double_quote") {
|
||||||
|
cap.as_str().color(STRING_COLOR).to_string()
|
||||||
|
} else if let Some(cap) = caps.name("string_single_quote") {
|
||||||
|
cap.as_str().color(STRING_COLOR).to_string()
|
||||||
|
} else if let Some(cap) = caps.name("template_literal") {
|
||||||
|
cap.as_str().color(STRING_COLOR).to_string()
|
||||||
|
} else if let Some(cap) = caps.name("op") {
|
||||||
|
cap.as_str().color(OPERATOR_COLOR).to_string()
|
||||||
|
} else if let Some(cap) = caps.name("number") {
|
||||||
|
cap.as_str().color(NUMBER_COLOR).to_string()
|
||||||
|
} else {
|
||||||
|
caps[0].to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
coloured.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
387
javascript-engine/external/boa/boa_cli/src/main.rs
vendored
Normal file
387
javascript-engine/external/boa/boa_cli/src/main.rs
vendored
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
//! A ECMAScript REPL implementation based on boa_engine.
|
||||||
|
|
||||||
|
#![doc(
|
||||||
|
html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg",
|
||||||
|
html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
|
||||||
|
#![warn(missing_docs, clippy::dbg_macro)]
|
||||||
|
#![deny(
|
||||||
|
// rustc lint groups https://doc.rust-lang.org/rustc/lints/groups.html
|
||||||
|
warnings,
|
||||||
|
future_incompatible,
|
||||||
|
let_underscore,
|
||||||
|
nonstandard_style,
|
||||||
|
rust_2018_compatibility,
|
||||||
|
rust_2018_idioms,
|
||||||
|
rust_2021_compatibility,
|
||||||
|
unused,
|
||||||
|
|
||||||
|
// rustc allowed-by-default lints https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html
|
||||||
|
macro_use_extern_crate,
|
||||||
|
meta_variable_misuse,
|
||||||
|
missing_abi,
|
||||||
|
missing_copy_implementations,
|
||||||
|
missing_debug_implementations,
|
||||||
|
non_ascii_idents,
|
||||||
|
noop_method_call,
|
||||||
|
single_use_lifetimes,
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unreachable_pub,
|
||||||
|
unsafe_op_in_unsafe_fn,
|
||||||
|
unused_crate_dependencies,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_lifetimes,
|
||||||
|
unused_qualifications,
|
||||||
|
unused_tuple_struct_fields,
|
||||||
|
variant_size_differences,
|
||||||
|
|
||||||
|
// rustdoc lints https://doc.rust-lang.org/rustdoc/lints.html
|
||||||
|
rustdoc::broken_intra_doc_links,
|
||||||
|
rustdoc::private_intra_doc_links,
|
||||||
|
rustdoc::missing_crate_level_docs,
|
||||||
|
rustdoc::private_doc_tests,
|
||||||
|
rustdoc::invalid_codeblock_attributes,
|
||||||
|
rustdoc::invalid_rust_codeblocks,
|
||||||
|
rustdoc::bare_urls,
|
||||||
|
|
||||||
|
// clippy categories https://doc.rust-lang.org/clippy/
|
||||||
|
clippy::all,
|
||||||
|
clippy::correctness,
|
||||||
|
clippy::suspicious,
|
||||||
|
clippy::style,
|
||||||
|
clippy::complexity,
|
||||||
|
clippy::perf,
|
||||||
|
clippy::pedantic,
|
||||||
|
clippy::nursery,
|
||||||
|
)]
|
||||||
|
#![allow(clippy::option_if_let_else, clippy::redundant_pub_crate)]
|
||||||
|
|
||||||
|
mod helper;
|
||||||
|
|
||||||
|
use boa_ast::StatementList;
|
||||||
|
use boa_engine::{
|
||||||
|
context::ContextBuilder,
|
||||||
|
job::{JobQueue, NativeJob},
|
||||||
|
vm::flowgraph::{Direction, Graph},
|
||||||
|
Context, JsResult,
|
||||||
|
};
|
||||||
|
use clap::{Parser, ValueEnum, ValueHint};
|
||||||
|
use colored::{Color, Colorize};
|
||||||
|
use rustyline::{config::Config, error::ReadlineError, EditMode, Editor};
|
||||||
|
use std::{cell::RefCell, collections::VecDeque, fs::read, fs::OpenOptions, io, path::PathBuf};
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
|
||||||
|
#[cfg_attr(
|
||||||
|
all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"),
|
||||||
|
global_allocator
|
||||||
|
)]
|
||||||
|
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
|
||||||
|
/// CLI configuration for Boa.
|
||||||
|
static CLI_HISTORY: &str = ".boa_history";
|
||||||
|
|
||||||
|
const READLINE_COLOR: Color = Color::Cyan;
|
||||||
|
|
||||||
|
// Added #[allow(clippy::option_option)] because to StructOpt an Option<Option<T>>
|
||||||
|
// is an optional argument that optionally takes a value ([--opt=[val]]).
|
||||||
|
// https://docs.rs/structopt/0.3.11/structopt/#type-magic
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(author, version, about, name = "boa")]
|
||||||
|
struct Opt {
|
||||||
|
/// The JavaScript file(s) to be evaluated.
|
||||||
|
#[arg(name = "FILE", value_hint = ValueHint::FilePath)]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Dump the AST to stdout with the given format.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
short = 'a',
|
||||||
|
value_name = "FORMAT",
|
||||||
|
ignore_case = true,
|
||||||
|
value_enum,
|
||||||
|
conflicts_with = "graph"
|
||||||
|
)]
|
||||||
|
#[allow(clippy::option_option)]
|
||||||
|
dump_ast: Option<Option<DumpFormat>>,
|
||||||
|
|
||||||
|
/// Dump the AST to stdout with the given format.
|
||||||
|
#[arg(long, short, conflicts_with = "graph")]
|
||||||
|
trace: bool,
|
||||||
|
|
||||||
|
/// Use vi mode in the REPL
|
||||||
|
#[arg(long = "vi")]
|
||||||
|
vi_mode: bool,
|
||||||
|
|
||||||
|
/// Generate instruction flowgraph. Default is Graphviz.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_name = "FORMAT",
|
||||||
|
ignore_case = true,
|
||||||
|
value_enum,
|
||||||
|
group = "graph"
|
||||||
|
)]
|
||||||
|
#[allow(clippy::option_option)]
|
||||||
|
flowgraph: Option<Option<FlowgraphFormat>>,
|
||||||
|
|
||||||
|
/// Specifies the direction of the flowgraph. Default is TopToBottom.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_name = "FORMAT",
|
||||||
|
ignore_case = true,
|
||||||
|
value_enum,
|
||||||
|
requires = "graph"
|
||||||
|
)]
|
||||||
|
flowgraph_direction: Option<FlowgraphDirection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Opt {
|
||||||
|
/// Returns whether a dump flag has been used.
|
||||||
|
const fn has_dump_flag(&self) -> bool {
|
||||||
|
self.dump_ast.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, ValueEnum)]
|
||||||
|
enum DumpFormat {
|
||||||
|
/// The different types of format available for dumping.
|
||||||
|
// NOTE: This can easily support other formats just by
|
||||||
|
// adding a field to this enum and adding the necessary
|
||||||
|
// implementation. Example: Toml, Html, etc.
|
||||||
|
//
|
||||||
|
// NOTE: The fields of this enum are not doc comments because
|
||||||
|
// arg_enum! macro does not support it.
|
||||||
|
|
||||||
|
// This is the default format that you get from std::fmt::Debug.
|
||||||
|
Debug,
|
||||||
|
|
||||||
|
// This is a minified json format.
|
||||||
|
Json,
|
||||||
|
|
||||||
|
// This is a pretty printed json format.
|
||||||
|
JsonPretty,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the format of the instruction flowgraph.
|
||||||
|
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||||
|
enum FlowgraphFormat {
|
||||||
|
/// Generates in [graphviz][graphviz] format.
|
||||||
|
///
|
||||||
|
/// [graphviz]: https://graphviz.org/
|
||||||
|
Graphviz,
|
||||||
|
/// Generates in [mermaid][mermaid] format.
|
||||||
|
///
|
||||||
|
/// [mermaid]: https://mermaid-js.github.io/mermaid/#/
|
||||||
|
Mermaid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the direction of the instruction flowgraph.
|
||||||
|
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||||
|
enum FlowgraphDirection {
|
||||||
|
TopToBottom,
|
||||||
|
BottomToTop,
|
||||||
|
LeftToRight,
|
||||||
|
RightToLeft,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the the token stream into an AST and returns it.
|
||||||
|
///
|
||||||
|
/// Returns a error of type String with a message,
|
||||||
|
/// if the token stream has a parsing error.
|
||||||
|
fn parse_tokens<S>(src: S, context: &mut Context<'_>) -> Result<StatementList, String>
|
||||||
|
where
|
||||||
|
S: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
let src_bytes = src.as_ref();
|
||||||
|
boa_parser::Parser::new(src_bytes)
|
||||||
|
.parse_all(context.interner_mut())
|
||||||
|
.map_err(|e| format!("ParsingError: {e}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dumps the AST to stdout with format controlled by the given arguments.
|
||||||
|
///
|
||||||
|
/// Returns a error of type String with a error message,
|
||||||
|
/// if the source has a syntax or parsing error.
|
||||||
|
fn dump<S>(src: S, args: &Opt, context: &mut Context<'_>) -> Result<(), String>
|
||||||
|
where
|
||||||
|
S: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
if let Some(ref arg) = args.dump_ast {
|
||||||
|
let ast = parse_tokens(src, context)?;
|
||||||
|
|
||||||
|
match arg {
|
||||||
|
Some(DumpFormat::Json) => println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string(&ast).expect("could not convert AST to a JSON string")
|
||||||
|
),
|
||||||
|
Some(DumpFormat::JsonPretty) => println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&ast)
|
||||||
|
.expect("could not convert AST to a pretty JSON string")
|
||||||
|
),
|
||||||
|
Some(DumpFormat::Debug) | None => println!("{ast:#?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_flowgraph(
|
||||||
|
context: &mut Context<'_>,
|
||||||
|
src: &[u8],
|
||||||
|
format: FlowgraphFormat,
|
||||||
|
direction: Option<FlowgraphDirection>,
|
||||||
|
) -> JsResult<String> {
|
||||||
|
let ast = context.parse(src)?;
|
||||||
|
let code = context.compile(&ast)?;
|
||||||
|
|
||||||
|
let direction = match direction {
|
||||||
|
Some(FlowgraphDirection::TopToBottom) | None => Direction::TopToBottom,
|
||||||
|
Some(FlowgraphDirection::BottomToTop) => Direction::BottomToTop,
|
||||||
|
Some(FlowgraphDirection::LeftToRight) => Direction::LeftToRight,
|
||||||
|
Some(FlowgraphDirection::RightToLeft) => Direction::RightToLeft,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut graph = Graph::new(direction);
|
||||||
|
code.to_graph(context.interner(), graph.subgraph(String::default()));
|
||||||
|
let result = match format {
|
||||||
|
FlowgraphFormat::Graphviz => graph.to_graphviz_format(),
|
||||||
|
FlowgraphFormat::Mermaid => graph.to_mermaid_format(),
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), io::Error> {
|
||||||
|
let args = Opt::parse();
|
||||||
|
|
||||||
|
let queue = Jobs::default();
|
||||||
|
let mut context = ContextBuilder::new().job_queue(&queue).build();
|
||||||
|
|
||||||
|
// Trace Output
|
||||||
|
context.set_trace(args.trace);
|
||||||
|
|
||||||
|
for file in &args.files {
|
||||||
|
let buffer = read(file)?;
|
||||||
|
|
||||||
|
if args.has_dump_flag() {
|
||||||
|
if let Err(e) = dump(&buffer, &args, &mut context) {
|
||||||
|
eprintln!("{e}");
|
||||||
|
}
|
||||||
|
} else if let Some(flowgraph) = args.flowgraph {
|
||||||
|
match generate_flowgraph(
|
||||||
|
&mut context,
|
||||||
|
&buffer,
|
||||||
|
flowgraph.unwrap_or(FlowgraphFormat::Graphviz),
|
||||||
|
args.flowgraph_direction,
|
||||||
|
) {
|
||||||
|
Ok(v) => println!("{v}"),
|
||||||
|
Err(v) => eprintln!("Uncaught {v}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match context.eval(&buffer) {
|
||||||
|
Ok(v) => println!("{}", v.display()),
|
||||||
|
Err(v) => eprintln!("Uncaught {v}"),
|
||||||
|
}
|
||||||
|
context.run_jobs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.files.is_empty() {
|
||||||
|
let config = Config::builder()
|
||||||
|
.keyseq_timeout(1)
|
||||||
|
.edit_mode(if args.vi_mode {
|
||||||
|
EditMode::Vi
|
||||||
|
} else {
|
||||||
|
EditMode::Emacs
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut editor =
|
||||||
|
Editor::with_config(config).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
// Check if the history file exists. If it does, create it.
|
||||||
|
OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(CLI_HISTORY)?;
|
||||||
|
editor.load_history(CLI_HISTORY).map_err(|err| match err {
|
||||||
|
ReadlineError::Io(e) => e,
|
||||||
|
e => io::Error::new(io::ErrorKind::Other, e),
|
||||||
|
})?;
|
||||||
|
editor.set_helper(Some(helper::RLHelper::new()));
|
||||||
|
|
||||||
|
let readline = ">> ".color(READLINE_COLOR).bold().to_string();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match editor.readline(&readline) {
|
||||||
|
Ok(line) if line == ".exit" => break,
|
||||||
|
Err(ReadlineError::Interrupted | ReadlineError::Eof) => break,
|
||||||
|
|
||||||
|
Ok(line) => {
|
||||||
|
editor.add_history_entry(&line);
|
||||||
|
|
||||||
|
if args.has_dump_flag() {
|
||||||
|
if let Err(e) = dump(&line, &args, &mut context) {
|
||||||
|
eprintln!("{e}");
|
||||||
|
}
|
||||||
|
} else if let Some(flowgraph) = args.flowgraph {
|
||||||
|
match generate_flowgraph(
|
||||||
|
&mut context,
|
||||||
|
line.trim_end().as_bytes(),
|
||||||
|
flowgraph.unwrap_or(FlowgraphFormat::Graphviz),
|
||||||
|
args.flowgraph_direction,
|
||||||
|
) {
|
||||||
|
Ok(v) => println!("{v}"),
|
||||||
|
Err(v) => eprintln!("Uncaught {v}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match context.eval(line.trim_end()) {
|
||||||
|
Ok(v) => {
|
||||||
|
println!("{}", v.display());
|
||||||
|
}
|
||||||
|
Err(v) => {
|
||||||
|
eprintln!("{}: {}", "Uncaught".red(), v.to_string().red());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.run_jobs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Unknown error: {err:?}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editor
|
||||||
|
.save_history(CLI_HISTORY)
|
||||||
|
.expect("could not save CLI history");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Jobs(RefCell<VecDeque<NativeJob>>);
|
||||||
|
|
||||||
|
impl JobQueue for Jobs {
|
||||||
|
fn enqueue_promise_job(&self, job: NativeJob, _: &mut Context<'_>) {
|
||||||
|
self.0.borrow_mut().push_front(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_jobs(&self, context: &mut Context<'_>) {
|
||||||
|
loop {
|
||||||
|
let jobs = std::mem::take(&mut *self.0.borrow_mut());
|
||||||
|
if jobs.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for job in jobs {
|
||||||
|
if let Err(e) = job.call(context) {
|
||||||
|
eprintln!("Uncaught {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
javascript-engine/external/boa/boa_engine/Cargo.toml
vendored
Normal file
95
javascript-engine/external/boa/boa_engine/Cargo.toml
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
[package]
|
||||||
|
name = "boa_engine"
|
||||||
|
keywords = ["javascript", "js", "compiler", "lexer", "parser"]
|
||||||
|
categories = ["parser-implementations", "compilers"]
|
||||||
|
readme = "../README.md"
|
||||||
|
description.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
profiler = ["boa_profiler/profiler"]
|
||||||
|
deser = ["boa_interner/serde", "boa_ast/serde"]
|
||||||
|
intl = [
|
||||||
|
"dep:boa_icu_provider",
|
||||||
|
"dep:icu_locid_transform",
|
||||||
|
"dep:icu_locid",
|
||||||
|
"dep:icu_datetime",
|
||||||
|
"dep:icu_plurals",
|
||||||
|
"dep:icu_provider",
|
||||||
|
"dep:icu_calendar",
|
||||||
|
"dep:icu_collator",
|
||||||
|
"dep:icu_list",
|
||||||
|
"dep:writeable",
|
||||||
|
"dep:sys-locale",
|
||||||
|
]
|
||||||
|
|
||||||
|
fuzz = ["boa_ast/fuzz", "boa_interner/fuzz"]
|
||||||
|
|
||||||
|
# Enable Boa's VM instruction flowgraph generator.
|
||||||
|
flowgraph = []
|
||||||
|
|
||||||
|
# Enable Boa's WHATWG console object implementation.
|
||||||
|
console = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
boa_interner.workspace = true
|
||||||
|
boa_gc.workspace = true
|
||||||
|
boa_profiler.workspace = true
|
||||||
|
boa_macros.workspace = true
|
||||||
|
boa_ast.workspace = true
|
||||||
|
boa_parser.workspace = true
|
||||||
|
serde = { version = "1.0.152", features = ["derive", "rc"] }
|
||||||
|
serde_json = "1.0.91"
|
||||||
|
rand = "0.8.5"
|
||||||
|
num-traits = "0.2.15"
|
||||||
|
regress = "0.4.1"
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
|
num-bigint = { version = "0.4.3", features = ["serde"] }
|
||||||
|
num-integer = "0.1.45"
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
indexmap = "1.9.2"
|
||||||
|
ryu-js = "0.2.2"
|
||||||
|
chrono = "0.4.23"
|
||||||
|
fast-float = "0.2.0"
|
||||||
|
unicode-normalization = "0.1.22"
|
||||||
|
once_cell = "1.17.0"
|
||||||
|
tap = "1.0.1"
|
||||||
|
sptr = "0.3.2"
|
||||||
|
static_assertions = "1.1.0"
|
||||||
|
thiserror = "1.0.38"
|
||||||
|
dashmap = "5.4.0"
|
||||||
|
num_enum = "0.5.7"
|
||||||
|
|
||||||
|
# intl deps
|
||||||
|
boa_icu_provider = { workspace = true, optional = true }
|
||||||
|
icu_locid_transform = { version = "1.0.0", features = ["serde"], optional = true }
|
||||||
|
icu_locid = { version = "1.0.0", features = ["serde"], optional = true }
|
||||||
|
icu_datetime = { version = "1.0.0", features = ["serde", "experimental"], optional = true }
|
||||||
|
icu_calendar = { version = "1.0.0", optional = true }
|
||||||
|
icu_collator = { version = "1.0.1", features = ["serde"], optional = true }
|
||||||
|
icu_plurals = { version = "1.0.0", features = ["serde"], optional = true }
|
||||||
|
icu_provider = { version = "1.0.1", optional = true }
|
||||||
|
icu_list = { version = "1.0.0", features = ["serde"], optional = true }
|
||||||
|
writeable = { version = "0.5.0", optional = true }
|
||||||
|
sys-locale = { version = "0.2.3", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
criterion = "0.4.0"
|
||||||
|
float-cmp = "0.9.0"
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu.dev-dependencies]
|
||||||
|
jemallocator = "0.5.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "lib"]
|
||||||
|
name = "boa_engine"
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "full"
|
||||||
|
harness = false
|
||||||
10
javascript-engine/external/boa/boa_engine/benches/README.md
vendored
Normal file
10
javascript-engine/external/boa/boa_engine/benches/README.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Boa Benchmarks
|
||||||
|
|
||||||
|
For each js script in the `bench_scripts` folder, we create three benchmarks:
|
||||||
|
|
||||||
|
- Parser => lexing and parsing of the source code
|
||||||
|
- Compiler => compilation of the parsed statement list into bytecode
|
||||||
|
- Execution => execution of the bytecode in the vm
|
||||||
|
|
||||||
|
The idea is to check the performance of Boa in different scenarios.
|
||||||
|
Different parts of Boa are benchmarked separately to make the impact of local changes visible.
|
||||||
1
javascript-engine/external/boa/boa_engine/benches/bench_scripts/arithmetic_operations.js
vendored
Normal file
1
javascript-engine/external/boa/boa_engine/benches/bench_scripts/arithmetic_operations.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
((2 + 2) ** 3 / 100 - 5 ** 3 * -1000) ** 2 + 100 - 8;
|
||||||
7
javascript-engine/external/boa/boa_engine/benches/bench_scripts/array_access.js
vendored
Normal file
7
javascript-engine/external/boa/boa_engine/benches/bench_scripts/array_access.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
(function () {
|
||||||
|
let testArr = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
let res = testArr[2];
|
||||||
|
|
||||||
|
return res;
|
||||||
|
})();
|
||||||
8
javascript-engine/external/boa/boa_engine/benches/bench_scripts/array_create.js
vendored
Normal file
8
javascript-engine/external/boa/boa_engine/benches/bench_scripts/array_create.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
(function () {
|
||||||
|
let testArr = [];
|
||||||
|
for (let a = 0; a <= 500; a++) {
|
||||||
|
testArr[a] = "p" + a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return testArr;
|
||||||
|
})();
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user