diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml
deleted file mode 100644
index cad5473..0000000
--- a/.github/workflows/demo.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: Demo
-
-on:
- push:
- branches: [ "master" ]
- pull_request:
- branches: [ "master" ]
-
-permissions:
- contents: write
-
-env:
- CARGO_TERM_COLOR: always
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- - name: Use nightly Rust
- run: rustup default nightly
- - name: Add wasm32 target
- run: rustup target add wasm32-unknown-unknown
- - name: Install wasm-bindgen CLI
- run: cargo install wasm-bindgen-cli
- - name: Build demo
- run: cargo build -p as3_parser_demo --release --target wasm32-unknown-unknown
- - name: Update demo/dist
- run: wasm-bindgen --target web --out-dir demo/dist target/wasm32-unknown-unknown/release/as3_parser_demo.wasm
- - name: Git commit report
- run: |
- git config --global user.name 'hydroper'
- git config --global user.email 'matheusdiasdesouzads@gmail.com'
- git switch -C demo
- git rm --cached -r .
- git add demo
- git rm --cached -r demo/src
- git rm --cached demo/Cargo.toml
- git commit -m "Automated report"
- git push origin -f demo
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c41cc9e..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index 54ec816..0000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,639 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "anstream"
-version = "0.6.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
-dependencies = [
- "anstyle",
- "windows-sys",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
-
-[[package]]
-name = "as3_parser"
-version = "1.0.8"
-dependencies = [
- "bitflags",
- "by_address",
- "bytes",
- "conv",
- "file_paths",
- "htmlentity",
- "hydroper_source_text",
- "late_format",
- "lazy-regex",
- "lazy_static",
- "maplit",
- "num-bigint",
- "num-derive",
- "num-traits",
- "serde",
- "serde_json",
- "unicode-general-category",
-]
-
-[[package]]
-name = "as3_parser_demo"
-version = "0.1.0"
-dependencies = [
- "as3_parser",
- "maplit",
- "serde",
- "serde_json",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "as3_parser_test"
-version = "0.4.0"
-dependencies = [
- "as3_parser",
- "clap",
- "file_paths",
- "maplit",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "asdoc-example"
-version = "0.1.0"
-dependencies = [
- "as3_parser",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
-
-[[package]]
-name = "bitflags"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
-
-[[package]]
-name = "by_address"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
-
-[[package]]
-name = "bytes"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "clap"
-version = "4.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
-
-[[package]]
-name = "conv"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
-dependencies = [
- "custom_derive",
-]
-
-[[package]]
-name = "custom_derive"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
-
-[[package]]
-name = "file_paths"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6655a548f719048f152b0349acf5f1b0fa7ce430acb49d4afc1d42513f160549"
-dependencies = [
- "lazy-regex",
-]
-
-[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
-name = "htmlentity"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab11d4e4796b618b77cabd8f0729eb8033891609820303af715e9306dbb95cd"
-dependencies = [
- "anyhow",
- "lazy_static",
- "thiserror",
-]
-
-[[package]]
-name = "hydroper_source_text"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cce3d21a188729674efc26164f9a201d567ab2fe28b6789cb802d7ca66ee7aaf"
-
-[[package]]
-name = "itoa"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
-
-[[package]]
-name = "js-sys"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "late_format"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c20a4c2785e13b46810cdd5b6df71b2bbacd6195d18d37b99098c6f52631dc6d"
-dependencies = [
- "lazy-regex",
- "maplit",
-]
-
-[[package]]
-name = "lazy-regex"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
-dependencies = [
- "lazy-regex-proc_macros",
- "once_cell",
- "regex",
-]
-
-[[package]]
-name = "lazy-regex-proc_macros"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
-dependencies = [
- "proc-macro2",
- "quote",
- "regex",
- "syn",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "log"
-version = "0.4.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
-
-[[package]]
-name = "maplit"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
-
-[[package]]
-name = "memchr"
-version = "2.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
-
-[[package]]
-name = "num-bigint"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-derive"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "regex"
-version = "1.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
-
-[[package]]
-name = "ryu"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
-
-[[package]]
-name = "serde"
-version = "1.0.197"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.197"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.115"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "strsim"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-
-[[package]]
-name = "syn"
-version = "2.0.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "thiserror"
-version = "1.0.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-general-category"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
-
-[[package]]
-name = "web-sys"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index d173730..0000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[workspace]
-members = [
- "crates/parser",
- "crates/parser_test",
- "demo",
- "examples/asdoc",
-]
-resolver = "2"
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 9820eb1..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2024 Hydroper
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index 22fe4ef..0000000
--- a/README.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# ActionScript 3 Parser
-
-
-
-
-
-
-
-
-
-
-ActionScript 3 parser in the Rust language.
-
-[Online demo](https://hydroper.github.io/as3parser/demo)
-
-## Documentation
-
-[Getting started](docs/getting-started.md)
-
-[Working with Diagnostics](docs/diagnostics.md)
-
-[Working with Locations](docs/locations.md)
-
-[Working with MXML](docs/working-with-mxml.md)
-
-[Working with CSS](docs/working-with-css.md)
-
-[Attaching Meaning](docs/attaching-meaning.md)
-
-[Reference Documents](docs/references.md)
-
-[New Syntax](docs/new-syntax.md)
-
-[Processing Deviations](docs/processing-deviations.md)
-
-[Building a Compiler](docs/building-a-compiler.md)
-
-## Wiki
-
-The [wiki](https://github.com/hydroper/as3parser/wiki) of this repository contains other introductory articles.
-
-## License
-
-Apache License 2.0, copyright 2024 Hydroper
diff --git a/as3/promise/AggregateError.as b/as3/promise/AggregateError.as
deleted file mode 100644
index c09f54c..0000000
--- a/as3/promise/AggregateError.as
+++ /dev/null
@@ -1,10 +0,0 @@
-package {
- public class AggregateError extends Error {
- public var errors: Array;
-
- public function AggregateError(errors: Array, message: String = "") {
- super(message);
- this.errors = errors.slice(0);
- }
- }
-}
\ No newline at end of file
diff --git a/as3/promise/Promise.as b/as3/promise/Promise.as
deleted file mode 100644
index 147b551..0000000
--- a/as3/promise/Promise.as
+++ /dev/null
@@ -1,354 +0,0 @@
-package {
- import flash.utils.setTimeout;
- import __AS3__.promise.*;
-
- /**
- * The Promise object represents the eventual completion (or failure)
- * of an asynchronous operation and its resulting value.
- *
- * For more information, consult [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
- *
- * # Examples
- *
- * ```
- * const promise = new Promise.<*>(function(resolve: Function, reject: Function): void {
- * //
- * });
- *
- * promise
- * .then(function(): * {})
- * .catch(function(error: *): * {})
- * .finally(function(): void {});
- * ```
- */
- public final class Promise. {
- // Implementation based on
- // https://github.com/taylorhakes/promise-polyfill
-
- private var m_state:Number = 0;
- private var m_handled:Boolean = false;
- private var m_value:* = undefined;
- private var m_deferreds:Vector. = new Vector.;
-
- private static function bindFunction(fn:Function, thisArg:*):Function {
- return function(...argumentsList):void {
- fn.apply(thisArg, argumentsList);
- };
- }
-
- public function Promise(fn: Function) {
- doResolve(fn, this);
- }
-
- private static function handle(self:Promise., deferred:PromiseHandler):void {
- while (self.m_state === 3) {
- self = self.m_value;
- }
- if (self.m_state === 0) {
- self.m_deferreds.push(deferred);
- return;
- }
- self.m_handled = true;
- Promise.._immediateFn(function():void {
- var cb:Function = self.m_state === 1 ? deferred.onFulfilled : deferred.onRejected;
- if (cb === null) {
- (self.m_state === 1 ? Promise..privateResolve : Promise..privateReject)(deferred.promise, self.m_value);
- return;
- }
- var ret:* = undefined;
- try {
- ret = cb(self.m_value);
- }
- catch (e:*) {
- Promise..privateReject(deferred.promise, e);
- return;
- }
- Promise..privateResolve(deferred.promise, ret);
- });
- }
-
- private static function privateResolve(self:Promise., newValue:*):void {
- try {
- // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
- if (newValue === self) {
- throw new TypeError('A promise cannot be resolved with itself.');
- }
- if (newValue is Promise) {
- self.m_state = 3;
- self.m_value = newValue;
- Promise..finale(self);
- return;
- }
- self.m_state = 1;
- self.m_value = newValue;
- Promise..finale(self);
- }
- catch (e:*) {
- Promise..privateReject(self, e);
- }
- }
-
- private static function privateReject(self:Promise., newValue:*):void {
- self.m_state = 2;
- self.m_value = newValue;
- Promise..finale(self);
- }
-
- private static function finale(self:Promise.):void {
- if (self.m_state === 2 && self.m_deferreds.length === 0) {
- Promise.._immediateFn(function():void {
- if (!self.m_handled) {
- Promise.._unhandledRejectionFn(self.m_value);
- }
- });
- }
-
- for (var i:Number = 0, len:Number = self.m_deferreds.length; i < len; i++) {
- handle(self, self.m_deferreds[i]);
- }
- self.m_deferreds = null;
- }
-
- /**
- * Takes a potentially misbehaving resolver function and make sure
- * `onFulfilled` and `onRejected` are only called once.
- *
- * Makes no guarantees about asynchrony.
- */
- private static function doResolve(fn:Function, self:Promise.):void {
- var done:Boolean = false;
- try {
- fn(
- function(value:*):* {
- if (done) return;
- done = true;
- Promise..privateResolve(self, value);
- },
- function(reason:*):* {
- if (done) return;
- done = true;
- Promise..privateReject(self, reason);
- }
- );
- }
- catch (ex:*) {
- if (done) return;
- done = true;
- Promise..privateReject(self, ex);
- }
- }
-
- /**
- * The `Promise.allSettled()` static method takes an iterable of promises
- * as input and returns a single Promise.
- * This returned promise fulfills when all of the input's promises settle
- * (including when an empty iterable is passed), with an array of objects that
- * describe the outcome of each promise.
- *
- * # Example
- *
- * ```
- * const promise1 = Promise..resolve(3);
- * const promise2 = new Promise.(function(resolve: Function, reject: Function): void {
- * setTimeout(reject, 100, "foo");
- * });
- * Promise..allSettled([promise1, promise2])
- * .then(function(results: Array): void {
- * for each (const result in results) {
- * trace(result.status);
- * }
- * });
- * // Expected output:
- * // "fulfilled"
- * // "rejected"
- * ```
- *
- * @return A `Promise` that is:
- *
- * - **Already fulfilled,** if the iterable passed is empty.
- * - **Asynchronously fulfilled,** when all promises in the given
- * iterable have settled (either fulfilled or rejected).
- * The fulfillment value is an array of objects, each describing the
- * outcome of one promise in the iterable, in the order of the promises passed,
- * regardless of completion order. Each outcome object has the following properties:
- * - `status`: A string, either `"fulfilled"` or `"rejected"`, indicating the eventual state of the promise.
- * - `value`: Only present if `status` is `"fulfilled"`. The value that the promise was fulfilled with.
- * - `reason`: Only present if `status` is `"rejected"`. The reason that the promise was rejected with.
- *
- * If the iterable passed is non-empty but contains no pending promises,
- * the returned promise is still asynchronously (instead of synchronously) fulfilled.
- */
- public static function allSettled(promises: Array): Promise. {
- return new Promise(function(resolve:Function, reject:Function):void {
- var args:Array = promises.slice(0);
- if (args.length === 0) {
- resolve([]);
- return;
- }
- var remaining:Number = args.length;
- function res(i:Number, val:*):void {
- if (val is Promise) {
- Promise(val).then(
- function(val:*):* {
- res(i, val);
- },
- function(e:*):* {
- args[i] = { status: 'rejected', reason: e };
- if (--remaining === 0) {
- resolve(args);
- }
- }
- );
- return;
- }
- args[i] = { status: 'fulfilled', value: val };
- if (--remaining === 0) {
- resolve(args);
- }
- }
- for (var i:Number = 0; i < args.length; ++i) {
- res(i, args[i]);
- }
- });
- } // allSettled
-
- /**
- * [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any)
- */
- public static function any(promises:Array):Promise. {
- return new Promise(function(resolve:Function, reject:Function):void {
- var args:Array = promises.slice(0);
- if (args.length === 0) {
- reject(undefined);
- return;
- }
- var rejectionReasons:Array = [];
- for (var i:Number = 0; i < args.length; ++i) {
- try {
- Promise..resolve(args[i])
- .then(resolve)
- .catch(function(error:*):* {
- rejectionReasons.push(error);
- if (rejectionReasons.length === args.length) {
- reject(
- new AggregateError(
- rejectionReasons,
- 'All promises were rejected'
- )
- );
- }
- });
- }
- catch (ex:*) {
- reject(ex);
- }
- }
- });
- } // any
-
- public function finally(callback:Function):Promise. {
- return this.then(
- function(value:*):* {
- return Promise..resolve(callback()).then(function(_:*):* {
- return value;
- });
- },
- function(reason:*):* {
- return Promise..resolve(callback()).then(function(_:*):* {
- return Promise..reject(reason);
- });
- }
- );
- }
-
- public function catch(onRejected: Function):Promise. {
- return this.then(null, onRejected);
- }
-
- public function then(onFulfilled: function(T): U, onRejected: function(*): E = null):Promise.<*> {
- var prom = new Promise.<*>(function(_a:*, _b:*):void {});
- Promise..handle(this, new PromiseHandler(onFulfilled, onRejected, prom));
- return prom;
- }
-
- /**
- * [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
- */
- public static function all(promises: Array):Promise. {
- return new Promise(function(resolve:Function, reject:Function):void {
- var args:Array = promises.slice(0);
- if (args.length === 0) {
- resolve([]);
- return;
- }
- var remaining:Number = args.length;
-
- function res(i:Number, val:*):void {
- try {
- if (val is Promise) {
- Promise(val).then(
- function(val): * {
- res(i, val);
- },
- reject
- );
- return;
- }
- args[i] = val;
- if (--remaining === 0) {
- resolve(args);
- }
- }
- catch (ex:*) {
- reject(ex);
- }
- }
-
- for (var i:Number = 0; i < args.length; i++) {
- res(i, args[i]);
- }
- });
- } // all
-
- /**
- * [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve)
- */
- public static function resolve(value: *):Promise. {
- if (value is Promise) {
- return Promise.(value);
- }
-
- return new Promise.(function(resolve: Function, reject: Function): void {
- resolve(value);
- });
- }
-
- /**
- * [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject)
- */
- public static function reject(value: *): Promise. {
- return new Promise(function(resolve: Function, reject: Function): void {
- reject(value);
- });
- }
-
- /**
- * [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)
- */
- public static function race(promises:Array):Promise. {
- return new Promise.(function(resolve:Function, reject:Function):void {
- for each (var arg:* in promises) {
- Promise..resolve(arg).then(resolve, reject);
- }
- });
- }
-
- private static function _immediateFn(fn:Function):void {
- setTimeout(fn, 0);
- }
-
- private static function _unhandledRejectionFn(err:*):void {
- trace("Possible unhandled Promise rejection:", err);
- }
- }
-}
diff --git a/as3/promise/PromiseHandler.as b/as3/promise/PromiseHandler.as
deleted file mode 100644
index 708f554..0000000
--- a/as3/promise/PromiseHandler.as
+++ /dev/null
@@ -1,16 +0,0 @@
-package __AS3__.promise {
- /**
- * @private
- */
- public final class PromiseHandler {
- public var onFulfilled: Function;
- public var onRejected: Function;
- public var promise: Promise;
-
- public function PromiseHandler(onFulfilled: Function, onRejected: Function, promise: Promise) {
- this.onFulfilled = onFulfilled;
- this.onRejected = onRejected;
- this.promise = promise;
- }
- }
-}
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
deleted file mode 100644
index a1f551d..0000000
--- a/crates/parser/Cargo.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-[package]
-name = "as3_parser"
-version = "1.0.8"
-edition = "2021"
-authors = ["hydroper "]
-repository = "https://github.com/hydroper/as3parser"
-keywords = ["actionscript", "as3", "parser"]
-description = "ActionScript 3 parser"
-license = "Apache-2.0"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[lib]
-name = "as3_parser"
-path = "lib.rs"
-
-[dependencies]
-bitflags = { version = "2.4.1", features = ["serde"] }
-bytes = "1"
-file_paths = "1.0.0"
-conv = "0.3.3"
-htmlentity = "1.3.1"
-late_format = "1.0.0"
-maplit = "1.0.2"
-num-bigint = "0.4"
-num-derive = "0.4.1"
-num-traits = "0.2.17"
-lazy-regex = "3.0.2"
-lazy_static = "1.4.0"
-unicode-general-category = "0.6.0"
-by_address = "1.1.0"
-serde = { version = "1.0.192", features = ["rc", "derive"] }
-serde_json = "1.0.108"
-hydroper_source_text = "1.0.3"
diff --git a/crates/parser/README.md b/crates/parser/README.md
deleted file mode 100644
index 61237d1..0000000
--- a/crates/parser/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# ActionScript 3 Parser
-
-Refer to the [crate repository](https://github.com/hydroper/as3parser) for full details.
diff --git a/crates/parser/compilation_unit.rs b/crates/parser/compilation_unit.rs
deleted file mode 100644
index 93b1777..0000000
--- a/crates/parser/compilation_unit.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//! Defines the compilation unit, comments, and source locations.
-
-mod compilation_unit;
-pub use compilation_unit::*;
-mod comment;
-pub use comment::*;
-mod location;
-pub use location::*;
\ No newline at end of file
diff --git a/crates/parser/compilation_unit/comment.rs b/crates/parser/compilation_unit/comment.rs
deleted file mode 100644
index 6046ab7..0000000
--- a/crates/parser/compilation_unit/comment.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::ns::*;
-
-pub struct Comment {
- pub(crate) multiline: bool,
- pub(crate) content: RefCell,
- pub(crate) location: RefCell,
-}
-
-impl Comment {
- pub fn new(multiline: bool, content: String, location: Location) -> Self {
- Self {
- multiline,
- content: RefCell::new(content),
- location: RefCell::new(location),
- }
- }
-
- pub fn multiline(&self) -> bool {
- self.multiline
- }
-
- /// The content of the comment.
- /// * If it is a multi-line comment, it includes all the characters after `/*` until `*/` (exclusive).
- /// * If it is a single-line comment, it includes all the characters after `//`
- /// until the next line terminator (exclusive) or end of program.
- pub fn content(&self) -> String {
- self.content.borrow().clone()
- }
-
- pub fn set_content(&self, content: String) {
- self.content.replace(content);
- }
-
- pub fn location(&self) -> Location {
- self.location.borrow().clone()
- }
-
- pub fn set_location(&self, location: Location) {
- self.location.replace(location);
- }
-
- /// Indicates whether the comment is an AsDoc comment preceding
- /// a specific location.
- pub fn is_asdoc(&self, location_to_precede: &Location) -> bool {
- if self.multiline && self.content.borrow().starts_with('*') {
- let mut i: usize = self.location.borrow().last_offset;
- for (i_1, ch) in self.location.borrow().compilation_unit().text()[i..].char_indices() {
- i = i_1;
- if !(CharacterValidator::is_whitespace(ch) || CharacterValidator::is_line_terminator(ch)) {
- break;
- }
- }
- i += self.location.borrow().last_offset;
- location_to_precede.first_offset == i
- } else {
- false
- }
- }
-}
\ No newline at end of file
diff --git a/crates/parser/compilation_unit/compilation_unit.rs b/crates/parser/compilation_unit/compilation_unit.rs
deleted file mode 100644
index fe900a5..0000000
--- a/crates/parser/compilation_unit/compilation_unit.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-use std::{any::Any, cell::RefMut};
-use crate::ns::*;
-use hydroper_source_text::SourceText;
-
-/// `CompilationUnit` identifies an AS3 compilation unit and contains
-/// a source text.
-pub struct CompilationUnit {
- pub(crate) file_path: Option,
- pub(crate) source_text: SourceText,
- pub(crate) compiler_options: RefCell>>,
- pub(crate) diagnostics: RefCell>,
- pub(crate) error_count: Cell,
- pub(crate) warning_count: Cell,
- pub(crate) invalidated: Cell,
- pub(crate) comments: RefCell>>,
- pub(crate) included_from: RefCell>>,
- pub(crate) nested_compilation_units: RefCell>>,
-}
-
-impl Default for CompilationUnit {
- fn default() -> Self {
- Self {
- file_path: None,
- source_text: SourceText::new("".into()),
- compiler_options: RefCell::new(None),
- diagnostics: RefCell::new(vec![]),
- invalidated: Cell::new(false),
- error_count: Cell::new(0),
- warning_count: Cell::new(0),
- comments: RefCell::new(vec![]),
- nested_compilation_units: RefCell::new(vec![]),
- included_from: RefCell::new(None),
- }
- }
-}
-
-impl CompilationUnit {
- /// Constructs a source file in unparsed and non verified state.
- pub fn new(file_path: Option, text: String) -> Rc {
- Rc::new(Self {
- file_path,
- source_text: SourceText::new(text),
- compiler_options: RefCell::new(None),
- diagnostics: RefCell::new(vec![]),
- invalidated: Cell::new(false),
- error_count: Cell::new(0),
- warning_count: Cell::new(0),
- comments: RefCell::new(vec![]),
- nested_compilation_units: RefCell::new(vec![]),
- included_from: RefCell::new(None),
- })
- }
-
- /// File path of the source or `None` if not a file.
- pub fn file_path(&self) -> Option {
- self.file_path.clone()
- }
-
- /// Source text.
- pub fn text(&self) -> &String {
- &self.source_text.contents
- }
-
- /// Compiler options.
- pub fn compiler_options(&self) -> Option> {
- self.compiler_options.borrow().clone()
- }
-
- /// Set compiler options.
- pub fn set_compiler_options(&self, options: Option>) {
- self.compiler_options.replace(options);
- }
-
- /// Whether the source contains any errors after parsing
- /// and/or verification.
- pub fn invalidated(&self) -> bool {
- self.invalidated.get()
- }
-
- /// The comments present in the source file. To get mutable access to the
- /// collection of comments, use the `comments_mut()` method instead.
- pub fn comments(&self) -> Vec> {
- let mut collection = vec![];
- for c in self.comments.borrow().iter() {
- collection.push(c.clone());
- }
- collection
- }
-
- /// The comments present in the source file, as a mutable collection.
- pub fn comments_mut(&self) -> RefMut>> {
- self.comments.borrow_mut()
- }
-
- /// Contributes a comment if there is no other comment
- /// in the same location.
- pub fn add_comment(&self, comment: Rc) {
- let mut dup = false;
- let i = comment.location.borrow().first_offset();
- for c1 in self.comments.borrow().iter() {
- if c1.location.borrow().first_offset == i {
- dup = true;
- break;
- }
- }
- if !dup {
- self.comments.borrow_mut().push(comment);
- }
- }
-
- /// Diagnostics of the source file after parsing and/or
- /// verification.
- pub fn diagnostics(&self) -> Vec {
- self.diagnostics.borrow().clone()
- }
-
- /// Diagnostics of the source file after parsing and/or
- /// verification, including those of nested compilation units.
- pub fn nested_diagnostics(&self) -> Vec {
- let mut result = self.diagnostics();
- for unit in self.nested_compilation_units.borrow().iter() {
- result.extend(unit.nested_diagnostics());
- }
- result
- }
-
- /// Sort diagnostics from the compilation unit
- /// and any nested compilation units.
- pub fn sort_diagnostics(&self) {
- self.diagnostics.borrow_mut().sort();
- for unit in self.nested_compilation_units.borrow().iter() {
- unit.sort_diagnostics();
- }
- }
-
- /// Determines whether to skip contributing an error when it
- /// occurs at the same offset of another error.
- pub fn prevent_equal_offset_error(&self, location: &Location) -> bool {
- let diag_list = self.diagnostics.borrow();
- for diag in diag_list.iter() {
- if diag.is_warning() {
- continue;
- }
- if diag.location.first_offset == location.first_offset {
- return true;
- }
- }
- false
- }
-
- /// Determines whether to skip contributing a warning when it
- /// occurs at the same offset of another warning.
- pub fn prevent_equal_offset_warning(&self, location: &Location) -> bool {
- let diag_list = self.diagnostics.borrow();
- for diag in diag_list.iter() {
- if diag.is_error() {
- continue;
- }
- if diag.location.first_offset == location.first_offset {
- return true;
- }
- }
- false
- }
-
- /// If this compilation unit is subsequent of an include directive in another
- /// compilation unit, returns the compilation unit of that include directive.
- pub fn included_from(&self) -> Option> {
- self.included_from.borrow().clone()
- }
-
- pub(crate) fn set_included_from(&self, included_from: Option>) {
- self.included_from.replace(included_from);
- }
-
- pub(crate) fn include_directive_is_circular(&self, file_path: &str) -> bool {
- if canonicalize_path(&self.file_path.clone().unwrap_or("".into())) == canonicalize_path(file_path) {
- return true;
- }
- if let Some(included_from) = self.included_from() {
- return included_from.include_directive_is_circular(file_path);
- }
- return false;
- }
-
- pub fn nested_compilation_units(&self) -> Vec> {
- let mut result = vec![];
- for unit in self.nested_compilation_units.borrow().iter() {
- result.push(unit.clone());
- }
- result
- }
-
- pub fn add_nested_compilation_unit(&self, unit: Rc) {
- self.nested_compilation_units.borrow_mut().push(unit);
- }
-
- pub fn add_diagnostic(&self, diagnostic: Diagnostic) {
- if diagnostic.is_warning() {
- self.warning_count.set(self.warning_count.get() + 1);
- } else {
- self.error_count.set(self.error_count.get() + 1);
- self.invalidated.set(true);
- }
- self.diagnostics.borrow_mut().push(diagnostic);
- }
-
- pub fn error_count(&self) -> u32 {
- self.error_count.get()
- }
-
- pub fn warning_count(&self) -> u32 {
- self.warning_count.get()
- }
-
- /// Retrieves line number from an offset. The resulting line number
- /// is counted from one.
- pub fn get_line_number(&self, offset: usize) -> usize {
- self.source_text.get_line_number(offset)
- }
-
- /// Returns the zero based column of an offset.
- pub fn get_column(&self, offset: usize) -> usize {
- self.source_text.get_column(offset)
- }
-
- /// Retrieves offset from line number (counted from one).
- pub fn get_line_offset(&self, line: usize) -> Option {
- self.source_text.get_line_offset(line)
- }
-
- /// Retrieves the offset from the corresponding line of an offset.
- pub fn get_line_offset_from_offset(&self, offset: usize) -> usize {
- self.source_text.get_line_offset_from_offset(offset)
- }
-
- pub fn get_line_indent(&self, line: usize) -> usize {
- let line_offset = self.get_line_offset(line).unwrap();
- CharacterValidator::indent_count(&self.source_text.contents[line_offset..])
- }
-}
-
-fn canonicalize_path(path: &str) -> String {
- std::path::Path::new(path).canonicalize().unwrap_or(std::path::PathBuf::new()).to_string_lossy().into_owned()
-}
\ No newline at end of file
diff --git a/crates/parser/compilation_unit/location.rs b/crates/parser/compilation_unit/location.rs
deleted file mode 100644
index 44d46ed..0000000
--- a/crates/parser/compilation_unit/location.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-use std::cmp::Ordering;
-use std::fmt::Debug;
-use serde::{Serialize, Deserialize, Serializer};
-use std::rc::Rc;
-use crate::compilation_unit::*;
-use crate::util::{CharacterReader, count_first_whitespace_characters};
-
-/// Represents a source location. This location includes
-/// spanning lines and columns and the reference compilation unit.
-#[derive(Clone, Deserialize)]
-pub struct Location {
- /// The compilation unit that this location belongs to.
- #[serde(skip)]
- pub(crate) compilation_unit: Rc,
-
- /// First UTF-8 offset.
- #[serde(skip)]
- pub(crate) first_offset: usize,
-
- /// Last UTF-8 offset.
- #[serde(skip)]
- pub(crate) last_offset: usize,
-}
-
-impl Serialize for Location {
- fn serialize(&self, serializer: S) -> Result
- where
- S: Serializer,
- {
- serializer.serialize_str(&format!("{}:{}-{}:{}", self.first_line_number(), self.first_column() + 1, self.last_line_number(), self.last_column() + 1))
- }
-}
-
-impl Debug for Location {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f,
- "Location(first_line_number={}, first_column={}, first_offset={}, last_line_number={}, last_column={}, last_offset={})",
- self.first_line_number(),
- self.first_column(),
- self.first_offset,
- self.last_line_number(),
- self.last_column(),
- self.last_offset
- )
- }
-}
-
-impl Eq for Location {}
-
-impl PartialEq for Location {
- fn eq(&self, other: &Self) -> bool {
- Rc::ptr_eq(&self.compilation_unit, &other.compilation_unit) &&
- self.first_offset == other.first_offset &&
- self.last_offset == other.last_offset
- }
-}
-
-impl Ord for Location {
- fn cmp(&self, other: &Self) -> Ordering {
- self.partial_cmp(other).unwrap_or(Ordering::Equal)
- }
-}
-
-impl PartialOrd for Location {
- fn partial_cmp(&self, other: &Self) -> Option {
- self.first_offset.partial_cmp(&other.first_offset)
- }
-}
-
-impl Location {
- /// Builds a location.
- pub fn with_offsets(
- compilation_unit: &Rc,
- first_offset: usize,
- last_offset: usize,
- ) -> Self {
- Self {
- compilation_unit: compilation_unit.clone(),
- first_offset,
- last_offset,
- }
- }
-
- /// Builds a location.
- pub fn with_offset(compilation_unit: &Rc, offset: usize) -> Self {
- Self::with_offsets(compilation_unit, offset, offset)
- }
-
- /// Build a location by combining two locations. `self`
- /// serves as the first location, while `other` serves as the
- /// last location.
- pub fn combine_with(&self, other: Location) -> Self {
- Self {
- compilation_unit: self.compilation_unit.clone(),
- first_offset: self.first_offset,
- last_offset: other.last_offset,
- }
- }
-
- /// Build a location by combining two locations. `self`
- /// serves as the first location, while the first column and first line
- /// of `other` serve as the last location.
- pub fn combine_with_start_of(&self, other: Location) -> Self {
- Self {
- compilation_unit: self.compilation_unit.clone(),
- first_offset: self.first_offset,
- last_offset: other.first_offset,
- }
- }
-
- /// The compilation unit that this location belongs to.
- pub fn compilation_unit(&self) -> Rc {
- self.compilation_unit.clone()
- }
-
- /// First line number, counted from one.
- pub fn first_line_number(&self) -> usize {
- self.compilation_unit.get_line_number(self.first_offset)
- }
-
- /// Last line number, counted from one.
- pub fn last_line_number(&self) -> usize {
- self.compilation_unit.get_line_number(self.last_offset)
- }
-
- // The first byte offset of this location.
- pub fn first_offset(&self) -> usize {
- self.first_offset
- }
-
- // The last byte offset of this location.
- pub fn last_offset(&self) -> usize {
- self.last_offset
- }
-
- /// Zero based first column of the location in code points.
- pub fn first_column(&self) -> usize {
- self.compilation_unit.get_column(self.first_offset)
- }
-
- /// Zero based last column of the location in code points.
- pub fn last_column(&self) -> usize {
- self.compilation_unit.get_column(self.last_offset)
- }
-
- pub fn character_count(&self) -> usize {
- self.compilation_unit.text()[self.first_offset..self.last_offset].chars().count()
- }
-
- /// Indicates whether a previous location and a next location
- /// have a line break in between.
- pub fn line_break(&self, other: &Self) -> bool {
- self.last_line_number() != other.first_line_number()
- }
-
- /// Returns the source text comprising the source location.
- pub fn text(&self) -> String {
- self.compilation_unit.text()[self.first_offset..self.last_offset].to_owned()
- }
-
- /// Shifts a count of characters off this location until end-of-file.
- pub fn shift_until_eof(&self, count: usize) -> Location {
- let mut ch = CharacterReader::from(&self.compilation_unit.text()[self.first_offset..]);
- for _ in 0..count {
- if ch.next().is_none() {
- break;
- }
- }
- Self::with_offsets(&self.compilation_unit, self.first_offset + ch.index(), self.last_offset)
- }
-
- /// Shifts the count of whitespace characters in a text off this location.
- pub fn shift_whitespace(&self, text: &str) -> Location {
- self.shift_until_eof(count_first_whitespace_characters(text))
- }
-}
\ No newline at end of file
diff --git a/crates/parser/diagnostics.rs b/crates/parser/diagnostics.rs
deleted file mode 100644
index 34522bf..0000000
--- a/crates/parser/diagnostics.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Defines the diagnostics produced by the parser.
-
-mod diagnostics;
-pub use diagnostics::*;
-mod diagnostic_kind;
-pub use diagnostic_kind::*;
\ No newline at end of file
diff --git a/crates/parser/diagnostics/diagnostic_kind.rs b/crates/parser/diagnostics/diagnostic_kind.rs
deleted file mode 100644
index e03cb70..0000000
--- a/crates/parser/diagnostics/diagnostic_kind.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-#[repr(i32)]
-#[derive(Eq, PartialEq, Clone, Copy)]
-pub enum DiagnosticKind {
- InvalidEscapeValue = 1024,
- UnexpectedEnd = 1025,
- UnallowedNumericSuffix = 1026,
- StringLiteralMustBeTerminatedBeforeLineBreak = 1027,
- Expecting = 1028,
- ExpectingIdentifier = 1029,
- ExpectingExpression = 1030,
- ExpectingXmlName = 1031,
- ExpectingXmlAttributeValue = 1032,
- IllegalNullishCoalescingLeftOperand = 1033,
- WrongParameterPosition = 1034,
- DuplicateRestParameter = 1035,
- NotAllowedHere = 1036,
- MalformedRestParameter = 1037,
- IllegalForInInitializer = 1038,
- MultipleForInBindings = 1039,
- UndefinedLabel = 1040,
- IllegalContinue = 1041,
- IllegalBreak = 1042,
- ExpressionMustNotFollowLineBreak = 1043,
- TokenMustNotFollowLineBreak = 1044,
- ExpectingStringLiteral = 1045,
- DuplicateAttribute = 1046,
- DuplicateAccessModifier = 1047,
- ExpectingDirectiveKeyword = 1048,
- UnallowedAttribute = 1049,
- UseDirectiveMustContainPublic = 1050,
- MalformedEnumMember = 1051,
- FunctionMayNotBeGenerator = 1052,
- FunctionMayNotBeAsynchronous = 1053,
- FunctionMustNotContainBody = 1054,
- FunctionMustContainBody = 1055,
- FunctionMustNotContainAnnotations = 1056,
- NestedClassesNotAllowed = 1057,
- DirectiveNotAllowedInInterface = 1058,
- FailedParsingAsDocTag = 1059,
- UnrecognizedAsDocTag = 1060,
- UnrecognizedProxy = 1061,
- EnumMembersMustBeConst = 1062,
- ConstructorMustNotSpecifyResultType = 1063,
- UnrecognizedMetadataSyntax = 1064,
- FailedToIncludeFile = 1065,
- ParentSourceIsNotAFile = 1066,
- CircularIncludeDirective = 1067,
- MalformedDestructuring = 1068,
- XmlPrefixNotDefined = 1069,
- RedefiningXmlAttribute = 1070,
- InvalidXmlPi = 1071,
- XmlPiUnknownAttribute = 1072,
- XmlPiVersion = 1073,
- XmlPiEncoding = 1074,
- XmlMustConsistOfExactly1Element = 1075,
- XmlNameAtMostOneColon = 1076,
- UnexpectedCharacter = 1077,
- InputEndedBeforeReachingClosingQuoteForString = 1078,
- InputEndedBeforeReachingClosingSeqForCData = 1079,
- InputEndedBeforeReachingClosingSeqForPi = 1080,
- InputEndedBeforeReachingClosingSeqForXmlComment = 1081,
- InputEndedBeforeReachingClosingSeqForMultiLineComment = 1082,
- InputEndedBeforeReachingClosingSlashForRegExp = 1083,
- InputEndedBeforeReachingClosingQuoteForAttributeValue = 1084,
- ExpectingEitherSemicolonOrNewLineHere = 1085,
- CssInvalidHexEscape = 1086,
- ExpectingDirective = 1087,
- ExpectingStatement = 1088,
- Unexpected = 1089,
- XmlClosingTagNameMustBeEquals = 1090,
-}
-
-impl DiagnosticKind {
- pub fn id(&self) -> i32 {
- *self as i32
- }
-}
\ No newline at end of file
diff --git a/crates/parser/diagnostics/diagnostics.rs b/crates/parser/diagnostics/diagnostics.rs
deleted file mode 100644
index 351b58c..0000000
--- a/crates/parser/diagnostics/diagnostics.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use std::any::Any;
-
-use maplit::hashmap;
-use crate::ns::*;
-
-#[path = "diagnostics_english_resources.rs"]
-mod diagnostics_english_resources;
-
-/// Represents a diagnostic originated from a compilation unit.
-///
-/// Arguments are formatted using integer keys counted from 1 (one).
-#[derive(Clone)]
-pub struct Diagnostic {
- pub(crate) location: Location,
- pub(crate) kind: DiagnosticKind,
- pub(crate) is_warning: bool,
- pub(crate) is_verify_error: bool,
- pub(crate) arguments: Vec>,
- pub(crate) custom_kind: RefCell>>,
-}
-
-impl Eq for Diagnostic {}
-
-impl PartialEq for Diagnostic {
- fn eq(&self, other: &Self) -> bool {
- self.location == other.location &&
- self.kind == other.kind
- }
-}
-
-impl Ord for Diagnostic {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.location.cmp(&other.location)
- }
-}
-
-impl PartialOrd for Diagnostic {
- fn partial_cmp(&self, other: &Self) -> Option {
- self.location.partial_cmp(&other.location)
- }
-}
-
-impl Diagnostic {
- pub fn new_syntax_error(location: &Location, kind: DiagnosticKind, arguments: Vec>) -> Self {
- Self {
- location: location.clone(),
- kind,
- is_verify_error: false,
- is_warning: false,
- arguments,
- custom_kind: RefCell::new(None),
- }
- }
-
- pub fn new_verify_error(location: &Location, kind: DiagnosticKind, arguments: Vec>) -> Self {
- Self {
- location: location.clone(),
- kind,
- is_verify_error: true,
- is_warning: false,
- arguments,
- custom_kind: RefCell::new(None),
- }
- }
-
- pub fn new_warning(location: &Location, kind: DiagnosticKind, arguments: Vec>) -> Self {
- Self {
- location: location.clone(),
- kind,
- is_verify_error: false,
- is_warning: true,
- arguments,
- custom_kind: RefCell::new(None),
- }
- }
-
- pub fn location(&self) -> Location {
- self.location.clone()
- }
-
- pub fn kind(&self) -> DiagnosticKind {
- self.kind.clone()
- }
-
- pub fn is_warning(&self) -> bool {
- self.is_warning
- }
-
- pub fn is_error(&self) -> bool {
- !self.is_warning
- }
-
- pub fn is_syntax_error(&self) -> bool {
- !self.is_verify_error && !self.is_warning
- }
-
- pub fn is_verify_error(&self) -> bool {
- self.is_verify_error
- }
-
- pub fn arguments(&self) -> Vec> {
- self.arguments.clone()
- }
-
- pub fn id(&self) -> i32 {
- self.kind.id()
- }
-
- pub fn custom_kind(&self) -> Option> {
- self.custom_kind.borrow().clone()
- }
-
- pub fn set_custom_kind(&self, id: Option>) {
- self.custom_kind.replace(id);
- }
-
- /// Formats the diagnostic by overriding the message text.
- pub fn format_with_message(&self, message: &str, id: Option) -> String {
- let category = (if self.is_verify_error {
- "Verify error"
- } else if self.is_warning {
- "Warning"
- } else {
- "Syntax error"
- }).to_owned();
-
- let file_path = self.location.compilation_unit.file_path.clone().map_or("".to_owned(), |s| format!("{s}:"));
- let line = self.location.first_line_number();
- let column = self.location.first_column() + 1;
- if let Some(id) = id {
- format!("{file_path}{line}:{column}: {category} #{}: {message}", id.to_string())
- } else {
- format!("{file_path}{line}:{column}: {category}: {message}")
- }
- }
-
- /// Formats the diagnostic in English.
- pub fn format_english(&self) -> String {
- self.format_with_message(&self.format_message_english(), Some(self.id()))
- }
-
- pub fn format_message_english(&self) -> String {
- self.format_message(&diagnostics_english_resources::DATA)
- }
-
- pub fn format_message(&self, messages: &HashMap) -> String {
- let mut string_arguments: HashMap = hashmap!{};
- let mut i = 1;
- for argument in &self.arguments {
- string_arguments.insert(i.to_string(), argument.to_string());
- i += 1;
- }
- use late_format::LateFormat;
- let Some(msg) = messages.get(&self.id()) else {
- let id = self.id();
- panic!("Message resource is missing for ID {id}");
- };
- msg.late_format(string_arguments)
- }
-}
-
-/// The `diagarg![...]` literal is used for initializing
-/// diagnostic arguments.
-///
-/// For example: `diagarg![token, "foo".to_owned()]`.
-pub macro diagarg {
- ($($value:expr),*) => { vec![ $(Rc::new($value)),* ] },
-}
-
-pub trait DiagnosticArgument: Any + ToString + 'static {
-}
-
-impl DiagnosticArgument for String {}
-
-impl DiagnosticArgument for Token {}
\ No newline at end of file
diff --git a/crates/parser/diagnostics/diagnostics_english_resources.rs b/crates/parser/diagnostics/diagnostics_english_resources.rs
deleted file mode 100644
index 192a7e7..0000000
--- a/crates/parser/diagnostics/diagnostics_english_resources.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use lazy_static::lazy_static;
-use maplit::hashmap;
-use crate::ns::*;
-
-lazy_static! {
- pub static ref DATA: HashMap = hashmap! {
- // DiagnosticKind::K.id() => ".".into(),
- DiagnosticKind::InvalidEscapeValue.id() => "Invalid escape value.".into(),
- DiagnosticKind::UnexpectedEnd.id() => "Unexpected end-of-file.".into(),
- DiagnosticKind::UnallowedNumericSuffix.id() => "Unallowed numeric suffix.".into(),
- DiagnosticKind::StringLiteralMustBeTerminatedBeforeLineBreak.id() => "A string literal must be terminated before the line break.".into(),
- DiagnosticKind::Expecting.id() => "Expecting {1} before {2}.".into(),
- DiagnosticKind::ExpectingIdentifier.id() => "Expecting identifier before {1}.".into(),
- DiagnosticKind::ExpectingExpression.id() => "Expecting expression before {1}.".into(),
- DiagnosticKind::ExpectingXmlName.id() => "Expecting XML name before {1}.".into(),
- DiagnosticKind::ExpectingXmlAttributeValue.id() => "Expecting XML attribute value before {1}.".into(),
- DiagnosticKind::IllegalNullishCoalescingLeftOperand.id() => "Illegal nullish coalescing left operand.".into(),
- DiagnosticKind::WrongParameterPosition.id() => "Wrong parameter position.".into(),
- DiagnosticKind::DuplicateRestParameter.id() => "Duplicate rest parameter.".into(),
- DiagnosticKind::NotAllowedHere.id() => "{1} not allowed here.".into(),
- DiagnosticKind::MalformedRestParameter.id() => "Malformed rest parameter.".into(),
- DiagnosticKind::IllegalForInInitializer.id() => "Illegal 'for..in' initializer.".into(),
- DiagnosticKind::MultipleForInBindings.id() => "Multiple 'for..in' bindings are not allowed.".into(),
- DiagnosticKind::UndefinedLabel.id() => "Undefined label '{1}'.".into(),
- DiagnosticKind::IllegalContinue.id() => "Illegal continue statement.".into(),
- DiagnosticKind::IllegalBreak.id() => "Illegal break statement.".into(),
- DiagnosticKind::ExpressionMustNotFollowLineBreak.id() => "Expression must not follow line break.".into(),
- DiagnosticKind::TokenMustNotFollowLineBreak.id() => "Token must not follow line break.".into(),
- DiagnosticKind::ExpectingStringLiteral.id() => "Expecting string literal before {1}.".into(),
- DiagnosticKind::DuplicateAttribute.id() => "Duplicate attribute.".into(),
- DiagnosticKind::DuplicateAccessModifier.id() => "Duplicate access modifier.".into(),
- DiagnosticKind::ExpectingDirectiveKeyword.id() => "Expecting either 'var', 'const', 'function', 'class' or 'interface.".into(),
- DiagnosticKind::UnallowedAttribute.id() => "Unallowed attribute.".into(),
- DiagnosticKind::UseDirectiveMustContainPublic.id() => "Use directive must contain the 'public' attribute.".into(),
- DiagnosticKind::MalformedEnumMember.id() => "Malformed enumeration member.".into(),
- DiagnosticKind::FunctionMayNotBeGenerator.id() => "Function may not be generator.".into(),
- DiagnosticKind::FunctionMayNotBeAsynchronous.id() => "Function may not be asynchronous.".into(),
- DiagnosticKind::FunctionMustNotContainBody.id() => "Function must not contain body.".into(),
- DiagnosticKind::FunctionMustContainBody.id() => "Function must contain body.".into(),
- DiagnosticKind::FunctionMustNotContainAnnotations.id() => "Function must not contain annotations.".into(),
- DiagnosticKind::NestedClassesNotAllowed.id() => "Nested classes are not allowed.".into(),
- DiagnosticKind::DirectiveNotAllowedInInterface.id() => "Directive not allowed in interface.".into(),
- DiagnosticKind::FailedParsingAsDocTag.id() => "Failed parsing contents of ASDoc tag: '@{1}'.".into(),
- DiagnosticKind::UnrecognizedAsDocTag.id() => "Unrecognized ASDoc tag: '@{1}'.".into(),
- DiagnosticKind::UnrecognizedProxy.id() => "Unrecognized proxy: '{1}'.".into(),
- DiagnosticKind::EnumMembersMustBeConst.id() => "Enumeration members must be 'const'.".into(),
- DiagnosticKind::UnrecognizedMetadataSyntax.id() => "Unrecognized meta-data syntax.".into(),
- DiagnosticKind::FailedToIncludeFile.id() => "Failed to include file.".into(),
- DiagnosticKind::ParentSourceIsNotAFile.id() => "Parent source is not a file.".into(),
- DiagnosticKind::CircularIncludeDirective.id() => "Circular include directive.".into(),
- DiagnosticKind::MalformedDestructuring.id() => "Malformed destructuring.".into(),
- DiagnosticKind::XmlPrefixNotDefined.id() => "Prefix not defined: '{1}'.".into(),
- DiagnosticKind::RedefiningXmlAttribute.id() => "Redefining attribute: '{1}'.".into(),
- DiagnosticKind::InvalidXmlPi.id() => "Invalid processing instruction.".into(),
- DiagnosticKind::XmlPiUnknownAttribute.id() => "Unknown attribute at processing instruction: '{1}'.".into(),
- DiagnosticKind::XmlPiVersion.id() => "XML version must be '1.0'.".into(),
- DiagnosticKind::XmlPiEncoding.id() => "XML encoding must be either 'utf-8' or 'utf-16'.".into(),
- DiagnosticKind::XmlMustConsistOfExactly1Element.id() => "Document must consist of exactly one element.".into(),
- DiagnosticKind::XmlNameAtMostOneColon.id() => "XML name may have at most one colon.".into(),
- DiagnosticKind::UnexpectedCharacter.id() => "Unexpected character. '{1}' is not allowed here".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString.id() => "Input ended before reaching the closing quotation mark for a string literal.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingSeqForCData.id() => "Input ended before reaching the closing ']]>' for a CDATA.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingSeqForPi.id() => "Input ended before reaching the closing '?>' for a processing instruction.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingSeqForXmlComment.id() => "Input ended before reaching the closing '-->' for a comment.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingSeqForMultiLineComment.id() => "Input ended before reaching the closing '*/' for a comment.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingSlashForRegExp.id() => "Input ended before reaching the closing slash for a regular expression.".into(),
- DiagnosticKind::InputEndedBeforeReachingClosingQuoteForAttributeValue.id() => "Input ended before reaching the closing quotation mark for an attribute value.".into(),
- DiagnosticKind::ExpectingEitherSemicolonOrNewLineHere.id() => "Expecting either a semicolon or a new line here.".into(),
- DiagnosticKind::CssInvalidHexEscape.id() => "Invalid hexadecimal escape: '\\{1}'.".into(),
- DiagnosticKind::ExpectingDirective.id() => "Expecting directive before {1}.".into(),
- DiagnosticKind::ExpectingStatement.id() => "Expecting statement before {1}.".into(),
- DiagnosticKind::Unexpected.id() => "Unexpected {1}.".into(),
- DiagnosticKind::XmlClosingTagNameMustBeEquals.id() => "Closing tag name must be equals '{1}'.".into(),
- // DiagnosticKind::K.id() => ".".into(),
- };
-}
\ No newline at end of file
diff --git a/crates/parser/lib.rs b/crates/parser/lib.rs
deleted file mode 100644
index c82a279..0000000
--- a/crates/parser/lib.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(decl_macro)]
-#![feature(try_blocks)]
-
-pub mod tree;
-pub mod compilation_unit;
-pub mod diagnostics;
-pub mod operator;
-pub mod parser;
-pub mod util;
-
-pub mod ns;
\ No newline at end of file
diff --git a/crates/parser/ns.rs b/crates/parser/ns.rs
deleted file mode 100644
index 09adc4b..0000000
--- a/crates/parser/ns.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//! The `ns` module is an union of all of the parser modules.
-
-pub use crate::tree::*;
-pub use crate::compilation_unit::*;
-pub use crate::diagnostics::*;
-pub use crate::operator::*;
-pub use crate::parser::*;
-pub use crate::util::*;
\ No newline at end of file
diff --git a/crates/parser/operator.rs b/crates/parser/operator.rs
deleted file mode 100644
index bbad3db..0000000
--- a/crates/parser/operator.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Defines the ActionScript 3 operators.
-
-mod operator;
-pub use operator::*;
-mod operator_precedence;
-pub use operator_precedence::*;
\ No newline at end of file
diff --git a/crates/parser/operator/operator.rs b/crates/parser/operator/operator.rs
deleted file mode 100644
index 69cd19a..0000000
--- a/crates/parser/operator/operator.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use crate::ns::*;
-use serde::{Serialize, Deserialize};
-
-/// Represents an ActionScript operator.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
-pub enum Operator {
- PostIncrement,
- PostDecrement,
- NonNull,
- Delete,
- Void,
- Typeof,
- Await,
- Yield,
- PreIncrement,
- PreDecrement,
- Positive,
- Negative,
- BitwiseNot,
- LogicalNot,
-
- Power,
- Multiply,
- Divide,
- Remainder,
- Add,
- Subtract,
- ShiftLeft,
- ShiftRight,
- ShiftRightUnsigned,
- Lt,
- Gt,
- Le,
- Ge,
- Instanceof,
- In,
- NotIn,
- Is,
- IsNot,
- As,
- Equals,
- NotEquals,
- StrictEquals,
- StrictNotEquals,
- BitwiseAnd,
- BitwiseXor,
- BitwiseOr,
- LogicalAnd,
- LogicalXor,
- LogicalOr,
- NullCoalescing,
-}
-
-/// Represents binary operator associativity.
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum BinaryAssociativity {
- LeftToRight,
- RightToLeft,
-}
-
-/// Represents an ActionScript binary operator.
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub struct BinaryOperator(pub Operator, pub OperatorPrecedence, pub BinaryAssociativity);
-
-impl BinaryOperator {
- pub fn operator(&self) -> Operator {
- self.0
- }
-
- pub fn precedence(&self) -> OperatorPrecedence {
- self.1
- }
-
- pub fn associativity(&self) -> BinaryAssociativity {
- self.2
- }
-
- pub fn right_precedence(&self) -> OperatorPrecedence {
- if self.operator() == Operator::NullCoalescing {
- OperatorPrecedence::BitwiseOr
- } else {
- self.precedence().add(if self.associativity() == BinaryAssociativity::LeftToRight { 1 } else { 0 }).unwrap()
- }
- }
-}
-
-impl TryFrom for BinaryOperator {
- type Error = ();
- /// Constructs `BinaryOperator` from abstract operator.
- fn try_from(value: Operator) -> Result {
- match value {
- Operator::Multiply => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
- Operator::Divide => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
- Operator::Remainder => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
- Operator::Add => Ok(BinaryOperator(value, OperatorPrecedence::Additive, BinaryAssociativity::LeftToRight)),
- Operator::Subtract => Ok(BinaryOperator(value, OperatorPrecedence::Additive, BinaryAssociativity::LeftToRight)),
- Operator::ShiftLeft => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
- Operator::ShiftRight => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
- Operator::ShiftRightUnsigned => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
- Operator::Lt => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Gt => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Le => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Ge => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::As => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::In => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::NotIn => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Instanceof => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Is => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::IsNot => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
- Operator::Equals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
- Operator::NotEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
- Operator::StrictEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
- Operator::StrictNotEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
- Operator::BitwiseAnd => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseAnd, BinaryAssociativity::LeftToRight)),
- Operator::BitwiseXor => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseXor, BinaryAssociativity::LeftToRight)),
- Operator::BitwiseOr => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseOr, BinaryAssociativity::LeftToRight)),
- Operator::LogicalAnd => Ok(BinaryOperator(value, OperatorPrecedence::LogicalAnd, BinaryAssociativity::LeftToRight)),
- Operator::LogicalXor => Ok(BinaryOperator(value, OperatorPrecedence::LogicalXor, BinaryAssociativity::LeftToRight)),
- Operator::LogicalOr => Ok(BinaryOperator(value, OperatorPrecedence::LogicalOrAndOther, BinaryAssociativity::LeftToRight)),
- Operator::NullCoalescing => Ok(BinaryOperator(value, OperatorPrecedence::LogicalOrAndOther, BinaryAssociativity::LeftToRight)),
-
- Operator::Power => Ok(BinaryOperator(value, OperatorPrecedence::Exponentiation, BinaryAssociativity::RightToLeft)),
-
- _ => Err(()),
- }
- }
-}
\ No newline at end of file
diff --git a/crates/parser/operator/operator_precedence.rs b/crates/parser/operator/operator_precedence.rs
deleted file mode 100644
index 68b0abe..0000000
--- a/crates/parser/operator/operator_precedence.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use num_derive::FromPrimitive;
-use num_traits::FromPrimitive;
-
-#[derive(FromPrimitive)]
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-#[repr(u32)]
-pub enum OperatorPrecedence {
- Postfix = 16,
- Unary = 15,
- Exponentiation = 14,
- Multiplicative = 13,
- Additive = 12,
- Shift = 11,
- Relational = 10,
- Equality = 9,
- BitwiseAnd = 8,
- BitwiseXor = 7,
- BitwiseOr = 6,
- LogicalAnd = 5,
- LogicalXor = 4,
- /// Includes logical OR and nullish coalescing (`??`).
- LogicalOrAndOther = 3,
- /// Includes assignment operators, conditional operator, function expression and `yield` operator.
- AssignmentAndOther = 2,
- List = 1,
-}
-
-impl OperatorPrecedence {
- pub fn add(&self, value: u32) -> Option {
- FromPrimitive::from_u32(*self as u32 + value)
- }
-
- pub fn value_of(&self) -> u32 {
- *self as u32
- }
-
- pub fn includes(&self, other: &Self) -> bool {
- *self <= *other
- }
-}
-
-impl TryFrom for OperatorPrecedence {
- type Error = ();
- fn try_from(value: u32) -> Result {
- if let Some(v) = FromPrimitive::from_u32(value as u32) { Ok(v) } else { Err(()) }
- }
-}
-
-#[derive(FromPrimitive)]
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-#[repr(u32)]
-pub enum CssOperatorPrecedence {
- Unary = 3,
- MultiValue = 2,
- Array = 1,
-}
-
-impl CssOperatorPrecedence {
- pub fn add(&self, value: u32) -> Option {
- FromPrimitive::from_u32(*self as u32 + value)
- }
-
- pub fn value_of(&self) -> u32 {
- *self as u32
- }
-
- pub fn includes(&self, other: &Self) -> bool {
- *self <= *other
- }
-}
-
-impl TryFrom for CssOperatorPrecedence {
- type Error = ();
- fn try_from(value: u32) -> Result {
- if let Some(v) = FromPrimitive::from_u32(value as u32) { Ok(v) } else { Err(()) }
- }
-}
\ No newline at end of file
diff --git a/crates/parser/parser.rs b/crates/parser/parser.rs
deleted file mode 100644
index 897a3e2..0000000
--- a/crates/parser/parser.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-//! Defines the parser and the tokenizer.
-//!
-//! Using the methods of the `ParserFacade` structure is the most common way of parsing
-//! programs until end-of-file.
-
-mod character_validator;
-pub use character_validator::*;
-mod context;
-pub use context::*;
-mod reserved_word;
-pub use reserved_word::*;
-mod parser;
-pub use parser::*;
-mod css_parser;
-pub use css_parser::*;
-mod css_tokenizer;
-pub use css_tokenizer::*;
-mod parser_error;
-pub use parser_error::*;
-mod token;
-pub use token::*;
-mod tokenizer;
-pub use tokenizer::*;
\ No newline at end of file
diff --git a/crates/parser/parser/character_validator.rs b/crates/parser/parser/character_validator.rs
deleted file mode 100644
index ef06b61..0000000
--- a/crates/parser/parser/character_validator.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-//use lazy_regex::{Lazy, Regex, lazy_regex};
-use unicode_general_category::{get_general_category, GeneralCategory};
-
-// pub(crate) static CR_OR_CRLF_REGEX: Lazy = lazy_regex!(r"\r\n?");
-
-/// The `CharacterValidator` structure defines static methods for character
-/// validation.
-pub struct CharacterValidator;
-
-impl CharacterValidator {
- /// Returns the count of indentation characters in a string.
- pub fn indent_count(string: &str) -> usize {
- let mut n: usize = 0;
- for ch in string.chars() {
- if !CharacterValidator::is_whitespace(ch) {
- break;
- }
- n += 1;
- }
- n
- }
-
- pub fn is_whitespace(ch: char) -> bool {
- if ch == '\x20' || ch == '\x09' || ch == '\x08'
- || ch == '\x0C' || ch == '\u{A0}' {
- return true;
- }
- let category = get_general_category(ch);
- category == GeneralCategory::SpaceSeparator
- }
-
- pub fn is_line_terminator(ch: char) -> bool {
- ch == '\x0A' || ch == '\x0D' || ch == '\u{2028}' || ch == '\u{2029}'
- }
-
- pub fn is_bin_digit(ch: char) -> bool {
- ch == '\x30' || ch == '\x31'
- }
-
- pub fn is_dec_digit(ch: char) -> bool {
- ch >= '\x30' && ch <= '\x39'
- }
-
- pub fn is_hex_digit(ch: char) -> bool {
- CharacterValidator::is_dec_digit(ch) || (ch >= '\x41' && ch <= '\x46') || (ch >= '\x61' && ch <= '\x66')
- }
-
- /// Returns the mathematical value of a hexadecimal digit.
- pub fn hex_digit_mv(ch: char) -> Option {
- if ch >= 'A' && ch <= 'F' {
- Some((ch as u32) - 0x41 + 10)
- } else if ch >= 'a' && ch <= 'f' {
- Some((ch as u32) - 0x61 + 10)
- } else if ch >= '0' && ch <= '9' {
- Some((ch as u32) - 0x30)
- } else {
- None
- }
- }
-
- /// Returns the mathematical value of a binary digit.
- pub fn bin_digit_mv(ch: char) -> Option {
- if ch >= '0' && ch <= '1' {
- Some((ch as u32) - 0x30)
- } else {
- None
- }
- }
-
- pub fn is_css_identifier_start(ch: char) -> bool {
- (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
- }
-
- pub fn is_css_identifier_part(ch: char) -> bool {
- (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') || ch == '_' || ch == '-'
- }
-
- pub fn is_identifier_start(ch: char) -> bool {
- if ch == '\x5f' || ch == '\x24' {
- return true;
- }
- let category = get_general_category(ch);
- [
- GeneralCategory::LowercaseLetter,
- GeneralCategory::UppercaseLetter,
- GeneralCategory::ModifierLetter,
- GeneralCategory::OtherLetter,
- GeneralCategory::TitlecaseLetter,
- GeneralCategory::LetterNumber,
- ].contains(&category)
- }
-
- pub fn is_identifier_part(ch: char) -> bool {
- if ch == '\x5f' || ch == '\x24' {
- return true;
- }
- let category = get_general_category(ch);
- [
- GeneralCategory::LowercaseLetter,
- GeneralCategory::UppercaseLetter,
- GeneralCategory::ModifierLetter,
- GeneralCategory::OtherLetter,
- GeneralCategory::TitlecaseLetter,
- GeneralCategory::LetterNumber,
- GeneralCategory::NonspacingMark,
- GeneralCategory::SpacingMark,
- GeneralCategory::ConnectorPunctuation,
- GeneralCategory::DecimalNumber,
- ].contains(&category)
- }
-
- pub fn is_xml_name_start(ch: char) -> bool {
- if ch == '\x5f' || ch == ':' {
- return true;
- }
- let category = get_general_category(ch);
- [
- GeneralCategory::LowercaseLetter,
- GeneralCategory::UppercaseLetter,
- GeneralCategory::ModifierLetter,
- GeneralCategory::OtherLetter,
- GeneralCategory::TitlecaseLetter,
- GeneralCategory::LetterNumber,
- ].contains(&category)
- }
-
- pub fn is_xml_name_part(ch: char) -> bool {
- if ch == '\x5f' || ch == ':' || ch == '.' || ch == '-' {
- return true;
- }
- let category = get_general_category(ch);
- [
- GeneralCategory::LowercaseLetter,
- GeneralCategory::UppercaseLetter,
- GeneralCategory::ModifierLetter,
- GeneralCategory::OtherLetter,
- GeneralCategory::TitlecaseLetter,
- GeneralCategory::LetterNumber,
- GeneralCategory::DecimalNumber,
- ].contains(&category)
- }
-
- pub fn is_xml_whitespace(ch: char) -> bool {
- ch == '\x20' || ch == '\x09' || ch == '\x0A' || ch == '\x0D'
- }
-}
\ No newline at end of file
diff --git a/crates/parser/parser/context.rs b/crates/parser/parser/context.rs
deleted file mode 100644
index 3132d5b..0000000
--- a/crates/parser/parser/context.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-use crate::ns::*;
-
-/// Context used to control the parsing of an expression.
-#[derive(Clone)]
-pub struct ParserExpressionContext {
- pub min_precedence: OperatorPrecedence,
- pub allow_in: bool,
- pub allow_assignment: bool,
-}
-
-impl Default for ParserExpressionContext {
- fn default() -> Self {
- Self {
- min_precedence: OperatorPrecedence::List,
- allow_in: true,
- allow_assignment: true,
- }
- }
-}
-
-#[derive(Clone)]
-pub enum ParserDirectiveContext {
- Default,
- TopLevel,
- PackageBlock,
- ClassBlock {
- name: String,
- },
- InterfaceBlock,
- EnumBlock,
- ConstructorBlock {
- super_statement_found: Rc>,
- },
- WithControl {
- super_statement_found: Option>>,
- to_be_labeled: Option,
- control_context: ParserControlFlowContext,
- labels: HashMap,
- },
-}
-
-impl ParserDirectiveContext {
- pub fn may_contain_super_statement(&self) -> bool {
- matches!(self, Self::ConstructorBlock { .. }) || matches!(self, Self::WithControl { .. })
- }
-
- pub fn super_statement_found(&self) -> bool {
- match self {
- Self::ConstructorBlock { super_statement_found } => super_statement_found.get(),
- Self::WithControl { super_statement_found, .. } => super_statement_found.as_ref().or(Some(&Rc::new(Cell::new(false)))).unwrap().get(),
- _ => false,
- }
- }
-
- pub fn set_super_statement_found(&self, value: bool) {
- match self {
- Self::ConstructorBlock { super_statement_found } => { super_statement_found.set(value) },
- Self::WithControl { super_statement_found, .. } => {
- if let Some(found) = super_statement_found.as_ref() {
- found.set(value);
- }
- },
- _ => {},
- }
- }
-
- pub fn function_name_is_constructor(&self, name: &(String, Location)) -> bool {
- if let ParserDirectiveContext::ClassBlock { name: ref name_1 } = self {
- &name.0 == name_1
- } else {
- false
- }
- }
-
- pub fn is_top_level_or_package(&self) -> bool {
- matches!(self, ParserDirectiveContext::TopLevel) || matches!(self, ParserDirectiveContext::PackageBlock)
- }
-
- pub fn is_type_block(&self) -> bool {
- match self {
- Self::ClassBlock { .. } |
- Self::InterfaceBlock |
- Self::EnumBlock => true,
- _ => false,
- }
- }
-
- pub fn clone_control(&self) -> Self {
- match self {
- Self::WithControl { .. } => self.clone(),
- _ => Self::Default,
- }
- }
-
- pub fn override_control_context(&self, label_only: bool, mut context: ParserControlFlowContext) -> Self {
- let mut prev_context = None;
- let mut label = None;
- let mut super_statement_found: Option>> = None;
- let mut labels = match self {
- Self::WithControl { control_context, labels, to_be_labeled: label1, super_statement_found: super_found_1 } => {
- prev_context = Some(control_context.clone());
- label = label1.clone();
- super_statement_found = super_found_1.clone();
- labels.clone()
- },
- _ => HashMap::new(),
- };
- if let Some(label) = label.clone() {
- labels.insert(label, context.clone());
- }
- if label_only {
- context = prev_context.unwrap_or(ParserControlFlowContext {
- breakable: false,
- iteration: false,
- });
- }
- Self::WithControl { control_context: context, labels, to_be_labeled: None, super_statement_found }
- }
-
- pub fn put_label(&self, label: String) -> Self {
- match self {
- Self::WithControl { control_context, labels, to_be_labeled: _, super_statement_found } => Self::WithControl {
- to_be_labeled: Some(label),
- control_context: control_context.clone(),
- labels: labels.clone(),
- super_statement_found: super_statement_found.clone(),
- },
- _ => Self::WithControl {
- to_be_labeled: Some(label),
- control_context: ParserControlFlowContext {
- breakable: false,
- iteration: false,
- },
- labels: HashMap::new(),
- super_statement_found: match self {
- Self::ConstructorBlock { super_statement_found } => Some(super_statement_found.clone()),
- _ => None,
- },
- },
- }
- }
-
- pub fn is_label_defined(&self, label: String) -> bool {
- self.resolve_label(label).is_some()
- }
-
- pub fn resolve_label(&self, label: String) -> Option {
- if let Self::WithControl { labels, .. } = &self { labels.get(&label).map(|c| c.clone()) } else { None }
- }
-
- pub fn is_break_allowed(&self, label: Option) -> bool {
- if let Some(label) = label {
- let context = self.resolve_label(label);
- if let Some(context) = context { context.breakable } else { false }
- } else {
- if let Self::WithControl { control_context, .. } = &self { control_context.breakable } else { false }
- }
- }
-
- pub fn is_continue_allowed(&self, label: Option) -> bool {
- if let Some(label) = label {
- let context = self.resolve_label(label);
- if let Some(context) = context { context.iteration } else { false }
- } else {
- if let Self::WithControl { control_context, .. } = &self { control_context.iteration } else { false }
- }
- }
-}
-
-#[derive(Clone)]
-pub struct ParserControlFlowContext {
- pub breakable: bool,
- pub iteration: bool,
-}
\ No newline at end of file
diff --git a/crates/parser/parser/css_parser.rs b/crates/parser/parser/css_parser.rs
deleted file mode 100644
index c7f64a1..0000000
--- a/crates/parser/parser/css_parser.rs
+++ /dev/null
@@ -1,847 +0,0 @@
-use crate::ns::*;
-use num_traits::ToPrimitive;
-
-pub struct CssParser<'input> {
- tokenizer: CssTokenizer<'input>,
- previous_token: (Token, Location),
- token: (Token, Location),
- locations: Vec,
- expecting_token_error: bool,
-}
-
-impl<'input> CssParser<'input> {
- /// Constructs a tokenizer.
- pub fn new(compilation_unit: &'input Rc, options: &ParserOptions) -> Self {
- Self {
- tokenizer: CssTokenizer::new(compilation_unit, options),
- previous_token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
- token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
- locations: vec![],
- expecting_token_error: false,
- }
- }
-
- fn options(&self) -> ParserOptions {
- ParserOptions {
- ..default()
- }
- }
-
- fn compilation_unit(&self) -> &Rc {
- self.tokenizer.compilation_unit()
- }
-
- fn token_location(&self) -> Location {
- self.token.1.clone()
- }
-
- fn mark_location(&mut self) {
- self.locations.push(self.token.1.clone());
- }
-
- fn duplicate_location(&mut self) {
- self.locations.push(self.locations.last().unwrap().clone());
- }
-
- fn push_location(&mut self, location: &Location) {
- self.locations.push(location.clone());
- }
-
- fn pop_location(&mut self) -> Location {
- self.locations.pop().unwrap().combine_with(self.previous_token.1.clone())
- }
-
- fn add_syntax_error(&self, location: &Location, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().prevent_equal_offset_error(location) {
- return;
- }
- self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments));
- }
-
- /*
- fn add_warning(&self, location: &Location, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().prevent_equal_offset_warning(location) {
- return;
- }
- self.compilation_unit().add_diagnostic(Diagnostic::new_warning(location, kind, arguments));
- }
- */
-
- fn next(&mut self) {
- self.previous_token = self.token.clone();
- self.token = self.tokenizer.scan();
- }
-
- fn peek(&self, token: Token) -> bool {
- self.token.0 == token
- }
-
- fn peek_identifier(&self) -> Option<(String, Location)> {
- if let Token::Identifier(id) = self.token.0.clone() {
- let location = self.token.1.clone();
- Some((id, location))
- } else {
- None
- }
- }
-
- fn peek_keyword(&self, name: &str) -> bool {
- if let Token::Identifier(id) = self.token.0.clone() { id == name && self.token.1.character_count() == name.len() } else { false }
- }
-
- fn consume(&mut self, token: Token) -> bool {
- if self.token.0 == token {
- self.next();
- true
- } else {
- false
- }
- }
-
- fn consume_identifier(&mut self) -> Option<(String, Location)> {
- if let Token::Identifier(id) = self.token.0.clone() {
- let location = self.token.1.clone();
- self.next();
- Some((id, location))
- } else {
- None
- }
- }
-
- fn consume_keyword(&mut self, name: &str) -> bool {
- if let Token::Identifier(name1) = self.token.0.clone() {
- if name1 == name {
- self.next();
- return true;
- }
- }
- false
- }
-
- /// Expects a token in non-greedy mode: if it fails, does not skip any token.
- fn expect(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- } else {
- self.expecting_token_error = false;
- self.next();
- }
- }
-
- fn expect_identifier(&mut self) -> (String, Location) {
- if let Token::Identifier(id) = self.token.0.clone() {
- self.expecting_token_error = false;
- let location = self.token.1.clone();
- self.next();
- (id, location)
- } else {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
- (INVALIDATED_IDENTIFIER.to_owned(), self.tokenizer.cursor_location())
- }
- }
-
- fn expect_unitless_number(&mut self) -> Option {
- if let Token::CssNumber { value, .. } = self.token.0.clone() {
- self.expecting_token_error = false;
- self.next();
- Some(value)
- } else {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- None
- }
- }
-
- fn expect_string(&mut self) -> (String, Location) {
- if let Token::String(v) = self.token.0.clone() {
- self.expecting_token_error = false;
- let location = self.token.1.clone();
- self.next();
- (v, location)
- } else {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingStringLiteral, diagarg![self.token.0.clone()]);
- ("".into(), self.tokenizer.cursor_location())
- }
- }
-
- pub fn expect_eof(&mut self) {
- self.expect(Token::Eof);
- }
-
- fn create_invalidated_directive(&self, location: &Location) -> Rc {
- Rc::new(CssDirective::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn create_invalidated_property_value(&self, location: &Location) -> Rc {
- Rc::new(CssPropertyValue::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn _create_invalidated_selector(&self, location: &Location) -> Rc {
- Rc::new(CssSelector::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn create_invalidated_selector_condition(&self, location: &Location) -> Rc {
- Rc::new(CssSelectorCondition::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn create_invalidated_media_query_condition(&self, location: &Location) -> Rc {
- Rc::new(CssMediaQueryCondition::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn eof(&self) -> bool {
- matches!(self.token.0, Token::Eof)
- }
-
- pub fn parse_document(&mut self) -> Rc {
- self.mark_location();
- let just_eof = self.peek(Token::Eof);
- let mut directives: Vec> = vec![];
- while !self.eof() {
- directives.push(self.parse_directive());
- }
- let loc = self.pop_location();
- Rc::new(CssDocument {
- location: if just_eof {
- self.token.1.clone()
- } else {
- loc
- },
- directives,
- })
- }
-
- fn parse_directive(&mut self) -> Rc {
- if let Some(rule) = self.parse_opt_rule() {
- Rc::new(CssDirective::Rule(rule))
- } else if self.peek(Token::CssAtNamespace) {
- self.mark_location();
- self.next();
- let prefix = self.expect_identifier();
- let uri = if self.expecting_token_error {
- (String::new(), self.tokenizer.cursor_location())
- } else {
- self.expect_string()
- };
- if !self.expecting_token_error {
- self.expect(Token::CssSemicolons);
- }
- let loc = self.pop_location();
- Rc::new(CssDirective::NamespaceDefinition(CssNamespaceDefinition {
- location: loc,
- prefix,
- uri,
- }))
- } else if self.peek(Token::CssAtMedia) {
- self.parse_media_query()
- } else if self.peek(Token::CssAtFontFace) {
- self.parse_font_face()
- } else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::ExpectingDirective, diagarg![self.token.0.clone()]);
- let d = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- self.next();
- d
- }
- }
-
- fn parse_media_query(&mut self) -> Rc {
- self.mark_location();
- self.next();
- let mut conditions: Vec> = vec![];
- let condition = self.parse_opt_media_query_condition();
- if let Some(condition) = condition {
- conditions.push(condition);
- } else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- }
- loop {
- if let Some(condition) = self.parse_opt_media_query_condition() {
- conditions.push(condition);
- } else if self.eof() || self.peek(Token::BlockOpen) {
- break;
- } else if !self.consume(Token::Comma) {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- self.next();
- }
- }
- let mut rules: Vec> = vec![];
- self.expect(Token::BlockOpen);
- if !self.expecting_token_error {
- while !(self.eof() || self.peek(Token::BlockClose)) {
- if let Some(rule) = self.parse_opt_rule() {
- rules.push(Rc::new(rule));
- } else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- self.next();
- }
- }
- self.expect(Token::BlockClose);
- }
- Rc::new(CssDirective::MediaQuery(CssMediaQuery {
- location: self.pop_location(),
- conditions,
- rules,
- }))
- }
-
- fn parse_font_face(&mut self) -> Rc {
- self.mark_location();
- self.next();
- let mut properties: Vec> = vec![];
- self.expect(Token::BlockOpen);
- if !self.expecting_token_error {
- self.consume(Token::CssSemicolons);
- while !(self.eof() || self.peek(Token::BlockClose)) {
- properties.push(self.parse_property());
- if !self.consume(Token::CssSemicolons) {
- break;
- }
- }
- self.expect(Token::BlockClose);
- }
- Rc::new(CssDirective::FontFace(CssFontFace {
- location: self.pop_location(),
- properties,
- }))
- }
-
- fn parse_opt_media_query_condition(&mut self) -> Option> {
- let mut base: Option> = None;
- if self.peek_keyword("only") {
- self.mark_location();
- self.next();
- let id = self.expect_identifier();
- base = Some(Rc::new(CssMediaQueryCondition::OnlyId {
- location: self.pop_location(),
- id,
- }));
- }
- if let Some(id) = self.consume_identifier() {
- base = Some(Rc::new(CssMediaQueryCondition::Id(id)));
- }
- if self.peek(Token::ParenOpen) {
- self.mark_location();
- let property = self.parse_arguments().unwrap().parse_property();
- let loc = self.pop_location();
- base = Some(Rc::new(CssMediaQueryCondition::ParenProperty((property, loc))));
- }
- if let Some(mut base) = base.clone() {
- while self.consume_keyword("and") {
- self.push_location(&base.location());
- if let Some(right) = self.parse_opt_media_query_condition() {
- base = Rc::new(CssMediaQueryCondition::And {
- location: self.pop_location(),
- left: base,
- right,
- });
- } else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- base = Rc::new(CssMediaQueryCondition::And {
- location: self.pop_location(),
- left: base,
- right: self.create_invalidated_media_query_condition(&self.tokenizer.cursor_location()),
- });
- }
- }
- return Some(base);
- }
- base
- }
-
- fn parse_arguments(&mut self) -> Result {
- if !self.peek(Token::ParenOpen) {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Expecting, diagarg![Token::ParenOpen, self.token.0.clone()]);
- return Err(ParserError::Common);
- }
- let (byte_range, token) = self.tokenizer.scan_arguments();
- self.previous_token = self.token.clone();
- self.token = token;
- self.next();
- Ok(CssParserFacade(self.compilation_unit(), ParserOptions {
- byte_range: Some(byte_range),
- ..self.options()
- }))
- }
-
- fn parse_opt_rule(&mut self) -> Option {
- let mut selectors: Vec> = vec![self.parse_opt_selector()?];
- while self.consume(Token::Comma) {
- if let Some(s) = self.parse_opt_selector() {
- selectors.push(s);
- } else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- }
- }
- let mut properties: Vec> = vec![];
- self.expect(Token::BlockOpen);
- if !self.expecting_token_error {
- self.consume(Token::CssSemicolons);
- while !(self.eof() || self.peek(Token::BlockClose)) {
- properties.push(self.parse_property());
- if !self.consume(Token::CssSemicolons) {
- break;
- }
- }
- self.expect(Token::BlockClose);
- }
- self.push_location(&selectors[0].location());
- Some(CssRule {
- location: self.pop_location(),
- selectors,
- properties,
- })
- }
-
- fn parse_opt_selector(&mut self) -> Option> {
- let mut base = self.parse_opt_base_selector()?;
-
- // Parse descendant combinators
- while let Some(right) = self.parse_opt_base_selector() {
- self.push_location(&base.location());
- base = Rc::new(CssSelector::Combinator(CssCombinatorSelector {
- location: self.pop_location(),
- left: base,
- right,
- combinator_type: CssCombinatorType::Descendant,
- }));
- }
-
- Some(base)
- }
-
- fn parse_opt_base_selector(&mut self) -> Option> {
- self.mark_location();
- let mut namespace_prefix: Option<(String, Location)> = None;
- let mut element_name: Option<(String, Location)> = self.consume_identifier();
- let mut conditions: Vec> = vec![];
- if self.consume(Token::Pipe) {
- namespace_prefix = element_name.clone();
- element_name = Some(self.expect_identifier());
- }
- // Parse conditions as long as they are not separated by whitespace
- while (element_name.is_none() && conditions.is_empty()) || (self.token.1.first_offset() - self.previous_token.1.last_offset() == 0) {
- if let Some(condition) = self.parse_opt_selector_condition() {
- conditions.push(condition);
- } else {
- break;
- }
- }
- if element_name.is_none() && conditions.is_empty() {
- self.pop_location();
- return None;
- }
- Some(Rc::new(CssSelector::Base(CssBaseSelector {
- location: self.pop_location(),
- namespace_prefix,
- element_name,
- conditions,
- })))
- }
-
- fn parse_selector_condition(&mut self) -> Rc {
- let Some(c) = self.parse_opt_selector_condition() else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- return self.create_invalidated_selector_condition(&self.tokenizer.cursor_location());
- };
- c
- }
-
- fn parse_opt_selector_condition(&mut self) -> Option> {
- if self.peek(Token::Dot) {
- self.mark_location();
- self.next();
- let class_name = self.expect_identifier().0;
- return Some(Rc::new(CssSelectorCondition::Class((class_name, self.pop_location()))));
- }
- if let Token::CssHashWord(id_value) = self.token.0.clone() {
- let loc = self.token.1.clone();
- self.next();
- return Some(Rc::new(CssSelectorCondition::Id((id_value, loc))));
- }
- if self.peek(Token::Colon) {
- self.mark_location();
- self.next();
- if self.consume_keyword("not") {
- let condition = if let Ok(a) = self.parse_arguments() {
- a.parse_selector_condition()
- } else {
- self.duplicate_location();
- let loc = self.pop_location();
- self.create_invalidated_selector_condition(&loc)
- };
- return Some(Rc::new(CssSelectorCondition::Not {
- location: self.pop_location(),
- condition,
- }));
- } else {
- let name = self.expect_identifier().0;
- return Some(Rc::new(CssSelectorCondition::Pseudo((name, self.pop_location()))));
- }
- }
- if self.peek(Token::ColonColon) {
- self.mark_location();
- self.next();
- let name = self.expect_identifier().0;
- return Some(Rc::new(CssSelectorCondition::PseudoElement((name, self.pop_location()))));
- }
- if self.peek(Token::SquareOpen) {
- self.mark_location();
- self.next();
- let name = self.expect_identifier();
- let mut operator: Option = None;
- let mut value: Option<(String, Location)> = None;
- while let Some(t1) = self.consume_attribute_operator() {
- operator = Some(t1);
- }
- while let Token::String(s1) = self.token.0.clone() {
- value = Some((s1, self.token.1.clone()));
- self.next();
- }
- self.expect(Token::SquareClose);
- return Some(Rc::new(CssSelectorCondition::Attribute {
- location: self.pop_location(),
- name,
- operator,
- value,
- }));
- }
- None
- }
-
- fn consume_attribute_operator(&mut self) -> Option {
- if self.consume(Token::CssBeginsWith) {
- Some(CssAttributeOperator::BeginsWith)
- } else if self.consume(Token::CssEndsWith) {
- Some(CssAttributeOperator::EndsWith)
- } else if self.consume(Token::CssContains) {
- Some(CssAttributeOperator::Contains)
- } else if self.consume(Token::CssListMatch) {
- Some(CssAttributeOperator::ListMatch)
- } else if self.consume(Token::CssHreflangMatch) {
- Some(CssAttributeOperator::HreflangMatch)
- } else if self.consume(Token::Assign) {
- Some(CssAttributeOperator::Equals)
- } else {
- None
- }
- }
-
- fn parse_property(&mut self) -> Rc {
- self.mark_location();
- let name = self.expect_identifier();
- let mut value = self.create_invalidated_property_value(&self.tokenizer.cursor_location());
- if !self.expecting_token_error {
- self.expect(Token::Colon);
- if !self.expecting_token_error {
- value = self.parse_property_value(CssOperatorPrecedence::Array);
- }
- }
- Rc::new(CssProperty::new(self.pop_location(), name, value))
- }
-
- fn parse_property_value(&mut self, min_precedence: CssOperatorPrecedence) -> Rc {
- let Some(v) = self.parse_opt_property_value(min_precedence) else {
- self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- return self.create_invalidated_property_value(&self.tokenizer.cursor_location());
- };
- v
- }
-
- fn parse_opt_property_value(&mut self, min_precedence: CssOperatorPrecedence) -> Option> {
- let base: Option>;
- let t1 = self.token.0.clone();
-
- // #HHH
- // #HHHHHH
- if let Token::CssHashWord(word) = t1 {
- self.mark_location();
- self.next();
- let loc = self.pop_location();
- if let Ok(v) = CssColorPropertyValue::from_hex(loc.clone(), &word) {
- base = Some(Rc::new(CssPropertyValue::Color(v)));
- } else {
- base = Some(self.create_invalidated_property_value(&loc));
- }
- // "..."
- // '...'
- } else if let Token::String(value) = t1 {
- self.mark_location();
- self.next();
- base = Some(Rc::new(CssPropertyValue::String(CssStringPropertyValue {
- location: self.pop_location(),
- value
- })));
- // DECIMAL
- } else if let Token::CssNumber { value, unit } = t1 {
- self.mark_location();
- self.next();
- let loc = self.pop_location();
- base = Some(Rc::new(CssPropertyValue::Number(CssNumberPropertyValue {
- location: loc,
- value,
- unit,
- })));
- } else if let Some(id) = self.peek_identifier() {
- self.mark_location();
- self.next();
- let color_int = css_color_constant_to_int(&id.0);
- // COLOR_NAME such as "red"
- if let Some(color_int) = color_int {
- base = Some(Rc::new(CssPropertyValue::Color(CssColorPropertyValue {
- location: self.pop_location(),
- color_int,
- })));
- // rgb(...)
- } else if id.0 == "rgb" && self.peek(Token::ParenOpen) {
- if let Some(color_int) = self.parse_arguments().unwrap().parse_rgb() {
- base = Some(Rc::new(CssPropertyValue::RgbColor(CssRgbColorPropertyValue {
- location: self.pop_location(),
- color_int,
- })));
- } else {
- let loc = self.pop_location();
- base = Some(self.create_invalidated_property_value(&loc));
- }
- } else if id.0 == "ClassReference" && self.peek(Token::ParenOpen) {
- let name = self.parse_arguments().unwrap().parse_text();
- base = Some(Rc::new(CssPropertyValue::ClassReference(CssClassReferencePropertyValue {
- location: self.pop_location(),
- name,
- })));
- } else if id.0 == "PropertyReference" && self.peek(Token::ParenOpen) {
- let name = self.parse_arguments().unwrap().parse_text();
- base = Some(Rc::new(CssPropertyValue::PropertyReference(CssPropertyReferencePropertyValue {
- location: self.pop_location(),
- name,
- })));
- } else if id.0 == "url" && self.peek(Token::ParenOpen) {
- let url = self.parse_arguments().unwrap().parse_text();
- let mut format: Option<(String, Location)> = None;
- if self.consume_keyword("format") {
- if let Ok(a) = self.parse_arguments() {
- format = Some(a.parse_text());
- }
- }
- base = Some(Rc::new(CssPropertyValue::Url(CssUrlPropertyValue {
- location: self.pop_location(),
- url,
- format,
- })));
- } else if id.0 == "local" && self.peek(Token::ParenOpen) {
- let name = self.parse_arguments().unwrap().parse_text();
- base = Some(Rc::new(CssPropertyValue::Local(CssLocalPropertyValue {
- location: self.pop_location(),
- name,
- })));
- } else if id.0 == "Embed" && self.peek(Token::ParenOpen) {
- let entries = self.parse_arguments().unwrap().parse_embed_entries();
- base = Some(Rc::new(CssPropertyValue::Embed(CssEmbedPropertyValue {
- location: self.pop_location(),
- entries,
- })));
- } else {
- if self.peek(Token::ParenOpen) {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
- self.parse_arguments().unwrap();
- }
- base = Some(Rc::new(CssPropertyValue::Identifier(CssIdentifierPropertyValue {
- location: self.pop_location(),
- value: id.0,
- })));
- }
- } else if self.peek(Token::Plus) || self.peek(Token::Minus)
- || self.peek(Token::Times) || self.peek(Token::Div) {
- base = Some(self.create_invalidated_property_value(&self.token.1));
- self.next();
- } else {
- return None;
- }
-
- let mut base = base.unwrap();
-
- loop {
- if self.peek(Token::Comma) && min_precedence.includes(&CssOperatorPrecedence::Array) {
- self.push_location(&base.location());
- let mut elements: Vec> = vec![base];
- while self.consume(Token::Comma) {
- elements.push(self.parse_property_value(CssOperatorPrecedence::MultiValue));
- }
- base = Rc::new(CssPropertyValue::Array(CssArrayPropertyValue {
- location: self.pop_location(),
- elements,
- }));
- } else if min_precedence.includes(&CssOperatorPrecedence::MultiValue) {
- if let Some(mv1) = self.parse_opt_property_value(CssOperatorPrecedence::MultiValue.add(1).unwrap()) {
- self.push_location(&base.location());
- let mut values: Vec> = vec![base, mv1];
- while let Some(mv1) = self.parse_opt_property_value(CssOperatorPrecedence::MultiValue.add(1).unwrap()) {
- values.push(mv1);
- }
- base = Rc::new(CssPropertyValue::MultiValue(CssMultiValuePropertyValue {
- location: self.pop_location(),
- values,
- }));
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- Some(base)
- }
-
- fn parse_embed_entry(&mut self) -> Rc {
- self.mark_location();
- if let Some(key) = self.consume_identifier() {
- if self.consume(Token::Assign) {
- let value = self.expect_string();
- Rc::new(CssEmbedEntry {
- location: self.pop_location(),
- key: Some(key),
- value,
- })
- } else {
- Rc::new(CssEmbedEntry {
- location: self.pop_location(),
- key: None,
- value: key,
- })
- }
- } else {
- let value = self.expect_string();
- Rc::new(CssEmbedEntry {
- location: self.pop_location(),
- key: None,
- value,
- })
- }
- }
-}
-
-fn rgb_bytes_to_integer(r: f64, g: f64, b: f64) -> u32 {
- (calc_rgb_byte(r) << 16) | (calc_rgb_byte(g) << 8) | calc_rgb_byte(b)
-}
-
-fn calc_rgb_byte(value: f64) -> u32 {
- // Integer
- if value.round() == value {
- value.round().to_u32().unwrap_or(0).clamp(0, 255)
- // Float
- } else {
- (value * 255.0).round().to_u32().unwrap_or(0).clamp(0, 255)
- }
-}
-
-/// A simplified interface for executing the CSS parser.
-pub struct CssParserFacade<'input>(pub &'input Rc, pub ParserOptions);
-
-impl<'input> CssParserFacade<'input> {
- fn create_parser(&self) -> CssParser<'input> {
- CssParser::new(self.0, &self.1)
- }
-
- /// Parses `CssDocument` until end-of-file.
- pub fn parse_document(&self) -> Rc {
- let mut parser = self.create_parser();
- parser.next();
- parser.parse_document()
- }
-
- /// Parses either a string or return source text as is.
- pub fn parse_text(&self) -> (String, Location) {
- let mut parser = self.create_parser();
- while parser.tokenizer.consume_whitespace() {
- // Consumed whitespace
- }
- let d = parser.tokenizer.characters().peek_or_zero();
- if ['"', '\''].contains(&d) {
- parser.next();
- let mut v: (String, Location) = ("".into(), parser.tokenizer.cursor_location());
- while let Token::String(v1) = parser.token.0.clone() {
- v = (v1, parser.token.1.clone());
- parser.next();
- }
- parser.expect_eof();
- v
- } else {
- let mut s = String::new();
- let i = parser.tokenizer.characters().index();
- while let Some(ch) = parser.tokenizer.characters_mut().next() {
- s.push(ch);
- }
- let j = parser.tokenizer.characters().index();
- (s, Location::with_offsets(parser.compilation_unit(), i, j))
- }
- }
-
- /// Parses `CssSelectorCondition` until end-of-file.
- pub fn parse_selector_condition(&self) -> Rc {
- let mut parser = self.create_parser();
- parser.next();
- let r = parser.parse_selector_condition();
- parser.expect_eof();
- r
- }
-
- pub fn parse_property(&self) -> Rc {
- let mut parser = self.create_parser();
- parser.next();
- let r = parser.parse_property();
- parser.expect_eof();
- r
- }
-
- pub fn parse_property_value(&self) -> Rc {
- let mut parser = self.create_parser();
- parser.next();
- let r = parser.parse_property_value(CssOperatorPrecedence::Array);
- parser.expect_eof();
- r
- }
-
- pub fn parse_rgb(&self) -> Option {
- let mut parser = self.create_parser();
- parser.next();
- let r = parser.expect_unitless_number()?;
- let g: f64;
- let b: f64;
- if parser.consume(Token::Comma) {
- g = parser.expect_unitless_number()?;
- parser.expect(Token::Comma);
- b = parser.expect_unitless_number()?;
- } else {
- g = parser.expect_unitless_number()?;
- b = parser.expect_unitless_number()?;
- }
- parser.expect_eof();
- Some(rgb_bytes_to_integer(r, g, b))
- }
-
- pub fn parse_embed_entries(&self) -> Vec> {
- let mut parser = self.create_parser();
- let mut entries: Vec> = vec![];
- parser.next();
- if !parser.eof() {
- entries.push(parser.parse_embed_entry());
- }
- while parser.consume(Token::Comma) {
- entries.push(parser.parse_embed_entry());
- }
- parser.expect_eof();
- entries
- }
-}
diff --git a/crates/parser/parser/css_tokenizer.rs b/crates/parser/parser/css_tokenizer.rs
deleted file mode 100644
index 8c12cae..0000000
--- a/crates/parser/parser/css_tokenizer.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-use crate::ns::*;
-use std::str::FromStr;
-
-pub struct CssTokenizer<'input> {
- compilation_unit: Rc,
- characters: CharacterReader<'input>,
-}
-
-impl<'input> CssTokenizer<'input> {
- /// Constructs a tokenizer.
- pub fn new(compilation_unit: &'input Rc, options: &ParserOptions) -> Self {
- let text: &'input str = compilation_unit.text();
- let compilation_unit = compilation_unit.clone();
- let characters: CharacterReader<'input>;
- if let Some(range) = options.byte_range {
- characters = CharacterReader::from_offset(&text[0..range.1], range.0);
- } else {
- characters = CharacterReader::from(text);
- }
- Self {
- compilation_unit,
- characters,
- }
- }
-
- pub fn compilation_unit(&self) -> &Rc {
- &self.compilation_unit
- }
-
- pub fn characters(&self) -> &CharacterReader<'input> {
- &self.characters
- }
-
- pub fn characters_mut(&mut self) -> &mut CharacterReader<'input> {
- &mut self.characters
- }
-
- fn character_ahead_location(&self) -> Location {
- if self.characters.reached_end() {
- return self.cursor_location();
- }
- let offset = self.characters.index();
- let mut next_characters = self.characters.clone();
- next_characters.next().unwrap();
- Location::with_offsets(&self.compilation_unit, offset, next_characters.index())
- }
-
- pub fn cursor_location(&self) -> Location {
- let offset = self.characters.index();
- Location::with_offset(&self.compilation_unit, offset)
- }
-
- fn add_syntax_error(&self, location: &Location, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().prevent_equal_offset_error(location) {
- return;
- }
- self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments));
- }
-
- fn add_unexpected_error(&self) {
- if self.characters.has_remaining() {
- self.add_syntax_error(&self.character_ahead_location(), DiagnosticKind::UnexpectedCharacter, diagarg![self.characters.peek_or_zero().to_string()])
- } else {
- self.add_syntax_error(&self.cursor_location(), DiagnosticKind::UnexpectedEnd, vec![])
- }
- }
-
- fn add_unexpected_eof_error(&self, kind: DiagnosticKind) {
- self.add_syntax_error(&self.cursor_location(), kind, vec![]);
- }
-
- pub fn scan(&mut self) -> (Token, Location) {
- while self.consume_whitespace() || self.consume_comment() {
- // Do nothing
- }
- let start = self.cursor_location();
- let ch = self.characters.peek_or_zero();
-
- if let Some(id) = self.consume_css_id() {
- return (Token::Identifier(id), start.combine_with(self.cursor_location()));
- }
-
- // DECIMAL
- // DECIMAL.PART
- if CharacterValidator::is_dec_digit(ch) {
- self.characters.next();
- while CharacterValidator::is_dec_digit(self.characters.peek_or_zero()) {
- self.characters.next();
- }
- if self.characters.peek_or_zero() == '.' {
- self.characters.next();
- if !CharacterValidator::is_dec_digit(self.characters.peek_or_zero()) {
- self.add_unexpected_error();
- }
- while CharacterValidator::is_dec_digit(self.characters.peek_or_zero()) {
- self.characters.next();
- }
- }
- return self.finish_number(start);
- }
-
- if ch == '#' {
- self.characters.next();
- let mut word = String::new();
- loop {
- let ch = self.characters.peek_or_zero();
- if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') || ch == '-' || ch == '_' {
- word.push(ch);
- self.characters.next();
- } else {
- break;
- }
- }
- if word.is_empty() {
- self.add_unexpected_error();
- word = INVALIDATED_IDENTIFIER.to_owned();
- }
- return (Token::CssHashWord(word), start.combine_with(self.cursor_location()));
- }
-
- if ch == '@' {
- // @namespace
- if self.characters.peek_seq(10) == "@namespace" {
- self.characters.skip_count_in_place(10);
- return (Token::CssAtNamespace, start.combine_with(self.cursor_location()));
- }
- // @font-face
- if self.characters.peek_seq(10) == "@font-face" {
- self.characters.skip_count_in_place(10);
- return (Token::CssAtFontFace, start.combine_with(self.cursor_location()));
- }
- // @media
- if self.characters.peek_seq(6) == "@media" {
- self.characters.skip_count_in_place(6);
- return (Token::CssAtMedia, start.combine_with(self.cursor_location()));
- }
- }
-
- if ch == '!' && self.characters.peek_seq(10) == "!important" {
- self.characters.skip_count_in_place(10);
- return (Token::CssImportant, start.combine_with(self.cursor_location()));
- }
-
- match ch {
- // .
- // .DECIMAL
- '.' => {
- self.characters.next();
- if CharacterValidator::is_dec_digit(self.characters.peek_or_zero()) {
- while CharacterValidator::is_dec_digit(self.characters.peek_or_zero()) {
- self.characters.next();
- }
- return self.finish_number(start);
- }
- (Token::Dot, start.combine_with(self.cursor_location()))
- },
- '"' | '\'' => {
- self.scan_string(ch, start)
- },
- ';' => {
- while self.characters.peek_or_zero() == ';' {
- self.characters.next();
- }
- (Token::CssSemicolons, start.combine_with(self.cursor_location()))
- },
- '^' => {
- self.characters.next();
- if self.characters.peek_or_zero() != '=' {
- self.add_unexpected_error();
- self.characters.next();
- self.scan()
- } else {
- self.characters.next();
- (Token::CssBeginsWith, start.combine_with(self.cursor_location()))
- }
- },
- '$' => {
- self.characters.next();
- if self.characters.peek_or_zero() != '=' {
- self.add_unexpected_error();
- self.characters.next();
- self.scan()
- } else {
- self.characters.next();
- (Token::CssEndsWith, start.combine_with(self.cursor_location()))
- }
- },
- '*' => {
- self.characters.next();
- if self.characters.peek_or_zero() == '=' {
- self.characters.next();
- (Token::CssContains, start.combine_with(self.cursor_location()))
- } else {
- (Token::Times, start.combine_with(self.cursor_location()))
- }
- },
- '~' => {
- self.characters.next();
- if self.characters.peek_or_zero() == '=' {
- self.characters.next();
- (Token::CssListMatch, start.combine_with(self.cursor_location()))
- } else {
- (Token::Tilde, start.combine_with(self.cursor_location()))
- }
- },
- '|' => {
- self.characters.next();
- if self.characters.peek_or_zero() == '=' {
- self.characters.next();
- (Token::CssHreflangMatch, start.combine_with(self.cursor_location()))
- } else {
- (Token::Pipe, start.combine_with(self.cursor_location()))
- }
- },
- '{' => {
- self.characters.next();
- (Token::BlockOpen, start.combine_with(self.cursor_location()))
- },
- '}' => {
- self.characters.next();
- (Token::BlockClose, start.combine_with(self.cursor_location()))
- },
- '[' => {
- self.characters.next();
- (Token::SquareOpen, start.combine_with(self.cursor_location()))
- },
- ']' => {
- self.characters.next();
- (Token::SquareClose, start.combine_with(self.cursor_location()))
- },
- '(' => {
- self.characters.next();
- (Token::ParenOpen, start.combine_with(self.cursor_location()))
- },
- ')' => {
- self.characters.next();
- (Token::ParenClose, start.combine_with(self.cursor_location()))
- },
- ',' => {
- self.characters.next();
- (Token::Comma, start.combine_with(self.cursor_location()))
- },
- '%' => {
- self.characters.next();
- (Token::Percent, start.combine_with(self.cursor_location()))
- },
- '=' => {
- self.characters.next();
- (Token::Assign, start.combine_with(self.cursor_location()))
- },
- ':' => {
- self.characters.next();
- if self.characters.peek_or_zero() == ':' {
- self.characters.next();
- (Token::ColonColon, start.combine_with(self.cursor_location()))
- } else {
- (Token::Colon, start.combine_with(self.cursor_location()))
- }
- },
- '>' => {
- self.characters.next();
- (Token::Gt, start.combine_with(self.cursor_location()))
- },
- '+' => {
- self.characters.next();
- (Token::Plus, start.combine_with(self.cursor_location()))
- },
- _ => {
- if self.characters.reached_end() {
- return (Token::Eof, start);
- }
- self.add_unexpected_error();
- self.characters.next();
- self.scan()
- },
- }
- }
-
- pub fn consume_whitespace(&mut self) -> bool {
- let ch = self.characters.peek_or_zero();
- if [' ', '\t', '\n', '\r'].contains(&ch) {
- self.characters.next();
- true
- } else {
- false
- }
- }
-
- fn consume_comment(&mut self) -> bool {
- if self.characters.peek_or_zero() == '/' && self.characters.peek_at_or_zero(1) == '*' {
- let start = self.cursor_location();
- self.characters.skip_count_in_place(2);
- loop {
- if self.characters.peek_or_zero() == '*' && self.characters.peek_at_or_zero(1) == '/' {
- self.characters.skip_count_in_place(2);
- break;
- } else if self.characters.has_remaining() {
- self.characters.skip_in_place();
- } else {
- self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSeqForMultiLineComment);
- break;
- }
- }
-
- let location = start.combine_with(self.cursor_location());
- let i = location.first_offset() + 2;
- let j = decrease_last_offset(i, location.last_offset(), 2);
-
- self.compilation_unit.add_comment(Rc::new(Comment {
- multiline: true,
- content: RefCell::new(self.compilation_unit.text()[i..j].to_owned()),
- location: RefCell::new(location),
- }));
-
- true
- } else {
- false
- }
- }
-
- fn consume_css_id(&mut self) -> Option {
- let i = self.characters.index();
- let mut prefix_n = 0;
- if self.characters.peek_or_zero() == '_' {
- prefix_n += 1;
- if self.characters.peek_at_or_zero(prefix_n) == '_' {
- prefix_n += 1;
- if self.characters.peek_at_or_zero(prefix_n) == '_' {
- prefix_n += 1;
- }
- }
- } else if self.characters.peek_or_zero() == '-' {
- prefix_n += 1;
- }
- if CharacterValidator::is_css_identifier_start(self.characters.peek_at_or_zero(prefix_n)) {
- self.characters.skip_count_in_place(prefix_n + 1);
- while CharacterValidator::is_css_identifier_part(self.characters.peek_or_zero()) {
- self.characters.next();
- }
- return Some(self.compilation_unit.text()[i..self.characters.index()].to_owned());
- }
- None
- }
-
- fn finish_number(&mut self, start: Location) -> (Token, Location) {
- let digits = &self.compilation_unit.text()[start.first_offset..self.characters.index()];
- let mut mv = f64::from_str(digits).unwrap_or(f64::NAN);
- let mut unit: Option = None;
- if self.characters.peek_or_zero() == '%' {
- self.characters.next();
- mv /= 100.0;
- } else {
- unit = self.consume_css_id();
- }
- (Token::CssNumber {
- value: mv,
- unit,
- }, start.combine_with(self.cursor_location()))
- }
-
- fn scan_string(&mut self, delim: char, start: Location) -> (Token, Location) {
- let mut builder = String::new();
- self.characters.next();
- loop {
- let ch = self.characters.peek_or_zero();
- if ch == delim {
- self.characters.next();
- break;
- } else if ch == '\\' {
- let mut loc = self.cursor_location();
- self.characters.next();
- let mut digits = String::new();
- for _ in 0..6 {
- let ch = self.characters.peek_or_zero();
- if CharacterValidator::is_hex_digit(ch) {
- digits.push(ch);
- self.characters.next();
- } else {
- break;
- }
- }
- if digits.is_empty() {
- self.add_unexpected_error();
- } else {
- loc = loc.combine_with(self.cursor_location());
- let mv = u32::from_str_radix(&digits, 16).ok().and_then(|mv| char::from_u32(mv));
- if let Some(mv) = mv {
- builder.push(mv);
- } else {
- self.add_syntax_error(&loc, DiagnosticKind::CssInvalidHexEscape, diagarg![digits]);
- }
- }
- } else if self.characters.reached_end() {
- self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString);
- break;
- } else {
- builder.push(ch);
- self.characters.next();
- }
- }
- let loc = start.combine_with(self.cursor_location());
- (Token::String(builder), loc)
- }
-
- pub fn scan_arguments(&mut self) -> ((usize, usize), (Token, Location)) {
- let i = self.characters.index();
- let mut j: usize;
- let mut nesting = 1;
- let token: (Token, Location);
- loop {
- j = self.characters.index();
- let ch = self.characters.peek_or_zero();
- if ch == ')' {
- self.characters.next();
- nesting -= 1;
- if nesting == 0 {
- token = (Token::ParenClose, Location::with_offsets(&self.compilation_unit, j, self.characters.index()));
- break;
- }
- } else if ch == '(' {
- self.characters.next();
- nesting += 1;
- } else if self.characters.reached_end() {
- self.add_syntax_error(&self.cursor_location(), DiagnosticKind::Expecting, diagarg![Token::ParenClose, Token::Eof]);
- token = (Token::Eof, self.cursor_location());
- break;
- } else {
- self.characters.next();
- }
- }
- ((i, j), token)
- }
-}
\ No newline at end of file
diff --git a/crates/parser/parser/parser.rs b/crates/parser/parser/parser.rs
deleted file mode 100644
index d424750..0000000
--- a/crates/parser/parser/parser.rs
+++ /dev/null
@@ -1,5376 +0,0 @@
-use crate::ns::*;
-use lazy_regex::*;
-
-pub struct Parser<'input> {
- tokenizer: Tokenizer<'input>,
- previous_token: (Token, Location),
- token: (Token, Location),
- locations: Vec,
- activations: Vec,
- ignore_xml_whitespace: bool,
- expecting_token_error: bool,
-}
-
-impl<'input> Parser<'input> {
- /// Constructs a parser.
- pub fn new(compilation_unit: &'input Rc, options: &ParserOptions) -> Self {
- Self {
- tokenizer: Tokenizer::new(compilation_unit, options),
- previous_token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
- token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
- locations: vec![],
- activations: vec![],
- ignore_xml_whitespace: options.ignore_xml_whitespace,
- expecting_token_error: false,
- }
- }
-
- fn options(&self) -> ParserOptions {
- ParserOptions {
- ignore_xml_whitespace: self.ignore_xml_whitespace,
- ..default()
- }
- }
-
- fn compilation_unit(&self) -> &Rc {
- self.tokenizer.compilation_unit()
- }
-
- fn token_location(&self) -> Location {
- self.token.1.clone()
- }
-
- fn mark_location(&mut self) {
- self.locations.push(self.token.1.clone());
- }
-
- fn duplicate_location(&mut self) {
- self.locations.push(self.locations.last().unwrap().clone());
- }
-
- fn push_location(&mut self, location: &Location) {
- self.locations.push(location.clone());
- }
-
- fn pop_location(&mut self) -> Location {
- self.locations.pop().unwrap().combine_with(self.previous_token.1.clone())
- }
-
- fn add_syntax_error(&self, location: &Location, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().prevent_equal_offset_error(location) {
- return;
- }
- self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments));
- }
-
- fn patch_syntax_error(&self, original: DiagnosticKind, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().diagnostics.borrow().is_empty() {
- return;
- }
- if self.compilation_unit().diagnostics.borrow().last().unwrap().kind == original {
- let loc = self.compilation_unit().diagnostics.borrow_mut().pop().unwrap().location();
- self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(&loc, kind, arguments));
- }
- }
-
- /*
- fn add_warning(&self, location: &Location, kind: DiagnosticKind, arguments: Vec>) {
- if self.compilation_unit().prevent_equal_offset_warning(location) {
- return;
- }
- self.compilation_unit().add_diagnostic(Diagnostic::new_warning(location, kind, arguments));
- }
- */
-
- fn next(&mut self) {
- self.previous_token = self.token.clone();
- self.token = self.tokenizer.scan_ie_div();
- }
-
- fn next_ie_xml_tag(&mut self) {
- self.previous_token = self.token.clone();
- self.token = self.tokenizer.scan_ie_xml_tag();
- }
-
- fn next_ie_xml_content(&mut self) {
- self.previous_token = self.token.clone();
- self.token = self.tokenizer.scan_ie_xml_content();
- }
-
- fn peek(&self, token: Token) -> bool {
- self.token.0 == token
- }
-
- fn peek_identifier(&self, reserved_words: bool) -> Option<(String, Location)> {
- if let Token::Identifier(id) = self.token.0.clone() {
- let location = self.token.1.clone();
- Some((id, location))
- } else {
- if reserved_words {
- if let Some(id) = self.token.0.reserved_word_name() {
- let location = self.token.1.clone();
- return Some((id, location));
- }
- }
- None
- }
- }
-
- fn peek_context_keyword(&self, name: &str) -> bool {
- if let Token::Identifier(id) = self.token.0.clone() { id == name && self.token.1.character_count() == name.len() } else { false }
- }
-
- fn consume(&mut self, token: Token) -> bool {
- if self.token.0 == token {
- self.next();
- true
- } else {
- false
- }
- }
-
- fn consume_and_ie_xml_tag(&mut self, token: Token) -> bool {
- if self.token.0 == token {
- self.next_ie_xml_tag();
- true
- } else {
- false
- }
- }
-
- fn consume_and_ie_xml_content(&mut self, token: Token) -> bool {
- if self.token.0 == token {
- self.next_ie_xml_content();
- true
- } else {
- false
- }
- }
-
- fn consume_identifier(&mut self, reserved_words: bool) -> Option<(String, Location)> {
- if let Token::Identifier(id) = self.token.0.clone() {
- let location = self.token.1.clone();
- self.next();
- Some((id, location))
- } else {
- if reserved_words {
- if let Some(id) = self.token.0.reserved_word_name() {
- let location = self.token.1.clone();
- self.next();
- return Some((id, location));
- }
- }
- None
- }
- }
-
- fn _consume_context_keyword(&mut self, name: &str) -> bool {
- if let Token::Identifier(id) = self.token.0.clone() {
- if id == name && self.token.1.character_count() == name.len() {
- self.next();
- true
- } else {
- false
- }
- } else {
- false
- }
- }
-
- fn expect(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- let expecting_identifier_name = token.is_identifier_name();
- while self.token.0 != Token::Eof && (if expecting_identifier_name { self.token.0.is_identifier_name() } else { true }) {
- self.next();
- if self.token.0 == token {
- return;
- }
- }
- } else {
- self.expecting_token_error = false;
- self.next();
- }
- }
-
- /// Expects a token; but if it fails, does not skip any token.
- fn non_greedy_expect(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- } else {
- self.expecting_token_error = false;
- self.next();
- }
- }
-
- fn non_greedy_expect_virtual_semicolon(&mut self) {
- self.expecting_token_error = false;
- if !self.parse_semicolon() {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingEitherSemicolonOrNewLineHere, vec![]);
- }
- }
-
- fn expect_and_ie_xml_tag(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- while self.token.0 != Token::Eof {
- self.next_ie_xml_tag();
- if self.token.0 == token {
- return;
- }
- }
- } else {
- self.expecting_token_error = false;
- self.next_ie_xml_tag();
- }
- }
-
- /// Expects a token; but if it fails, does not skip any token.
- fn non_greedy_expect_and_ie_xml_tag(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- } else {
- self.expecting_token_error = false;
- self.next_ie_xml_tag();
- }
- }
-
- fn expect_and_ie_xml_content(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- while self.token.0 != Token::Eof {
- self.next_ie_xml_content();
- if self.token.0 == token {
- return;
- }
- }
- } else {
- self.expecting_token_error = false;
- self.next_ie_xml_content();
- }
- }
-
- fn non_greedy_expect_and_ie_xml_content(&mut self, token: Token) {
- if self.token.0 != token {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
- } else {
- self.expecting_token_error = false;
- self.next_ie_xml_content();
- }
- }
-
- fn expect_identifier(&mut self, reserved_words: bool) -> (String, Location) {
- if let Token::Identifier(id) = self.token.0.clone() {
- self.expecting_token_error = false;
- let location = self.token.1.clone();
- self.next();
- (id, location)
- } else {
- if reserved_words {
- if let Some(id) = self.token.0.reserved_word_name() {
- self.expecting_token_error = false;
- let location = self.token.1.clone();
- self.next();
- return (id, location);
- }
- }
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
- /*
- while self.token.0 != Token::Eof && self.token.0.is_identifier_name() {
- if let Some(id) = self.consume_identifier(reserved_words) {
- return id;
- } else {
- self.next();
- }
- }
- */
- (INVALIDATED_IDENTIFIER.to_owned(), self.tokenizer.cursor_location())
- }
- }
-
- fn _expect_context_keyword(&mut self, name: &str) {
- if let Token::Identifier(id) = self.token.0.clone() {
- if id == name && self.token.1.character_count() == name.len() {
- self.expecting_token_error = false;
- self.next();
- return;
- }
- }
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![format!("'{name}'"), self.token.0.clone()]);
- while self.token.0 != Token::Eof && self.token.0.is_identifier_name() {
- if self._consume_context_keyword(name) {
- return;
- } else {
- self.next();
- }
- }
- }
-
- fn non_greedy_expect_context_keyword(&mut self, name: &str) {
- if let Token::Identifier(id) = self.token.0.clone() {
- if id == name && self.token.1.character_count() == name.len() {
- self.expecting_token_error = false;
- self.next();
- return;
- }
- }
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![format!("'{name}'"), self.token.0.clone()]);
- }
-
- /// Expects a greater-than symbol. If the facing token is not greater-than,
- /// but starts with a greater-than symbol, the first character is shifted off
- /// from the facing token.
- fn _expect_type_parameters_gt(&mut self) {
- self.expecting_token_error = false;
- if !self.consume_type_parameters_gt() {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![Token::Gt, self.token.0.clone()]);
- while self.token.0 != Token::Eof {
- self.next();
- if self.consume_type_parameters_gt() {
- return;
- }
- }
- }
- }
-
- fn non_greedy_expect_type_parameters_gt(&mut self) {
- self.expecting_token_error = false;
- if !self.consume_type_parameters_gt() {
- self.expecting_token_error = true;
- self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![Token::Gt, self.token.0.clone()]);
- }
- }
-
- /// Consumes a greater-than symbol. If the facing token is not greater-than,
- /// but starts with a greater-than symbol, the first character is shifted off
- /// from the facing token.
- fn consume_type_parameters_gt(&mut self) -> bool {
- match self.token.0 {
- Token::Gt => {
- self.next();
- true
- },
- Token::Ge => {
- self.token.0 = Token::Assign;
- self.token.1.first_offset += 1;
- true
- },
- Token::RightShift => {
- self.token.0 = Token::Gt;
- self.token.1.first_offset += 1;
- true
- },
- Token::RightShiftAssign => {
- self.token.0 = Token::Ge;
- self.token.1.first_offset += 1;
- true
- },
- Token::UnsignedRightShift => {
- self.token.0 = Token::RightShift;
- self.token.1.first_offset += 1;
- true
- },
- Token::UnsignedRightShiftAssign => {
- self.token.0 = Token::RightShiftAssign;
- self.token.1.first_offset += 1;
- true
- },
- _ => {
- false
- },
- }
- }
-
- fn offending_token_is_inline_or_higher_indented(&self) -> bool {
- if !self.previous_token.1.line_break(&self.token.1) {
- return true;
- }
- let i1 = self.compilation_unit().get_line_indent(self.previous_token.1.first_line_number());
- let i2 = self.compilation_unit().get_line_indent(self.token.1.first_line_number());
- i2 > i1
- }
-
- pub fn expect_eof(&mut self) {
- self.expect(Token::Eof)
- }
-
- fn create_invalidated_expression(&self, location: &Location) -> Rc {
- Rc::new(Expression::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- fn create_invalidated_directive(&self, location: &Location) -> Rc {
- Rc::new(Directive::Invalidated(InvalidatedNode {
- location: location.clone(),
- }))
- }
-
- pub fn parse_expression(&mut self, context: ParserExpressionContext) -> Rc {
- if let Some(exp) = self.parse_opt_expression(context) {
- exp
- } else {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingExpression, diagarg![self.token.0.clone()]);
- self.create_invalidated_expression(&self.tokenizer.cursor_location())
- }
- }
-
- pub fn parse_opt_expression(&mut self, context: ParserExpressionContext) -> Option> {
- let exp: Option> = self.parse_opt_start_expression(context.clone());
-
- // Parse subexpressions
- if let Some(exp) = exp {
- return Some(self.parse_subexpressions(exp, context.clone()));
- }
- None
- }
-
- fn parse_subexpressions(&mut self, mut base: Rc, context: ParserExpressionContext) -> Rc {
- loop {
- if self.consume(Token::Dot) {
- base = self.parse_dot_subexpression(base);
- } else if self.consume(Token::OptionalChaining) {
- base = self.parse_optional_chaining(base);
- } else if self.peek(Token::SquareOpen) {
- let asdoc = self.parse_asdoc();
- self.next();
- self.push_location(&base.location());
- let key = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::SquareClose);
- base = Rc::new(Expression::ComputedMember(ComputedMemberExpression {
- base, asdoc, key, location: self.pop_location()
- }));
- } else if self.consume(Token::Descendants) {
- self.push_location(&base.location());
- let id = self.parse_qualified_identifier();
- base = Rc::new(Expression::Descendants(DescendantsExpression {
- location: self.pop_location(),
- base,
- identifier: id,
- }));
- } else if self.peek(Token::ParenOpen) {
- self.push_location(&base.location());
- let arguments = self.parse_arguments();
- base = Rc::new(Expression::Call(CallExpression {
- location: self.pop_location(),
- base,
- arguments,
- }));
- } else if self.peek(Token::Increment) && !self.previous_token.1.line_break(&self.token.1) {
- self.push_location(&base.location());
- self.next();
- base = Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base,
- operator: Operator::PostIncrement,
- }));
- } else if self.peek(Token::Decrement) && !self.previous_token.1.line_break(&self.token.1) {
- self.push_location(&base.location());
- self.next();
- base = Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base,
- operator: Operator::PostDecrement,
- }));
- } else if self.peek(Token::Exclamation) && !self.previous_token.1.line_break(&self.token.1) {
- self.push_location(&base.location());
- self.next();
- base = Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base, operator: Operator::NonNull,
- }));
- // `not in`
- } else if self.token.0 == Token::Not && context.allow_in && context.min_precedence.includes(&OperatorPrecedence::Relational) && !self.previous_token.1.line_break(&self.token.1) {
- self.push_location(&base.location());
- self.next();
- self.non_greedy_expect(Token::In);
- base = self.parse_binary_operator(base, Operator::NotIn, OperatorPrecedence::Relational.add(1).unwrap(), context.clone());
- // ConditionalExpression
- } else if self.peek(Token::Question) && context.min_precedence.includes(&OperatorPrecedence::AssignmentAndOther) {
- self.push_location(&base.location());
- self.next();
- let consequent = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..context.clone()
- });
- let mut alternative = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::Colon);
- if !self.expecting_token_error {
- alternative = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..context.clone()
- });
- }
- base = Rc::new(Expression::Conditional(ConditionalExpression {
- location: self.pop_location(),
- test: base, consequent, alternative,
- }));
- } else if let Some(binary_operator) = self.check_binary_operator(context.clone()) {
- let BinaryOperator(operator, required_precedence, _) = binary_operator;
- if context.min_precedence.includes(&required_precedence) {
- self.next();
- base = self.parse_binary_operator(base, operator, binary_operator.right_precedence(), context.clone());
- } else {
- break;
- }
- // AssignmentExpression
- } else if self.peek(Token::Assign) && context.min_precedence.includes(&OperatorPrecedence::AssignmentAndOther) && context.allow_assignment {
- self.push_location(&base.location());
- self.next();
- let left = base.clone();
- if !left.is_valid_assignment_left_hand_side() {
- self.add_syntax_error(&left.location(), DiagnosticKind::MalformedDestructuring, vec![])
- }
- let right = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..context.clone()
- });
- base = Rc::new(Expression::Assignment(AssignmentExpression {
- location: self.pop_location(),
- left, compound: None, right,
- }));
- // CompoundAssignment and LogicalAssignment
- } else if let Some(compound) = self.token.0.compound_assignment() {
- if context.min_precedence.includes(&OperatorPrecedence::AssignmentAndOther) && context.allow_assignment {
- self.push_location(&base.location());
- self.next();
- let left = base.clone();
- let right = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..context.clone()
- });
- base = Rc::new(Expression::Assignment(AssignmentExpression {
- location: self.pop_location(),
- left, compound: Some(compound), right,
- }));
- } else {
- break;
- }
- } else if self.peek(Token::Comma) && context.min_precedence.includes(&OperatorPrecedence::List) {
- self.push_location(&base.location());
- self.next();
- let right = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..context.clone()
- });
- base = Rc::new(Expression::Sequence(SequenceExpression {
- location: self.pop_location(),
- left: base, right,
- }));
- } else {
- break;
- }
- }
-
- base
- }
-
- fn parse_binary_operator(&mut self, base: Rc, mut operator: Operator, right_precedence: OperatorPrecedence, context: ParserExpressionContext) -> Rc {
- // The left operand of a null-coalescing operation must not be
- // a logical AND, XOR or OR operation.
- if operator == Operator::NullCoalescing {
- if let Expression::Unary(UnaryExpression { expression, operator, .. }) = base.as_ref() {
- if [Operator::LogicalAnd, Operator::LogicalXor, Operator::LogicalOr].contains(&operator) {
- self.add_syntax_error(&expression.location(), DiagnosticKind::IllegalNullishCoalescingLeftOperand, vec![]);
- }
- }
- }
-
- if operator == Operator::Is && self.consume(Token::Not) {
- operator = Operator::IsNot;
- }
-
- self.push_location(&base.location());
- let right = self.parse_expression(ParserExpressionContext {
- min_precedence: right_precedence,
- ..context
- });
- Rc::new(Expression::Binary(BinaryExpression {
- location: self.pop_location(),
- left: base, operator, right,
- }))
- }
-
- fn check_binary_operator(&self, context: ParserExpressionContext) -> Option {
- if let Some(operator) = self.token.0.to_binary_operator() {
- if operator == Operator::In && !context.allow_in {
- return None;
- }
- BinaryOperator::try_from(operator).ok()
- } else {
- None
- }
- }
-
- fn parse_optional_chaining(&mut self, base: Rc) -> Rc {
- self.push_location(&base.location());
- self.duplicate_location();
- let mut operation = Rc::new(Expression::OptionalChainingPlaceholder(OptionalChainingPlaceholder {
- location: base.location(),
- }));
- if self.peek(Token::ParenOpen) {
- let arguments: Vec> = self.parse_arguments();
- if arguments.len() == 1 && self.peek(Token::ColonColon) {
- self.duplicate_location();
- let ql = self.pop_location();
- let q = Rc::new(Expression::Paren(ParenExpression {
- location: ql.clone(),
- expression: arguments[0].clone(),
- }));
- let identifier = self.finish_qualified_identifier(false, ql, q);
- operation = Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base: operation,
- identifier,
- }));
- } else {
- operation = Rc::new(Expression::Call(CallExpression {
- location: self.pop_location(),
- base: operation, arguments
- }));
- }
- } else if self.peek(Token::SquareOpen) {
- let asdoc = self.parse_asdoc();
- self.next();
- let key = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::SquareClose);
- operation = Rc::new(Expression::ComputedMember(ComputedMemberExpression {
- location: self.pop_location(),
- base: operation, asdoc, key,
- }));
- } else {
- let identifier = self.parse_qualified_identifier();
- operation = Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base: operation, identifier
- }));
- }
-
- // Parse postfix subexpressions
- operation = self.parse_optional_chaining_subexpressions(operation);
-
- Rc::new(Expression::OptionalChaining(OptionalChainingExpression {
- location: self.pop_location(),
- base, expression: operation,
- }))
- }
-
- fn parse_optional_chaining_subexpressions(&mut self, mut base: Rc) -> Rc {
- loop {
- if self.consume(Token::Dot) {
- base = self.parse_dot_subexpression(base);
- } else if self.consume(Token::OptionalChaining) {
- base = self.parse_optional_chaining(base);
- } else if self.peek(Token::SquareOpen) {
- self.next();
- self.push_location(&base.location());
- let key = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::SquareClose);
- base = Rc::new(Expression::ComputedMember(ComputedMemberExpression {
- base, asdoc: None, key, location: self.pop_location()
- }));
- } else if self.consume(Token::Descendants) {
- self.push_location(&base.location());
- let id = self.parse_qualified_identifier();
- base = Rc::new(Expression::Descendants(DescendantsExpression {
- location: self.pop_location(),
- base,
- identifier: id,
- }));
- } else if self.peek(Token::ParenOpen) {
- self.push_location(&base.location());
- let arguments = self.parse_arguments();
- base = Rc::new(Expression::Call(CallExpression {
- location: self.pop_location(),
- base,
- arguments,
- }));
- } else if self.peek(Token::Exclamation) && !self.previous_token.1.line_break(&self.token.1) {
- self.push_location(&base.location());
- self.next();
- base = Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base, operator: Operator::NonNull,
- }));
- } else {
- break;
- }
- }
-
- base
- }
-
- fn parse_dot_subexpression(&mut self, base: Rc) -> Rc {
- self.push_location(&base.location());
- if self.peek(Token::ParenOpen) {
- let paren_location = self.token_location();
- let paren_exp = self.parse_paren_list_expression();
- if !matches!(paren_exp.as_ref(), Expression::Sequence(_)) && self.peek(Token::ColonColon) {
- let q = Rc::new(Expression::Paren(ParenExpression {
- location: paren_location.clone(),
- expression: paren_exp.clone(),
- }));
- let id = self.finish_qualified_identifier(false, paren_location, q);
- Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base, identifier: id
- }))
- } else {
- Rc::new(Expression::Filter(FilterExpression {
- location: self.pop_location(),
- base, test: paren_exp
- }))
- }
- } else if self.consume(Token::Lt) {
- let mut arguments = vec![];
- arguments.push(self.parse_type_expression());
- while self.consume(Token::Comma) {
- arguments.push(self.parse_type_expression());
- }
- self.non_greedy_expect_type_parameters_gt();
- Rc::new(Expression::WithTypeArguments(ExpressionWithTypeArguments {
- location: self.pop_location(),
- base, arguments
- }))
- } else {
- let id = self.parse_qualified_identifier();
- Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base, identifier: id
- }))
- }
- }
-
- /// Ensures a parameter list consists of zero or more required parameters followed by
- /// zero or more optional parameters optionally followed by a rest parameter.
- fn validate_parameter_list(&mut self, params: Vec<(ParameterKind, Location)>) {
- let mut least_kind = ParameterKind::Required;
- let mut has_rest = false;
- for (param_kind, param_loc) in params {
- if !least_kind.may_be_followed_by(param_kind) {
- self.add_syntax_error(¶m_loc, DiagnosticKind::WrongParameterPosition, vec![]);
- }
- least_kind = param_kind;
- if param_kind == ParameterKind::Rest && has_rest {
- self.add_syntax_error(¶m_loc, DiagnosticKind::DuplicateRestParameter, vec![]);
- }
- has_rest = param_kind == ParameterKind::Rest;
- }
- }
-
- fn parse_opt_start_expression(&mut self, context: ParserExpressionContext) -> Option> {
- if let Token::Identifier(id) = self.token.0.clone() {
- let id_location = self.token_location();
- self.next();
- Some(self.parse_expression_starting_with_identifier((id, id_location)))
- } else if self.peek(Token::Null) {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::NullLiteral(NullLiteral {
- location: self.pop_location(),
- })))
- } else if self.peek(Token::False) {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::BooleanLiteral(BooleanLiteral {
- location: self.pop_location(),
- value: false,
- })))
- } else if self.peek(Token::True) {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::BooleanLiteral(BooleanLiteral {
- location: self.pop_location(),
- value: true,
- })))
- } else if let Token::Number(n, suffix) = self.token.0.clone() {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::NumericLiteral(NumericLiteral {
- location: self.pop_location(),
- value: n,
- suffix,
- })))
- } else if let Token::String(ref s) = self.token.0.clone() {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::StringLiteral(StringLiteral {
- location: self.pop_location(),
- value: s.clone(),
- })))
- } else if self.peek(Token::This) {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::ThisLiteral(ThisLiteral {
- location: self.pop_location(),
- })))
- } else if self.peek(Token::Div) || self.peek(Token::DivideAssign) {
- self.mark_location();
- self.token = self.tokenizer.scan_regexp_literal(self.token.1.clone(), if self.peek(Token::DivideAssign) { "=".into() } else { "".into() });
- let Token::RegExp { ref body, ref flags } = self.token.0.clone() else {
- panic!();
- };
- self.next();
- Some(Rc::new(Expression::RegExpLiteral(RegExpLiteral {
- location: self.pop_location(),
- body: body.clone(), flags: flags.clone(),
- })))
- // `@`
- } else if self.peek(Token::Attribute) {
- self.mark_location();
- let id = self.parse_qualified_identifier();
- Some(Rc::new(Expression::QualifiedIdentifier(id)))
- // Parentheses
- } else if self.peek(Token::ParenOpen) {
- Some(self.parse_paren_list_expr_or_qual_id())
- // XMLList, XMLElement, XMLMarkup
- } else if self.peek(Token::Lt) {
- if let Some(token) = self.tokenizer.scan_xml_markup(self.token_location()) {
- self.token = token;
- }
- let start = self.token_location();
- if let Token::XmlMarkup(content) = &self.token.0.clone() {
- self.mark_location();
- self.next();
- Some(Rc::new(Expression::XmlMarkup(XmlMarkupExpression {
- location: self.pop_location(),
- markup: content.clone(),
- })))
- } else {
- Some(self.parse_xml_element_or_xml_list(start))
- }
- // ArrayInitializer
- } else if self.peek(Token::SquareOpen) {
- Some(self.parse_array_initializer())
- // NewExpression
- } else if self.peek(Token::New) && context.min_precedence.includes(&OperatorPrecedence::Unary) {
- let start = self.token_location();
- self.next();
- Some(self.parse_new_expression(start))
- } else if self.peek(Token::BlockOpen) {
- Some(self.parse_object_initializer())
- } else if self.peek(Token::Function) && context.min_precedence.includes(&OperatorPrecedence::AssignmentAndOther) {
- Some(self.parse_function_expression(context.clone()))
- // SuperExpression
- } else if self.peek(Token::Super) && context.min_precedence.includes(&OperatorPrecedence::Postfix) {
- Some(self.parse_super_expression_followed_by_property_operator())
- // AwaitExpression
- } else if self.peek(Token::Await) && context.min_precedence.includes(&OperatorPrecedence::Unary) {
- self.mark_location();
- let operator_token = self.token.clone();
- self.next();
- let base = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::Unary,
- ..default()
- });
- if let Some(activation) = self.activations.last_mut() {
- activation.uses_await = true;
- } else {
- self.add_syntax_error(&operator_token.1, DiagnosticKind::NotAllowedHere, diagarg![operator_token.0]);
- }
- Some(Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base, operator: Operator::Await,
- })))
- // YieldExpression
- } else if self.peek(Token::Yield) && context.min_precedence.includes(&OperatorPrecedence::AssignmentAndOther) {
- self.mark_location();
- let operator_token = self.token.clone();
- self.next();
- let base = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- });
- if let Some(activation) = self.activations.last_mut() {
- activation.uses_yield = true;
- } else {
- self.add_syntax_error(&operator_token.1, DiagnosticKind::NotAllowedHere, diagarg![operator_token.0]);
- }
- Some(Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base, operator: Operator::Yield,
- })))
- // Miscellaneous prefix unary expressions
- } else if let Some((operator, subexp_precedence)) = self.check_prefix_operator() {
- if context.min_precedence.includes(&OperatorPrecedence::Unary) {
- self.mark_location();
- self.next();
- let base = self.parse_expression(ParserExpressionContext { min_precedence: subexp_precedence, ..default() });
- Some(Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- expression: base, operator,
- })))
- } else {
- None
- }
- // ImportMeta
- } else if self.peek(Token::Import) && context.min_precedence.includes(&OperatorPrecedence::Postfix) {
- self.mark_location();
- self.next();
- self.non_greedy_expect(Token::Dot);
- self.non_greedy_expect_context_keyword("meta");
- Some(Rc::new(Expression::ImportMeta(ImportMeta {
- location: self.pop_location(),
- })))
- // QualifiedIdentifier
- } else if
- self.peek(Token::Times)
- || self.peek(Token::Public) || self.peek(Token::Private)
- || self.peek(Token::Protected) || self.peek(Token::Internal) {
- let id = self.parse_qualified_identifier();
- Some(Rc::new(Expression::QualifiedIdentifier(id)))
- } else {
- None
- }
- }
-
- fn parse_expression_starting_with_identifier(&mut self, id: (String, Location)) -> Rc {
- let id_location = id.1.clone();
- let id = id.0;
-
- /*
- // EmbedExpression
- if self.peek(Token::BlockOpen) && id == "embed" && self.previous_token.1.character_count() == "embed".len() {
- return self.finish_embed_expression(id_location);
- }
- */
-
- let id = Rc::new(Expression::QualifiedIdentifier(QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- }));
- if self.peek(Token::ColonColon) {
- self.push_location(&id_location.clone());
- let ql = self.pop_location();
- let id = self.finish_qualified_identifier(false, ql, id);
- Rc::new(Expression::QualifiedIdentifier(id))
- } else {
- id
- }
- }
-
- fn check_prefix_operator(&self) -> Option<(Operator, OperatorPrecedence)> {
- match self.token.0 {
- Token::Delete => Some((Operator::Delete, OperatorPrecedence::Postfix)),
- Token::Void => Some((Operator::Void, OperatorPrecedence::Unary)),
- Token::Typeof => Some((Operator::Typeof, OperatorPrecedence::Unary)),
- Token::Increment => Some((Operator::PreIncrement, OperatorPrecedence::Postfix)),
- Token::Decrement => Some((Operator::PreDecrement, OperatorPrecedence::Postfix)),
- Token::Plus => Some((Operator::Positive, OperatorPrecedence::Unary)),
- Token::Minus => Some((Operator::Negative, OperatorPrecedence::Unary)),
- Token::Tilde => Some((Operator::BitwiseNot, OperatorPrecedence::Unary)),
- Token::Exclamation => Some((Operator::LogicalNot, OperatorPrecedence::Unary)),
- _ => None,
- }
- }
-
- fn parse_function_expression(&mut self, context: ParserExpressionContext) -> Rc {
- self.mark_location();
- self.next();
- let mut name = None;
- if let Token::Identifier(id) = self.token.0.clone() {
- name = Some((id, self.token.1.clone()));
- self.next();
- }
- let common = self.parse_function_common(true, ParserDirectiveContext::Default, context.allow_in);
- Rc::new(Expression::Function(FunctionExpression {
- location: self.pop_location(),
- name,
- common,
- }))
- }
-
- fn parse_function_common(&mut self, function_expr: bool, block_context: ParserDirectiveContext, allow_in: bool) -> Rc {
- self.mark_location();
- self.duplicate_location();
- let mut params: Vec> = vec![];
- let mut return_annotation = Some(self.create_invalidated_expression(&self.tokenizer.cursor_location()));
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- if !self.peek(Token::ParenClose) {
- params.push(self.parse_parameter());
- while self.consume(Token::Comma) {
- params.push(self.parse_parameter());
- }
- }
- self.non_greedy_expect(Token::ParenClose);
- if !self.expecting_token_error {
- return_annotation = if self.consume(Token::Colon) { Some(self.parse_type_expression()) } else { None };
- }
- self.validate_parameter_list(params.iter().map(|p| (p.kind, p.location.clone())).collect::>());
- }
-
- let signature_location = self.pop_location();
-
- // Enter activation
- self.activations.push(ParserActivation::new());
-
- // Body
- let body = if self.peek(Token::BlockOpen) {
- Some(FunctionBody::Block(Rc::new(self.parse_block(block_context))))
- } else if !(self.offending_token_is_inline_or_higher_indented() || self.peek(Token::ParenOpen)) {
- None
- } else {
- self.parse_opt_expression(ParserExpressionContext {
- allow_in,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }).map(|e| FunctionBody::Expression(e))
- };
-
- // Body is required by function expressions
- if body.is_none() && function_expr {
- self.non_greedy_expect(Token::BlockOpen);
- }
-
- // Exit activation
- let activation = self.activations.pop().unwrap();
-
- Rc::new(FunctionCommon {
- location: self.pop_location(),
- contains_await: activation.uses_await,
- contains_yield: activation.uses_yield,
- signature: FunctionSignature {
- location: signature_location,
- parameters: params,
- result_type: return_annotation,
- },
- body,
- })
- }
-
- fn parse_parameter(&mut self) -> Rc {
- self.mark_location();
- let rest = self.consume(Token::Ellipsis);
- let binding: Rc = Rc::new(self.parse_variable_binding(true));
- let has_initializer = binding.initializer.is_some();
- let location = self.pop_location();
- if rest && has_initializer {
- self.add_syntax_error(&location.clone(), DiagnosticKind::MalformedRestParameter, vec![]);
- }
- Rc::new(Parameter {
- location,
- destructuring: binding.destructuring.clone(),
- default_value: binding.initializer.clone(),
- kind: if rest {
- ParameterKind::Rest
- } else if has_initializer {
- ParameterKind::Optional
- } else {
- ParameterKind::Required
- },
- })
- }
-
- fn parse_object_initializer(&mut self) -> Rc {
- self.mark_location();
- self.non_greedy_expect(Token::BlockOpen);
- let mut fields: Vec> = vec![];
- while !self.peek(Token::BlockClose) {
- fields.push(self.parse_field());
- if !self.consume(Token::Comma) {
- break;
- }
- }
- self.non_greedy_expect(Token::BlockClose);
-
- Rc::new(Expression::ObjectInitializer(ObjectInitializer {
- location: self.pop_location(),
- fields,
- }))
- }
-
- fn parse_field(&mut self) -> Rc {
- if self.peek(Token::Ellipsis) {
- self.mark_location();
- self.next();
- let subexp = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- });
- return Rc::new(InitializerField::Rest((subexp, self.pop_location())));
- }
-
- let name = self.parse_field_name();
-
- let non_null = self.consume(Token::Exclamation);
- let mut value = None;
-
- if self.consume(Token::Colon) {
- value = Some(self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }));
- } else if !matches!(name.0, FieldName::Identifier(_)) {
- self.non_greedy_expect(Token::Colon);
- }
-
- Rc::new(InitializerField::Field {
- name,
- non_null,
- value,
- })
- }
-
- fn parse_field_name(&mut self) -> (FieldName, Location) {
- if let Token::String(value) = &self.token.0.clone() {
- let location = self.token_location();
- self.next();
- (FieldName::StringLiteral(Rc::new(Expression::StringLiteral(StringLiteral {
- location: location.clone(),
- value: value.clone(),
- }))), location)
- } else if let Token::Number(value, suffix) = &self.token.0.clone() {
- let location = self.token_location();
- self.next();
- (FieldName::NumericLiteral(Rc::new(Expression::NumericLiteral(NumericLiteral {
- location: location.clone(),
- value: value.clone(),
- suffix: *suffix,
- }))), location)
- } else if self.peek(Token::SquareOpen) {
- self.mark_location();
- self.next();
- let key_expr = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::List,
- ..default()
- });
- self.non_greedy_expect(Token::SquareClose);
- let location = self.pop_location();
- (FieldName::Brackets(key_expr), location)
- } else {
- let id = self.parse_non_attribute_qualified_identifier();
- let l = id.location.clone();
- (FieldName::Identifier(id), l)
- }
- }
-
- fn parse_new_expression(&mut self, start: Location) -> Rc {
- self.push_location(&start);
- if self.consume(Token::Lt) {
- let element_type = self.parse_type_expression();
- self.non_greedy_expect_type_parameters_gt();
- let mut elements: Vec = vec![];
- self.non_greedy_expect(Token::SquareOpen);
- if !self.expecting_token_error {
- while !self.peek(Token::SquareClose) {
- if self.peek(Token::Ellipsis) {
- self.mark_location();
- self.next();
- elements.push(Element::Rest((self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }), self.pop_location())));
- } else {
- elements.push(Element::Expression(self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- })));
- }
- if !self.consume(Token::Comma) {
- break;
- }
- }
- self.non_greedy_expect(Token::SquareClose);
- }
- Rc::new(Expression::VectorLiteral(VectorLiteral {
- location: self.pop_location(),
- element_type,
- elements,
- }))
- } else {
- let base = self.parse_new_subexpression();
- let arguments = if self.peek(Token::ParenOpen) { Some(self.parse_arguments()) } else { None };
- Rc::new(Expression::New(NewExpression {
- location: self.pop_location(),
- base, arguments,
- }))
- }
- }
-
- fn parse_new_expression_start(&mut self) -> Rc {
- if self.peek(Token::New) {
- let start = self.token_location();
- self.next();
- self.parse_new_expression(start)
- } else if self.peek(Token::Super) {
- self.parse_super_expression_followed_by_property_operator()
- } else {
- self.parse_primary_expression()
- }
- }
-
- fn parse_super_expression_followed_by_property_operator(&mut self) -> Rc {
- self.mark_location();
- self.duplicate_location();
- self.next();
- let arguments = if self.peek(Token::ParenOpen) { Some(self.parse_arguments()) } else { None };
- let super_expr = Rc::new(Expression::Super(SuperExpression {
- location: self.pop_location(),
- object: arguments,
- }));
-
- if self.consume(Token::SquareOpen) {
- let key = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::SquareClose);
- Rc::new(Expression::ComputedMember(ComputedMemberExpression {
- location: self.pop_location(),
- base: super_expr, asdoc: None, key,
- }))
- } else {
- self.non_greedy_expect(Token::Dot);
- let identifier = self.parse_qualified_identifier();
- Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base: super_expr, identifier,
- }))
- }
- }
-
- fn parse_arguments(&mut self) -> Vec> {
- self.non_greedy_expect(Token::ParenOpen);
- let mut arguments = vec![];
- if !self.peek(Token::ParenClose) {
- arguments.push(self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }));
- while self.consume(Token::Comma) {
- arguments.push(self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }));
- }
- }
- self.non_greedy_expect(Token::ParenClose);
- arguments
- }
-
- fn parse_new_subexpression(&mut self) -> Rc {
- let mut base = self.parse_new_expression_start();
- loop {
- if self.consume(Token::SquareOpen) {
- self.push_location(&base.location());
- let key = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::SquareClose);
- base = Rc::new(Expression::ComputedMember(ComputedMemberExpression {
- location: self.pop_location(),
- base, asdoc: None, key,
- }));
- } else if self.consume(Token::Dot) {
- self.push_location(&base.location());
- if self.consume(Token::Lt) {
- let mut arguments = vec![];
- arguments.push(self.parse_type_expression());
- while self.consume(Token::Comma) {
- arguments.push(self.parse_type_expression());
- }
- self.non_greedy_expect_type_parameters_gt();
- base = Rc::new(Expression::WithTypeArguments(ExpressionWithTypeArguments {
- location: self.pop_location(),
- base, arguments
- }));
- } else {
- let identifier = self.parse_qualified_identifier();
- base = Rc::new(Expression::Member(MemberExpression {
- location: self.pop_location(),
- base, identifier,
- }));
- }
- } else {
- break;
- }
- }
- base
- }
-
- fn parse_primary_expression(&mut self) -> Rc {
- if let Token::Identifier(id) = self.token.0.clone() {
- let id_location = self.token_location();
- self.next();
-
- /*
- // EmbedExpression
- if self.peek(Token::BlockOpen) && id == "embed" && self.previous_token.1.character_count() == "embed".len() {
- return self.finish_embed_expression(id_location);
- }
- */
-
- let id = Rc::new(Expression::QualifiedIdentifier(QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- }));
- if self.peek(Token::ColonColon) {
- self.push_location(&id_location.clone());
- let ql = self.pop_location();
- let id = self.finish_qualified_identifier(false, ql, id);
- Rc::new(Expression::QualifiedIdentifier(id))
- } else {
- id
- }
- } else if self.peek(Token::Null) {
- self.mark_location();
- self.next();
- Rc::new(Expression::NullLiteral(NullLiteral {
- location: self.pop_location(),
- }))
- } else if self.peek(Token::False) {
- self.mark_location();
- self.next();
- Rc::new(Expression::BooleanLiteral(BooleanLiteral {
- location: self.pop_location(),
- value: false,
- }))
- } else if self.peek(Token::True) {
- self.mark_location();
- self.next();
- Rc::new(Expression::BooleanLiteral(BooleanLiteral {
- location: self.pop_location(),
- value: true,
- }))
- } else if let Token::Number(n, suffix) = self.token.0.clone() {
- self.mark_location();
- self.next();
- Rc::new(Expression::NumericLiteral(NumericLiteral {
- location: self.pop_location(),
- value: n,
- suffix,
- }))
- } else if let Token::String(ref s) = self.token.0.clone() {
- self.mark_location();
- self.next();
- Rc::new(Expression::StringLiteral(StringLiteral {
- location: self.pop_location(),
- value: s.clone(),
- }))
- } else if self.peek(Token::This) {
- self.mark_location();
- self.next();
- Rc::new(Expression::ThisLiteral(ThisLiteral {
- location: self.pop_location(),
- }))
- } else if self.peek(Token::Div) || self.peek(Token::DivideAssign) {
- self.mark_location();
- self.token = self.tokenizer.scan_regexp_literal(self.token.1.clone(), if self.peek(Token::DivideAssign) { "=".into() } else { "".into() });
- let Token::RegExp { ref body, ref flags } = self.token.0.clone() else {
- panic!();
- };
- self.next();
- Rc::new(Expression::RegExpLiteral(RegExpLiteral {
- location: self.pop_location(),
- body: body.clone(), flags: flags.clone(),
- }))
- // `@`
- } else if self.peek(Token::Attribute) {
- self.mark_location();
- let id = self.parse_qualified_identifier();
- Rc::new(Expression::QualifiedIdentifier(id))
- // Parentheses
- } else if self.peek(Token::ParenOpen) {
- return self.parse_paren_list_expr_or_qual_id();
- // XMLList, XMLElement, XMLMarkup
- } else if self.peek(Token::Lt) {
- if let Some(token) = self.tokenizer.scan_xml_markup(self.token_location()) {
- self.token = token;
- }
- let start = self.token_location();
- if let Token::XmlMarkup(content) = &self.token.0.clone() {
- self.mark_location();
- self.next();
- Rc::new(Expression::XmlMarkup(XmlMarkupExpression {
- location: self.pop_location(),
- markup: content.clone(),
- }))
- } else {
- self.parse_xml_element_or_xml_list(start)
- }
- // ArrayInitializer
- } else if self.peek(Token::SquareOpen) {
- self.parse_array_initializer()
- } else if self.peek(Token::BlockOpen) {
- self.parse_object_initializer()
- // QualifiedIdentifier
- } else if
- self.peek(Token::Times)
- || self.peek(Token::Public) || self.peek(Token::Private)
- || self.peek(Token::Protected) || self.peek(Token::Internal) {
- let id = self.parse_qualified_identifier();
- Rc::new(Expression::QualifiedIdentifier(id))
- } else {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingExpression, diagarg![self.token.0.clone()]);
- self.create_invalidated_expression(&self.tokenizer.cursor_location())
- }
- }
-
- /*
- fn finish_embed_expression(&mut self, start: Location) -> Rc {
- self.push_location(&start);
- let descriptor = self.parse_object_initializer().clone();
- let Expression::ObjectInitializer(descriptor) = descriptor.as_ref() else {
- panic!();
- };
- return Rc::new(Expression::Embed(EmbedExpression {
- location: self.pop_location(),
- description: descriptor.clone(),
- }));
- }
- */
-
- fn parse_array_initializer(&mut self) -> Rc {
- self.mark_location();
-
- let asdoc = self.parse_asdoc();
-
- self.non_greedy_expect(Token::SquareOpen);
-
- let mut elements: Vec = vec![];
-
- while !self.peek(Token::SquareClose) {
- let mut ellipses = false;
- while self.consume(Token::Comma) {
- elements.push(Element::Elision);
- ellipses = true;
- }
- if !ellipses {
- if self.peek(Token::Ellipsis) {
- self.mark_location();
- self.next();
- elements.push(Element::Rest((self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }), self.pop_location())));
- } else {
- elements.push(Element::Expression(self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- })));
- }
- }
- if !self.consume(Token::Comma) {
- break;
- }
- }
- self.non_greedy_expect(Token::SquareClose);
- Rc::new(Expression::ArrayLiteral(ArrayLiteral {
- location: self.pop_location(),
- asdoc,
- elements,
- }))
- }
-
- fn parse_xml_element_or_xml_list(&mut self, start: Location) -> Rc {
- self.next_ie_xml_tag();
- if self.consume_and_ie_xml_content(Token::Gt) {
- self.push_location(&start);
- let content = self.parse_xml_content();
- self.non_greedy_expect_and_ie_xml_tag(Token::XmlLtSlash);
- self.non_greedy_expect(Token::Gt);
- return Rc::new(Expression::XmlList(XmlListExpression {
- location: self.pop_location(),
- content,
- }));
- }
-
- self.push_location(&start);
- let element = Rc::new(self.parse_xml_element(start, true));
- return Rc::new(Expression::Xml(XmlExpression {
- location: self.pop_location(),
- element,
- }));
- }
-
- /// Parses XMLElement starting from its XMLTagContent.
- fn parse_xml_element(&mut self, start: Location, ends_at_ie_div: bool) -> XmlElement {
- self.push_location(&start);
- let name = self.parse_xml_tag_name();
- let mut attributes: Vec> = vec![];
- let mut attribute_expression: Option> = None;
- while self.consume_and_ie_xml_tag(Token::XmlWhitespace) {
- if self.consume(Token::BlockOpen) {
- let expr = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::AssignmentAndOther, ..default() });
- self.expect_and_ie_xml_tag(Token::BlockClose);
- attribute_expression = Some(expr);
- self.consume_and_ie_xml_tag(Token::XmlWhitespace);
- break;
- } else if matches!(self.token.0, Token::XmlName(_)) {
- self.mark_location();
- let name = self.parse_xml_name();
- self.consume_and_ie_xml_tag(Token::XmlWhitespace);
- self.non_greedy_expect_and_ie_xml_tag(Token::Assign);
- let mut value = XmlAttributeValue::Value(("".into(), self.token.1.clone()));
- if !self.expecting_token_error {
- self.consume_and_ie_xml_tag(Token::XmlWhitespace);
- if self.consume(Token::BlockOpen) {
- let expr = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::AssignmentAndOther, ..default() });
- self.expect_and_ie_xml_tag(Token::BlockClose);
- value = XmlAttributeValue::Expression(expr);
- } else {
- value = XmlAttributeValue::Value(self.parse_xml_attribute_value());
- }
- }
- attributes.push(Rc::new(XmlAttribute {
- location: self.pop_location(),
- name, value
- }));
- } else {
- break;
- }
- }
-
- let mut content: Option>> = None;
- let mut closing_name: Option = None;
-
- let is_empty;
-
- if ends_at_ie_div {
- is_empty = self.consume(Token::XmlSlashGt);
- } else {
- is_empty = self.consume_and_ie_xml_content(Token::XmlSlashGt);
- }
-
- if !is_empty {
- self.expect_and_ie_xml_content(Token::Gt);
- content = Some(self.parse_xml_content());
- self.non_greedy_expect_and_ie_xml_tag(Token::XmlLtSlash);
- closing_name = Some(self.parse_xml_tag_name());
- self.consume_and_ie_xml_tag(Token::XmlWhitespace);
- if ends_at_ie_div {
- self.non_greedy_expect(Token::Gt);
- } else {
- self.non_greedy_expect_and_ie_xml_content(Token::Gt);
- }
- }
-
- XmlElement {
- location: self.pop_location(),
- name,
- attributes,
- attribute_expression,
- content,
- closing_name,
- }
- }
-
- fn parse_xml_attribute_value(&mut self) -> (String, Location) {
- if let Token::XmlAttributeValue(value) = self.token.0.clone() {
- let location = self.token_location();
- self.next_ie_xml_tag();
- return (value, location);
- } else {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingXmlAttributeValue, diagarg![self.token.0.clone()]);
- ("".into(), self.tokenizer.cursor_location())
- }
- }
-
- fn parse_xml_tag_name(&mut self) -> XmlTagName {
- if self.consume(Token::BlockOpen) {
- let expr = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- });
- self.expect_and_ie_xml_tag(Token::BlockClose);
- XmlTagName::Expression(expr)
- } else {
- XmlTagName::Name(self.parse_xml_name())
- }
- }
-
- fn parse_xml_name(&mut self) -> (String, Location) {
- if let Token::XmlName(name) = self.token.0.clone() {
- let name_location = self.token_location();
- self.next_ie_xml_tag();
- return (name, name_location);
- } else {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingXmlName, diagarg![self.token.0.clone()]);
- (INVALIDATED_IDENTIFIER.into(), self.tokenizer.cursor_location())
- }
- }
-
- /// Parses XMLContent until a `` token.
- fn parse_xml_content(&mut self) -> Vec> {
- let mut content = vec![];
- while !self.peek(Token::XmlLtSlash) {
- if self.consume(Token::BlockOpen) {
- let expr = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::AssignmentAndOther, ..default() });
- self.expect_and_ie_xml_content(Token::BlockClose);
- content.push(Rc::new(XmlContent::Expression(expr)));
- } else if let Token::XmlMarkup(markup) = self.token.0.clone() {
- let location = self.token_location();
- self.next_ie_xml_content();
- content.push(Rc::new(XmlContent::Markup((markup, location))));
- } else if let Token::XmlText(text) = self.token.0.clone() {
- if self.tokenizer.characters().reached_end() {
- self.expect_and_ie_xml_content(Token::XmlLtSlash);
- break;
- }
- let location = self.token_location();
- self.next_ie_xml_content();
- content.push(Rc::new(XmlContent::Characters((text, location))));
- } else if self.consume_and_ie_xml_tag(Token::Lt) {
- let start = self.token_location();
- let element = self.parse_xml_element(start, false);
- content.push(Rc::new(XmlContent::Element(Rc::new(element))));
- } else if self.peek(Token::Eof) {
- break;
- } else {
- self.expect_and_ie_xml_content(Token::XmlLtSlash);
- }
- }
- content
- }
-
- fn finish_paren_list_expr_or_qual_id(&mut self, start: Location, left: Rc) -> Rc {
- if self.peek(Token::ColonColon) && !matches!(left.as_ref(), Expression::Sequence(_)) {
- self.push_location(&start);
- let ql = self.pop_location();
- let left = Rc::new(Expression::Paren(ParenExpression {
- location: ql.clone(),
- expression: left,
- }));
- let id = self.finish_qualified_identifier(false, ql, left);
- return Rc::new(Expression::QualifiedIdentifier(id));
- }
- self.push_location(&start);
- return Rc::new(Expression::Paren(ParenExpression {
- location: self.pop_location(),
- expression: left,
- }));
- }
-
- /// Parses either a ParenListExpression, (), or a QualifiedIdentifier
- fn parse_paren_list_expr_or_qual_id(&mut self) -> Rc {
- let start = self.token_location();
- self.non_greedy_expect(Token::ParenOpen);
-
- let expr = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::List,
- allow_in: true,
- ..default()
- });
-
- self.non_greedy_expect(Token::ParenClose);
- self.finish_paren_list_expr_or_qual_id(start, expr)
- }
-
- fn parse_opt_reserved_namespace(&mut self) -> Option> {
- let loc = self.token.1.clone();
- if self.consume(Token::Public) {
- Some(Rc::new(Expression::ReservedNamespace(ReservedNamespaceExpression::Public(loc))))
- } else if self.consume(Token::Private) {
- Some(Rc::new(Expression::ReservedNamespace(ReservedNamespaceExpression::Private(loc))))
- } else if self.consume(Token::Protected) {
- Some(Rc::new(Expression::ReservedNamespace(ReservedNamespaceExpression::Protected(loc))))
- } else if self.consume(Token::Internal) {
- Some(Rc::new(Expression::ReservedNamespace(ReservedNamespaceExpression::Internal(loc))))
- } else {
- None
- }
- }
-
- fn parse_qualified_identifier(&mut self) -> QualifiedIdentifier {
- self.mark_location();
-
- let attribute = self.consume(Token::Attribute);
- if attribute && self.peek(Token::SquareOpen) {
- let brackets = self.parse_brackets();
- return QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Brackets(brackets),
- };
- }
-
- // public, private, protected, internal
- if let Some(qual) = self.parse_opt_reserved_namespace() {
- if self.peek(Token::ColonColon) {
- let ql = self.pop_location();
- return self.finish_qualified_identifier(attribute, ql, qual);
- } else {
- let id = QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((qual.to_reserved_namespace_string().unwrap(), qual.location())),
- };
- return id;
- }
- }
-
- let mut id: Option = None;
-
- // IdentifierName
- if let Token::Identifier(id_1) = self.token.0.clone() {
- id = Some(id_1);
- } else {
- if let Some(id_1) = self.token.0.reserved_word_name() {
- id = Some(id_1);
- } else if self.peek(Token::Times) {
- id = Some("*".to_owned());
- }
- }
-
- if let Some(id) = id {
- let id_location = self.token_location();
- self.next();
- if self.peek(Token::ColonColon) {
- let id = QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- };
- let id = Rc::new(Expression::QualifiedIdentifier(id));
- let ql = self.pop_location();
- return self.finish_qualified_identifier(attribute, ql, id);
- } else {
- let id = QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- };
- return id;
- }
- }
-
- // (q)::x
- if self.peek(Token::ParenOpen) {
- let qual = self.parse_paren_expression();
- let ql = self.pop_location();
- let qual = Rc::new(Expression::Paren(ParenExpression {
- location: ql.clone(),
- expression: qual,
- }));
- return self.finish_qualified_identifier(attribute, ql, qual);
- }
-
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id(("".into(), self.tokenizer.cursor_location())),
- }
- }
-
- fn parse_non_attribute_qualified_identifier(&mut self) -> QualifiedIdentifier {
- self.mark_location();
-
- let attribute = false;
-
- // public, private, protected, internal
- if let Some(qual) = self.parse_opt_reserved_namespace() {
- if self.peek(Token::ColonColon) {
- let ql = self.pop_location();
- return self.finish_qualified_identifier(attribute, ql, qual);
- } else {
- let id = QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((qual.to_reserved_namespace_string().unwrap(), qual.location())),
- };
- return id;
- }
- }
-
- let mut id: Option = None;
-
- // IdentifierName
- if let Token::Identifier(id_1) = self.token.0.clone() {
- id = Some(id_1);
- } else {
- if let Some(id_1) = self.token.0.reserved_word_name() {
- id = Some(id_1);
- } else if self.peek(Token::Times) {
- id = Some("*".to_owned());
- }
- }
-
- if let Some(id) = id {
- let id_location = self.token_location();
- self.next();
- if self.peek(Token::ColonColon) {
- let id = QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- };
- let id = Rc::new(Expression::QualifiedIdentifier(id));
- let ql = self.pop_location();
- return self.finish_qualified_identifier(attribute, ql, id);
- } else {
- let id = QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id((id, id_location.clone())),
- };
- return id;
- }
- }
-
- // (q)::x
- if self.peek(Token::ParenOpen) {
- let qual = self.parse_paren_expression();
- let ql = self.pop_location();
- let qual = Rc::new(Expression::Paren(ParenExpression {
- location: ql.clone(),
- expression: qual,
- }));
- return self.finish_qualified_identifier(attribute, ql, qual);
- }
-
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id(("".into(), self.tokenizer.cursor_location())),
- }
- }
-
- /// Expects a colon-colon and finishes a qualified identifier.
- fn finish_qualified_identifier(&mut self, attribute: bool, start_location: Location, qual: Rc) -> QualifiedIdentifier {
- self.push_location(&start_location);
- self.non_greedy_expect(Token::ColonColon);
-
- // `::` may be followed by one of { IdentifierName, `*`, Brackets }
-
- // IdentifierName
- if let Some(id) = self.consume_identifier(true) {
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: Some(qual),
- id: QualifiedIdentifierIdentifier::Id(id),
- }
- // `*`
- } else if self.peek(Token::Times) {
- let id_location = self.token_location();
- self.next();
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: Some(qual),
- id: QualifiedIdentifierIdentifier::Id(("*".into(), id_location)),
- }
- // Brackets
- } else if self.peek(Token::SquareOpen) {
- let brackets = self.parse_brackets();
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: Some(qual),
- id: QualifiedIdentifierIdentifier::Brackets(brackets),
- }
- } else {
- self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
- QualifiedIdentifier {
- location: self.pop_location(),
- attribute,
- qualifier: Some(qual),
- id: QualifiedIdentifierIdentifier::Id(("".into(), self.tokenizer.cursor_location())),
- }
- }
- }
-
- fn parse_brackets(&mut self) -> Rc {
- self.non_greedy_expect(Token::SquareOpen);
- let expr = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::List,
- allow_in: true,
- ..default()
- });
- self.non_greedy_expect(Token::SquareClose);
- expr
- }
-
- fn parse_paren_expression(&mut self) -> Rc {
- self.non_greedy_expect(Token::ParenOpen);
- let expr = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- allow_in: true,
- ..default()
- });
- self.non_greedy_expect(Token::ParenClose);
- expr
- }
-
- fn parse_paren_list_expression(&mut self) -> Rc {
- self.non_greedy_expect(Token::ParenOpen);
- let expr = self.parse_expression(ParserExpressionContext {
- min_precedence: OperatorPrecedence::List,
- allow_in: true,
- ..default()
- });
- self.non_greedy_expect(Token::ParenClose);
- expr
- }
-
- fn parse_typed_destructuring(&mut self) -> TypedDestructuring {
- self.mark_location();
- let mut destructuring: Rc;
- if self.peek(Token::BlockOpen) {
- destructuring = self.parse_object_initializer();
- } else if self.peek(Token::SquareOpen) {
- destructuring = self.parse_array_initializer();
- } else {
- let id = self.expect_identifier(true);
- let id = QualifiedIdentifier {
- location: id.1.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id(id.clone()),
- };
- destructuring = Rc::new(Expression::QualifiedIdentifier(id));
- }
- if self.consume(Token::Exclamation) {
- self.push_location(&destructuring.location());
- destructuring = Rc::new(Expression::Unary(UnaryExpression {
- location: self.pop_location(),
- operator: Operator::NonNull,
- expression: destructuring.clone(),
- }));
- }
- if !destructuring.is_valid_destructuring() {
- self.add_syntax_error(&destructuring.location(), DiagnosticKind::MalformedDestructuring, vec![])
- }
- let type_annotation = if self.consume(Token::Colon) { Some(self.parse_type_expression()) } else { None };
- TypedDestructuring {
- location: self.pop_location(),
- destructuring,
- type_annotation,
- }
- }
-
- pub fn parse_type_expression(&mut self) -> Rc {
- let start = self.token_location();
- let (mut base, wrap_nullable) = self.parse_type_expression_start();
-
- loop {
- if self.consume(Token::Dot) {
- base = self.parse_dot_subexpression(base);
- } else if self.consume(Token::Question) {
- self.push_location(&base.location());
- base = Rc::new(Expression::NullableType(NullableTypeExpression {
- location: self.pop_location(),
- base,
- }));
- } else if self.consume(Token::Exclamation) {
- self.push_location(&base.location());
- base = Rc::new(Expression::NonNullableType(NonNullableTypeExpression {
- location: self.pop_location(),
- base,
- }));
- } else {
- break;
- }
- }
-
- if wrap_nullable {
- self.push_location(&start);
- base = Rc::new(Expression::NullableType(NullableTypeExpression {
- location: self.pop_location(),
- base,
- }));
- }
-
- base
- }
-
- fn parse_type_expression_start(&mut self) -> (Rc, bool) {
- // Allow a `?` prefix to wrap a type into nullable.
- let wrap_nullable = self.consume(Token::Question);
-
- // Parenthesized
- if self.peek(Token::ParenOpen) {
- self.mark_location();
- let expression = self.parse_type_expression();
- (Rc::new(Expression::Paren(ParenExpression {
- location: self.pop_location(),
- expression,
- })), wrap_nullable)
- }
- // `function`
- else if self.peek(Token::Function) {
- (self.parse_function_type_expression(), wrap_nullable)
- // `void`
- } else if self.peek(Token::Void) {
- self.mark_location();
- self.next();
- (Rc::new(Expression::VoidType(VoidTypeExpression {
- location: self.pop_location(),
- })), wrap_nullable)
- // [T]
- // [T1, T2, ...Tn]
- } else if self.peek(Token::SquareOpen) {
- let mut elements = vec![];
- self.mark_location();
- self.next();
- elements.push(self.parse_type_expression());
- if self.consume(Token::SquareClose) {
- (Rc::new(Expression::ArrayType(ArrayTypeExpression {
- location: self.pop_location(),
- expression: elements[0].clone(),
- })), wrap_nullable)
- } else {
- self.non_greedy_expect(Token::Comma);
- elements.push(self.parse_type_expression());
- while self.consume(Token::Comma) {
- if self.peek(Token::SquareClose) {
- break;
- }
- elements.push(self.parse_type_expression());
- }
- self.non_greedy_expect(Token::SquareClose);
- (Rc::new(Expression::TupleType(TupleTypeExpression {
- location: self.pop_location(),
- expressions: elements,
- })), wrap_nullable)
- }
- } else if self.peek(Token::Times) {
- let location = self.token_location();
- self.next();
- (Rc::new(Expression::AnyType(AnyTypeExpression {
- location,
- })), wrap_nullable)
- // Identifier
- } else {
- let id = self.parse_qualified_identifier();
- (Rc::new(Expression::QualifiedIdentifier(id)), wrap_nullable)
- }
- }
-
- fn parse_function_type_expression(&mut self) -> Rc {
- self.mark_location();
- self.next();
-
- let mut parameters = vec![];
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- if !self.peek(Token::ParenClose) {
- parameters.push(self.parse_function_type_parameter());
- while self.consume(Token::Comma) {
- parameters.push(self.parse_function_type_parameter());
- }
- }
- self.non_greedy_expect(Token::ParenClose);
- self.validate_parameter_list(parameters.iter().map(|p| (p.kind, p.location.clone())).collect::>());
- }
-
- let mut result_type = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::Colon);
- if !self.expecting_token_error {
- result_type = self.parse_type_expression();
- }
- Rc::new(Expression::FunctionType(FunctionTypeExpression {
- location: self.pop_location(),
- parameters,
- result_type: Some(result_type),
- }))
- }
-
- fn parse_function_type_parameter(&mut self) -> Rc {
- self.mark_location();
- let rest = self.consume(Token::Ellipsis);
- let type_expression: Option> = if rest && self.peek(Token::ParenClose) {
- None
- } else {
- Some(self.parse_type_expression())
- };
- let optional = !rest && self.consume(Token::Assign);
- let location = self.pop_location();
- Rc::new(FunctionTypeParameter {
- location,
- type_expression,
- kind: if rest {
- ParameterKind::Rest
- } else if optional {
- ParameterKind::Optional
- } else {
- ParameterKind::Required
- },
- })
- }
-
- fn parse_variable_binding(&mut self, allow_in: bool) -> VariableBinding {
- let destructuring = self.parse_typed_destructuring();
- let initializer = if self.consume(Token::Assign) {
- Some(self.parse_expression(ParserExpressionContext {
- allow_in,
- min_precedence: OperatorPrecedence::AssignmentAndOther,
- ..default()
- }))
- } else {
- None
- };
- VariableBinding {
- destructuring,
- initializer,
- }
- }
-
- fn parse_semicolon(&mut self) -> bool {
- self.consume(Token::Semicolon) || self.peek(Token::BlockClose) || self.previous_token.1.line_break(&self.token.1)
- }
-
- fn parse_substatement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- self.parse_statement(context)
- }
-
- fn parse_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- // ExpressionStatement or LabeledStatement
- if let Token::Identifier(id) = &self.token.0.clone() {
- let id = (id.clone(), self.token_location());
- self.next();
- self.parse_statement_starting_with_identifier(context, id)
- // SuperStatement or ExpressionStatement with `super`
- } else if self.peek(Token::Super) {
- self.mark_location();
- self.next();
- let arguments = if self.peek(Token::ParenOpen) { Some(self.parse_arguments()) } else { None };
- let mut semicolon = false;
- if arguments.is_some() {
- semicolon = self.parse_semicolon();
- }
- if !semicolon && (self.peek(Token::Dot) || self.peek(Token::SquareOpen)) {
- if !(self.peek(Token::Dot) || self.peek(Token::SquareOpen)) {
- self.non_greedy_expect(Token::Dot);
- }
- self.duplicate_location();
- // ExpressionStatement (`super`...)
- let mut expr = Rc::new(Expression::Super(SuperExpression {
- location: self.pop_location(),
- object: arguments,
- }));
- expr = self.parse_subexpressions(expr, ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::List,
- ..default()
- });
- let semicolon = self.parse_semicolon();
- (Rc::new(Directive::ExpressionStatement(ExpressionStatement {
- location: self.pop_location(),
- expression: expr,
- })), semicolon)
- } else {
- // SuperStatement
- let node = Rc::new(Directive::SuperStatement(SuperStatement {
- location: self.pop_location(),
- arguments: arguments.unwrap(),
- }));
-
- // Check whether super statement is allowed here
- let allowed_here;
- if context.may_contain_super_statement() {
- allowed_here = !context.super_statement_found();
- context.set_super_statement_found(true);
- } else {
- allowed_here = false;
- }
-
- if !allowed_here {
- self.add_syntax_error(&node.location(), DiagnosticKind::NotAllowedHere, diagarg![Token::Super]);
- }
-
- (node, semicolon)
- }
- // EmptyStatement
- } else if self.peek(Token::Semicolon) {
- self.mark_location();
- self.next();
- (Rc::new(Directive::EmptyStatement(EmptyStatement {
- location: self.pop_location(),
- })), true)
- // Block
- } else if self.peek(Token::BlockOpen) {
- let context = if context.is_top_level_or_package() || context.is_type_block() {
- context.clone()
- } else {
- context.override_control_context(true, ParserControlFlowContext {
- breakable: true,
- iteration: false,
- })
- };
- let block = self.parse_block(context);
- (Rc::new(Directive::Block(block)), true)
- // IfStatement
- } else if self.peek(Token::If) {
- self.parse_if_statement(context)
- // SwitchStatement
- // `switch type`
- } else if self.peek(Token::Switch) {
- self.parse_switch_statement(context)
- // DoStatement
- } else if self.peek(Token::Do) {
- self.parse_do_statement(context)
- // WhileStatement
- } else if self.peek(Token::While) {
- self.parse_while_statement(context)
- // ForStatement
- // `for..in`
- // `for each`
- } else if self.peek(Token::For) {
- self.parse_for_statement(context)
- // WithStatement
- } else if self.peek(Token::With) {
- self.parse_with_statement(context)
- // BreakStatement
- } else if self.peek(Token::Break) {
- self.parse_break_statement(context)
- // ContinueStatement
- } else if self.peek(Token::Continue) {
- self.parse_continue_statement(context)
- // ReturnStatement
- } else if self.peek(Token::Return) {
- self.parse_return_statement(context)
- // ThrowStatement
- } else if self.peek(Token::Throw) {
- self.parse_throw_statement(context)
- // TryStatement
- } else if self.peek(Token::Try) {
- self.parse_try_statement(context)
- // `default xml namespace = expression`
- } else if self.peek(Token::Default) {
- self.parse_default_xml_namespace_statement()
- // ExpressionStatement
- } else {
- self.mark_location();
-
- // Store offset for patching error
- let i = self.tokenizer.characters().index();
-
- let exp = self.parse_expression(ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- });
-
- // Patch error
- if i == self.tokenizer.characters().index() {
- self.patch_syntax_error(DiagnosticKind::ExpectingExpression, DiagnosticKind::ExpectingStatement, diagarg![self.token.0.clone()]);
- }
-
- let semicolon = if exp.is_invalidated() {
- self.next();
- true
- } else { self.parse_semicolon() };
- (Rc::new(Directive::ExpressionStatement(ExpressionStatement {
- location: self.pop_location(),
- expression: exp,
- })), semicolon)
- }
- }
-
- fn parse_statement_starting_with_identifier(&mut self, context: ParserDirectiveContext, id: (String, Location)) -> (Rc, bool) {
- self.push_location(&id.1);
- let id_location = id.1.clone();
-
- // LabeledStatement
- if self.consume(Token::Colon) {
- let (substatement, semicolon) = self.parse_substatement(context.put_label(id.0.clone()));
- let labeled = Rc::new(Directive::LabeledStatement(LabeledStatement {
- location: self.pop_location(),
- label: id.clone(),
- substatement,
- }));
- return (labeled, semicolon);
- }
-
- let mut exp: Rc;
-
- /*
- // EmbedExpression
- if self.peek(Token::BlockOpen) && id.0 == "embed" && self.previous_token.1.character_count() == "embed".len() {
- exp = self.finish_embed_expression(id_location);
- } else {
- */
- {
- let id = Rc::new(Expression::QualifiedIdentifier(QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id(id.clone()),
- }));
- if self.peek(Token::ColonColon) {
- self.push_location(&id_location.clone());
- let ql = self.pop_location();
- let id = self.finish_qualified_identifier(false, ql, id);
- exp = Rc::new(Expression::QualifiedIdentifier(id));
- } else {
- exp = id;
- }
- }
-
- exp = self.parse_subexpressions(exp, ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- });
- let semicolon = self.parse_semicolon();
- (Rc::new(Directive::ExpressionStatement(ExpressionStatement {
- location: self.pop_location(),
- expression: exp,
- })), semicolon)
- }
-
- fn parse_qualified_identifier_statement_or_normal_config(&mut self, context: ParserDirectiveContext, id: (String, Location), asdoc: Option>) -> (Rc, bool) {
- self.push_location(&id.1);
- let id_location = id.1.clone();
- let id = Rc::new(Expression::QualifiedIdentifier(QualifiedIdentifier {
- location: id_location.clone(),
- attribute: false,
- qualifier: None,
- id: QualifiedIdentifierIdentifier::Id(id.clone()),
- }));
- self.push_location(&id_location.clone());
- let ql = self.pop_location();
- let id = self.finish_qualified_identifier(false, ql, id);
- let mut exp = Rc::new(Expression::QualifiedIdentifier(id));
- exp = self.parse_subexpressions(exp, ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- });
-
- // Parse CONFIG::VAR_NAME
- if let Some(result) = self.parse_opt_normal_config(&exp, asdoc.clone(), context.clone()) {
- return result;
- }
-
- let semicolon = self.parse_semicolon();
- (Rc::new(Directive::ExpressionStatement(ExpressionStatement {
- location: self.pop_location(),
- expression: exp,
- })), semicolon)
- }
-
- fn parse_opt_normal_config(&mut self, exp: &Rc, asdoc: Option>, context: ParserDirectiveContext) -> Option<(Rc, bool)> {
- if self.peek_annotatable_directive_identifier_name() {
- match exp.to_normal_configuration_identifier(self) {
- Ok(Some((q, constant_name, metadata))) => {
- self.push_location(&exp.location());
- let mut context = AnnotatableContext {
- start_location: exp.location(),
- asdoc: self.parse_asdoc().or(asdoc),
- attributes: metadata,
- context,
- directive_context_keyword: None,
- };
- self.parse_attribute_keywords_or_expressions(&mut context);
- let (directive, semicolon) = self.parse_annotatable_directive(context);
- return Some((Rc::new(Directive::NormalConfigurationDirective(NormalConfigurationDirective {
- location: self.pop_location(),
- namespace: q,
- constant_name,
- directive,
- })), semicolon));
- },
- Ok(None) => {},
- Err(MetadataRefineError1(MetadataRefineError::Syntax, loc)) => {
- self.add_syntax_error(&loc, DiagnosticKind::UnrecognizedMetadataSyntax, diagarg![]);
- },
- }
- }
- if self.peek(Token::BlockOpen) {
- if let Some((q, constant_name)) = exp.to_normal_configuration_identifier_no_metadata() {
- self.push_location(&exp.location());
- let block = self.parse_block(context);
- return Some((Rc::new(Directive::NormalConfigurationDirective(NormalConfigurationDirective {
- location: self.pop_location(),
- namespace: q,
- constant_name,
- directive: Rc::new(Directive::Block(block)),
- })), true));
- }
- }
- None
- }
-
- fn parse_block(&mut self, context: ParserDirectiveContext) -> Block {
- self.mark_location();
- self.non_greedy_expect(Token::BlockOpen);
- let mut directives = vec![];
- if !self.expecting_token_error {
- let mut semicolon = false;
- while !self.peek(Token::BlockClose) && !self.peek(Token::Eof) {
- if !directives.is_empty() && !semicolon {
- self.non_greedy_expect_virtual_semicolon();
- }
- let (directive, semicolon_1) = self.parse_directive(context.clone());
- directives.push(directive);
- semicolon = semicolon_1;
- }
- self.non_greedy_expect(Token::BlockClose);
- }
- Block {
- location: self.pop_location(),
- directives,
- }
- }
-
- fn parse_if_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- let context = context.override_control_context(true, ParserControlFlowContext {
- breakable: true,
- iteration: false,
- });
- self.mark_location();
- self.next();
- let mut test = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- let mut consequent: Rc = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- let mut alternative: Option> = None;
- let semicolon;
- self.non_greedy_expect(Token::ParenOpen);
- if self.expecting_token_error {
- semicolon = self.parse_semicolon();
- } else {
- test = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- consequent = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::ParenClose);
- if self.expecting_token_error {
- semicolon = self.parse_semicolon();
- } else {
- let (consequent_1, semicolon_1) = self.parse_substatement(context.clone());
- consequent = consequent_1;
- if self.peek(Token::Else) {
- if !semicolon_1 {
- self.non_greedy_expect_virtual_semicolon();
- }
- self.next();
- let (alternative_2, semicolon_2) = self.parse_substatement(context.clone());
- alternative = Some(alternative_2);
- semicolon = semicolon_2;
- } else {
- semicolon = semicolon_1;
- }
- }
- }
- (Rc::new(Directive::IfStatement(IfStatement {
- location: self.pop_location(),
- test, consequent, alternative,
- })), semicolon)
- }
-
- fn parse_switch_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- self.mark_location();
- self.next();
- if self.peek_context_keyword("type") {
- self.forbid_line_break_before_token();
- self.next();
- return self.parse_switch_type_statement(context);
- }
- let context = context.override_control_context(false, ParserControlFlowContext {
- breakable: true,
- iteration: false,
- });
- let mut discriminant = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- let mut cases: Vec = vec![];
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- discriminant = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::ParenClose);
- if !self.expecting_token_error {
- self.non_greedy_expect(Token::BlockOpen);
- if !self.expecting_token_error {
- cases = self.parse_case_elements(context);
- self.non_greedy_expect(Token::BlockClose);
- }
- }
- }
- (Rc::new(Directive::SwitchStatement(SwitchStatement {
- location: self.pop_location(),
- discriminant, cases,
- })), true)
- }
-
- fn parse_case_elements(&mut self, context: ParserDirectiveContext) -> Vec {
- let mut cases = vec![];
- let mut semicolon = false;
- while !self.peek(Token::BlockClose) {
- if !cases.is_empty() && !semicolon {
- self.non_greedy_expect_virtual_semicolon();
- }
- if !(self.peek(Token::Case) || self.peek(Token::Default)) {
- break;
- }
- self.mark_location();
- let mut labels = vec![];
- loop {
- if self.peek(Token::Case) {
- self.mark_location();
- self.next();
- let exp = self.parse_expression(ParserExpressionContext {
- allow_in: true,
- min_precedence: OperatorPrecedence::List,
- ..default()
- });
- self.non_greedy_expect(Token::Colon);
- labels.push(CaseLabel::Case((exp, self.pop_location())));
- } else if self.peek(Token::Default) {
- self.mark_location();
- self.next();
- self.non_greedy_expect(Token::Colon);
- labels.push(CaseLabel::Default(self.pop_location()));
- } else {
- break;
- }
- }
- let mut directives = vec![];
- semicolon = false;
- while !(self.peek(Token::BlockClose) || self.peek(Token::Case) || self.peek(Token::Default)) {
- if !directives.is_empty() && !semicolon {
- self.non_greedy_expect_virtual_semicolon();
- }
- let (directive, semicolon_1) = self.parse_directive(context.clone());
- directives.push(directive);
- semicolon = semicolon_1;
- }
- cases.push(Case {
- location: self.pop_location(),
- labels,
- directives,
- });
- }
- cases
- }
-
- fn parse_switch_type_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- let context = context.override_control_context(true, ParserControlFlowContext {
- breakable: true,
- iteration: false,
- });
- let mut discriminant = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- let mut cases: Vec = vec![];
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- discriminant = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::ParenClose);
- if !self.expecting_token_error {
- self.non_greedy_expect(Token::BlockOpen);
- if !self.expecting_token_error {
- cases = self.parse_type_case_elements(context);
- self.non_greedy_expect(Token::BlockClose);
- }
- }
- }
- (Rc::new(Directive::SwitchTypeStatement(SwitchTypeStatement {
- location: self.pop_location(),
- discriminant, cases,
- })), true)
- }
-
- fn parse_type_case_elements(&mut self, context: ParserDirectiveContext) -> Vec {
- let mut cases = vec![];
- while !self.peek(Token::BlockClose) && !self.peek(Token::Eof) {
- if self.peek(Token::Default) {
- self.mark_location();
- self.next();
- let block = Rc::new(self.parse_block(context.clone()));
- cases.push(TypeCase {
- location: self.pop_location(),
- parameter: None,
- block,
- });
- } else {
- self.mark_location();
- self.non_greedy_expect(Token::Case);
- if !self.expecting_token_error {
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- let parameter = Some(self.parse_typed_destructuring());
- self.non_greedy_expect(Token::ParenClose);
- if !self.expecting_token_error {
- let block = Rc::new(self.parse_block(context.clone()));
- cases.push(TypeCase {
- location: self.pop_location(),
- parameter,
- block,
- });
- }
- }
- }
- }
- }
- cases
- }
-
- fn parse_do_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- let context = context.override_control_context(false, ParserControlFlowContext {
- breakable: true,
- iteration: true,
- });
- self.mark_location();
- self.next();
-
- // Body
- let (body, semicolon_1) = self.parse_substatement(context);
- if !semicolon_1 {
- self.non_greedy_expect_virtual_semicolon();
- }
-
- let mut test = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::While);
- if !self.expecting_token_error {
- test = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- test = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- self.non_greedy_expect(Token::ParenClose);
- }
- }
-
- let semicolon = self.parse_semicolon();
- (Rc::new(Directive::DoStatement(DoStatement {
- location: self.pop_location(),
- body, test,
- })), semicolon)
- }
-
- fn parse_while_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- let context = context.override_control_context(false, ParserControlFlowContext {
- breakable: true,
- iteration: true,
- });
- self.mark_location();
- self.next();
-
- // Test
- let mut test = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- let mut body = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- let semicolon: bool;
- self.non_greedy_expect(Token::ParenOpen);
- if !self.expecting_token_error {
- test = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() });
- body = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::ParenClose);
- if !self.expecting_token_error {
- let (body_1, semicolon_1) = self.parse_substatement(context);
- body = body_1;
- semicolon = semicolon_1;
- } else {
- semicolon = self.parse_semicolon();
- }
- } else {
- semicolon = self.parse_semicolon();
- }
-
- (Rc::new(Directive::WhileStatement(WhileStatement {
- location: self.pop_location(),
- test, body,
- })), semicolon)
- }
-
- /// Parses `for`, `for..in` or `for each`.
- fn parse_for_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- let context = context.override_control_context(false, ParserControlFlowContext {
- breakable: true,
- iteration: true,
- });
- self.mark_location();
- self.next();
-
- // `for each`
- if self.peek_context_keyword("each") {
- self.forbid_line_break_before_token();
- self.next();
- return self.parse_for_each_statement(context);
- }
-
- self.non_greedy_expect(Token::ParenOpen);
- if self.expecting_token_error {
- let body = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- let semicolon = self.parse_semicolon();
- return (Rc::new(Directive::ForStatement(ForStatement {
- location: self.pop_location(),
- init: None, test: None, update: None, body,
- })), semicolon);
- }
-
- let init_variable = if self.peek(Token::Var) || self.peek(Token::Const) {
- Some(self.parse_simple_variable_definition(false))
- } else {
- None
- };
-
- if init_variable.is_some() && self.consume(Token::In) {
- return self.parse_for_in_statement_with_left_variable(context, init_variable.unwrap());
- }
-
- let mut init_exp = if init_variable.is_none() && !self.peek(Token::Semicolon) {
- self.parse_opt_expression(ParserExpressionContext {
- allow_in: false,
- min_precedence: OperatorPrecedence::Postfix,
- ..default()
- })
- } else {
- None
- };
-
- if init_exp.is_some() && self.consume(Token::In) {
- return self.parse_for_in_statement_with_left_exp(context, init_exp.unwrap());
- }
-
- if init_exp.is_none() && init_variable.is_none() && !self.peek(Token::Semicolon) {
- init_exp = Some(self.parse_expression(ParserExpressionContext {
- allow_in: false, min_precedence: OperatorPrecedence::List, ..default()
- }));
- } else if let Some(exp) = init_exp.as_ref() {
- init_exp = Some(self.parse_subexpressions(exp.clone(), ParserExpressionContext {
- allow_in: false, min_precedence: OperatorPrecedence::List, ..default()
- }));
- }
-
- let init = if let Some(exp) = init_exp.as_ref() {
- Some(ForInitializer::Expression(exp.clone()))
- } else if let Some(variable) = init_variable.as_ref() {
- Some(ForInitializer::VariableDefinition(Rc::new(variable.clone())))
- } else {
- None
- };
-
- self.non_greedy_expect(Token::Semicolon);
- let test = if self.peek(Token::Semicolon) {
- None
- } else {
- Some(self.parse_expression(ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- }))
- };
- self.non_greedy_expect(Token::Semicolon);
- let update = if self.peek(Token::ParenClose) {
- None
- } else {
- Some(self.parse_expression(ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- }))
- };
- self.non_greedy_expect(Token::ParenClose);
-
- // Body
- let (body, semicolon) = self.parse_substatement(context);
-
- (Rc::new(Directive::ForStatement(ForStatement {
- location: self.pop_location(),
- init, test, update, body,
- })), semicolon)
- }
-
- fn parse_for_each_statement(&mut self, context: ParserDirectiveContext) -> (Rc, bool) {
- self.non_greedy_expect(Token::ParenOpen);
- if self.expecting_token_error {
- let left = ForInBinding::Expression(self.create_invalidated_expression(&self.tokenizer.cursor_location()));
- let right = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- let body = self.create_invalidated_directive(&self.tokenizer.cursor_location());
- let semicolon = self.parse_semicolon();
- return (Rc::new(Directive::ForInStatement(ForInStatement {
- location: self.pop_location(),
- each: true, left, right, body,
- })), semicolon);
- }
-
- let left = if self.peek(Token::Var) || self.peek(Token::Const) {
- self.mark_location();
- let kind = (if self.peek(Token::Var) { VariableDefinitionKind::Var } else { VariableDefinitionKind::Const }, self.token_location());
- self.next();
- let binding = self.parse_variable_binding(false);
- if let Some(init) = &binding.initializer {
- self.add_syntax_error(&init.location(), DiagnosticKind::IllegalForInInitializer, vec![]);
- }
- ForInBinding::VariableDefinition(Rc::new(SimpleVariableDefinition {
- location: self.pop_location(),
- kind,
- bindings: vec![Rc::new(binding)],
- }))
- } else {
- ForInBinding::Expression(self.parse_expression(ParserExpressionContext {
- allow_in: false, min_precedence: OperatorPrecedence::Postfix, ..default()
- }))
- };
- let mut right = self.create_invalidated_expression(&self.tokenizer.cursor_location());
- self.non_greedy_expect(Token::In);
- if !self.expecting_token_error {
- right = self.parse_expression(ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- });
- }
- self.non_greedy_expect(Token::ParenClose);
-
- // Body
- let (body, semicolon) = self.parse_substatement(context);
-
- (Rc::new(Directive::ForInStatement(ForInStatement {
- location: self.pop_location(),
- each: true, left, right, body,
- })), semicolon)
- }
-
- fn parse_for_in_statement_with_left_variable(&mut self, context: ParserDirectiveContext, left: SimpleVariableDefinition) -> (Rc, bool) {
- let variable_binding = left.bindings[0].clone();
-
- if let Some(init) = &variable_binding.initializer {
- self.add_syntax_error(&init.location(), DiagnosticKind::IllegalForInInitializer, vec![]);
- }
-
- if left.bindings.len() > 1 {
- self.add_syntax_error(&left.kind.1.clone(), DiagnosticKind::MultipleForInBindings, vec![]);
- }
-
- let right = self.parse_expression(ParserExpressionContext {
- allow_in: true, min_precedence: OperatorPrecedence::List, ..default()
- });
- self.non_greedy_expect(Token::ParenClose);
-
- // Body
- let (body, semicolon) = self.parse_substatement(context);
-
- (Rc::new(Directive::ForInStatement(ForInStatement {
- location: self.pop_location(),
- each: false, left: ForInBinding::VariableDefinition(Rc::new(left)), right, body,
- })), semicolon)
- }
-
- fn parse_for_in_statement_with_left_exp(&mut self, context: ParserDirectiveContext, left: Rc) -> (Rc |